more POE tweaks, validate dates
parent
8ec273219c
commit
07b44ba69e
|
@ -84,6 +84,9 @@
|
|||
border: none;
|
||||
background: none;
|
||||
padding: 0.1em 0.5em;
|
||||
&:invalid {
|
||||
background: mix($c-error, $c-bg-box, 30%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ export class ExplorerConfigCtrl {
|
|||
rating: storedJsonProp('explorer.rating', () => allRatings),
|
||||
speed: storedJsonProp<ExplorerSpeed[]>('explorer.speed', () => allSpeeds),
|
||||
mode: storedJsonProp<ExplorerMode[]>('explorer.mode', () => allModes),
|
||||
since: storedProp('explorer.since', ''),
|
||||
since: storedProp('explorer.since', '2010-01'),
|
||||
until: storedProp('explorer.until', ''),
|
||||
playerName: {
|
||||
open: prop(false),
|
||||
|
@ -176,9 +176,13 @@ const monthInput = (prop: StoredProp<Month>) =>
|
|||
type: 'month',
|
||||
pattern: '^20[12][0-9]-(0[1-9]|1[012])$',
|
||||
min: '2010-01',
|
||||
max: '2030-01',
|
||||
value: prop() || '',
|
||||
},
|
||||
hook: bind('change', e => prop((e.target as HTMLInputElement).value)),
|
||||
hook: bind('change', e => {
|
||||
const input = e.target as HTMLInputElement;
|
||||
if (input.checkValidity()) prop(input.value);
|
||||
}),
|
||||
});
|
||||
|
||||
const monthSection = (ctrl: ExplorerConfigCtrl) =>
|
||||
|
|
|
@ -113,7 +113,7 @@ export default class ExplorerCtrl {
|
|||
processData
|
||||
)
|
||||
.then(stream => {
|
||||
stream.end.promise.then(this.root.redraw);
|
||||
stream.end.promise.then(err => (err ? onError(err) : this.root.redraw()));
|
||||
return stream;
|
||||
})
|
||||
)
|
||||
|
|
|
@ -454,15 +454,13 @@ export default function (ctrl: AnalyseCtrl): VNode | undefined {
|
|||
[
|
||||
h('div.overlay'),
|
||||
content,
|
||||
!content || explorer.failing()
|
||||
? null
|
||||
: h('button.fbt.toconf', {
|
||||
attrs: {
|
||||
'aria-label': configOpened ? 'Close configuration' : 'Open configuration',
|
||||
...dataIcon(configOpened ? '' : ''),
|
||||
},
|
||||
hook: bind('click', () => ctrl.explorer.config.toggleOpen(), ctrl.redraw),
|
||||
}),
|
||||
h('button.fbt.toconf', {
|
||||
attrs: {
|
||||
'aria-label': configOpened ? 'Close configuration' : 'Open configuration',
|
||||
...dataIcon(configOpened ? '' : ''),
|
||||
},
|
||||
hook: bind('click', () => ctrl.explorer.config.toggleOpen(), ctrl.redraw),
|
||||
}),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import { ExplorerData, ExplorerDb, ExplorerMode, ExplorerSpeed, OpeningData, TablebaseData } from './interfaces';
|
||||
import { ExplorerData, ExplorerDb, OpeningData, TablebaseData } from './interfaces';
|
||||
import * as xhr from 'common/xhr';
|
||||
import { readNdJson, CancellableStream } from 'common/ndjson';
|
||||
import { ExplorerConfigData } from './explorerConfig';
|
||||
import { sync } from 'common/sync';
|
||||
|
||||
interface OpeningXhrOpts {
|
||||
endpoint: string;
|
||||
|
@ -16,7 +17,10 @@ interface OpeningXhrOpts {
|
|||
withGames?: boolean;
|
||||
}
|
||||
|
||||
export function opening(opts: OpeningXhrOpts, processData: (data: ExplorerData) => void): Promise<CancellableStream> {
|
||||
export async function opening(
|
||||
opts: OpeningXhrOpts,
|
||||
processData: (data: ExplorerData) => void
|
||||
): Promise<CancellableStream> {
|
||||
const conf = opts.config;
|
||||
const endpoint = opts.db == 'player' ? opts.endpoint3 : opts.endpoint;
|
||||
const url = new URL(opts.db === 'lichess' ? '/lichess' : opts.db == 'player' ? '/personal' : '/master', endpoint);
|
||||
|
@ -34,25 +38,32 @@ export function opening(opts: OpeningXhrOpts, processData: (data: ExplorerData)
|
|||
params.set('update', 'true');
|
||||
params.set('speeds', conf.speed().join(','));
|
||||
params.set('modes', conf.mode().join(','));
|
||||
if (conf.since()) params.set('since', conf.since().replace('-', '/'));
|
||||
if (conf.until()) params.set('until', conf.until().replace('-', '/'));
|
||||
if (conf.since()) params.set('since', conf.since());
|
||||
if (conf.until()) params.set('until', conf.until());
|
||||
}
|
||||
if (!opts.withGames) {
|
||||
params.set('topGames', '0');
|
||||
params.set('recentGames', '0');
|
||||
}
|
||||
const stream = fetch(url.href, {
|
||||
const res = await fetch(url.href, {
|
||||
cache: 'default',
|
||||
headers: {}, // avoid default headers for cors
|
||||
credentials: 'omit',
|
||||
});
|
||||
|
||||
const onMessage = (line: any) => {
|
||||
const data = line as Partial<OpeningData>;
|
||||
data.isOpening = true;
|
||||
data.fen = opts.fen;
|
||||
processData(data as OpeningData);
|
||||
};
|
||||
return stream.then(readNdJson(onMessage));
|
||||
|
||||
if (res.ok) return readNdJson(onMessage)(res);
|
||||
|
||||
return {
|
||||
cancel() {},
|
||||
end: sync(Promise.resolve(new Error(`Explorer error: ${res.status}`))),
|
||||
};
|
||||
}
|
||||
|
||||
export async function tablebase(endpoint: string, variant: VariantKey, fen: Fen): Promise<TablebaseData> {
|
||||
|
|
|
@ -4,7 +4,7 @@ export type ProcessLine = (line: any) => void;
|
|||
|
||||
export interface CancellableStream {
|
||||
cancel(): void;
|
||||
end: Sync<boolean>;
|
||||
end: Sync<Error | undefined>;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -21,11 +21,11 @@ export const readNdJson =
|
|||
const decoder = new TextDecoder();
|
||||
let buf = '';
|
||||
|
||||
const loop = (): Promise<boolean> =>
|
||||
const loop = (): Promise<Error | undefined> =>
|
||||
stream.read().then(({ done, value }) => {
|
||||
if (done) {
|
||||
if (buf.length > 0) processLine(JSON.parse(buf));
|
||||
return Promise.resolve(true);
|
||||
return Promise.resolve(undefined);
|
||||
} else {
|
||||
const chunk = decoder.decode(value, { stream: true });
|
||||
buf += chunk;
|
||||
|
|
Loading…
Reference in New Issue