From 5aa432fc10ad621b07be7a78f2ec5902270ea467 Mon Sep 17 00:00:00 2001 From: lifegpc Date: Fri, 30 Jun 2023 15:57:34 +0800 Subject: [PATCH] Use custom datalist implement --- components/BTextField.tsx | 56 ++++++++++++++++++++++++++++++++++++-- components/GidDataList.tsx | 44 ------------------------------ components/NewTask.tsx | 35 ++++++++++++++++++++---- static/common.css | 22 +++++++++++++++ 4 files changed, 106 insertions(+), 51 deletions(-) delete mode 100644 components/GidDataList.tsx diff --git a/components/BTextField.tsx b/components/BTextField.tsx index 8f271b4..f7d0ed8 100644 --- a/components/BTextField.tsx +++ b/components/BTextField.tsx @@ -1,7 +1,8 @@ import { Component, ComponentChildren, ContextType } from "preact"; import TextField from "preact-material-components/TextField"; -import { Ref, useRef } from "preact/hooks"; +import { Ref, useRef, useState } from "preact/hooks"; import { BCtx } from "./BContext.tsx"; +import List from "preact-material-components/List"; interface TextType { text: string; @@ -34,6 +35,7 @@ type Props = { outlined?: boolean; id?: string; list?: string; + datalist?: { value: TextType[T]; label?: string }[]; }; export default class BTextField @@ -98,6 +100,22 @@ export default class BTextField if (this.props.value !== undefined) this.update(this.props.value); else if (this.clear_cache) this.clear(); } + get value(): TextType[T] | undefined { + const e = this.ref?.current; + if (e) { + const b = e.base; + if (b) { + const t = b as HTMLElement; + const d = t.querySelector("input"); + if (d) { + const n = this.get_value(d); + if (typeof n === "number" && isNaN(n)) return undefined; + return n; + } + } + } + return undefined; + } get_value(e: HTMLInputElement): TextType[T] { const type = this.props.type; // @ts-ignore Checked @@ -107,10 +125,41 @@ export default class BTextField } render() { this.ref = useRef(); - let cn = "text"; + let cn = "b-text-field text"; + let datalist_div = null; + const [display_datalist, set_display_datalist] = useState(false); if (this.props.helpertext) cn += " helper"; if (this.props.outlined) cn += " outlined"; if (this.props.label) cn += " label"; + if (this.props.datalist && this.props.datalist.length) { + cn += " datalist"; + let cn2 = "datalist"; + if (display_datalist) cn2 += " open"; + const v = this.value?.toString(); + datalist_div = ( + + {this.props.datalist.map((d) => { + if (v !== undefined) { + if (!d.value.toString().startsWith(v)) return null; + } + let label_div = null; + if (d.label) { + label_div =
{d.label}
; + } + return ( + { + this.set_value(d.value); + }} + > +
{d.value}
+ {label_div} +
+ ); + })} +
+ ); + } let desc = null; if (this.props.description) { desc = ; @@ -136,7 +185,10 @@ export default class BTextField max={this.props.max} outlined={this.props.outlined} list={this.props.list} + onFocus={() => set_display_datalist(true)} + onBlur={() => set_display_datalist(false)} /> + {datalist_div} {this.props.children} ); diff --git a/components/GidDataList.tsx b/components/GidDataList.tsx deleted file mode 100644 index f1872cf..0000000 --- a/components/GidDataList.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { Component } from "preact"; -import { GMeta } from "../db.ts"; -import { useEffect } from "preact/hooks"; -import { GalleryListResult } from "../server/gallery.ts"; - -type Props = { - /**@default {false}*/ - jpn_title?: boolean; - id: string; -}; - -type State = { - data?: GMeta[]; -}; - -export default class GidDataList extends Component { - render() { - const fetchData = async () => { - const re = await fetch( - "/api/gallery/list?all=1&fields=gid,title,title_jpn", - ); - const d: GalleryListResult = await re.json(); - if (d.ok) { - this.setState({ data: d.data }); - } - }; - useEffect(() => { - fetchData().catch((e) => console.error(e)); - }, []); - return ( - - {this.state.data - ? this.state.data.map((d) => { - let title = d.title; - if (this.props.jpn_title && d.title_jpn) { - title = d.title_jpn; - } - return ; - }) - : null} - - ); - } -} diff --git a/components/NewTask.tsx b/components/NewTask.tsx index 4b814d6..dabadcb 100644 --- a/components/NewTask.tsx +++ b/components/NewTask.tsx @@ -5,7 +5,7 @@ import Icon from "preact-material-components/Icon"; import { set_state } from "../server/state.ts"; import t from "../server/i18n.ts"; import BSelect from "./BSelect.tsx"; -import { StateUpdater, useRef, useState } from "preact/hooks"; +import { StateUpdater, useEffect, useRef, useState } from "preact/hooks"; import { TaskType } from "../task.ts"; import BTextField from "./BTextField.tsx"; import { parseUrl, UrlType } from "../url.ts"; @@ -22,13 +22,18 @@ import Snackbar from "preact-material-components/Snackbar"; import { GalleryResult } from "../server/gallery.ts"; import { tw } from "twind"; import { ExportZipConfig } from "../tasks/export_zip.ts"; -import GidDataList from "./GidDataList.tsx"; +import { GMeta } from "../db.ts"; +import { GalleryListResult } from "../server/gallery.ts"; export type NewTaskProps = { show: boolean; }; -export default class NewTask extends Component { +type State = { + gids?: GMeta[]; +}; + +export default class NewTask extends Component { static contextType = GlobalCtx; declare context: ContextType; render() { @@ -54,6 +59,20 @@ export default class NewTask extends Component { const [abort, set_abort] = useState(); const [ezcfg, set_ezcfg1] = useState(generate_export_zip_cfg()); const [overwrite_ezcfg, set_overwrite_ezcfg] = useState(false); + const fetchGidsData = async () => { + const re = await fetch( + "/api/gallery/list?all=1&fields=gid,title,title_jpn", + ); + const d: GalleryListResult = await re.json(); + if (d.ok) { + this.setState({ ...this.state, gids: d.data }); + } + }; + useEffect(() => { + if (task_type === TaskType.ExportZip) { + fetchGidsData().catch((e) => console.error(e)); + } + }, [task_type]); if (task_type === TaskType.Download) { const set_url: StateUpdater = (u) => { const n = typeof u === "string" ? u : u(url || ""); @@ -288,16 +307,22 @@ export default class NewTask extends Component { ); } + const datalist: { value: number; label?: string }[] = []; + if (this.state.gids) { + this.state.gids.forEach((g) => { + const t = jpn_title && g.title_jpn ? g.title_jpn : g.title; + datalist.push({ value: g.gid, label: t }); + }); + } config_div = (
- {ginfo_div}