|
|
@@ -1,12 +1,18 @@
|
|
|
-import { useState, useEffect } from "react";
|
|
|
+import { useState, useEffect, useRef } from "react";
|
|
|
import WbwCase from "./WbwCase";
|
|
|
import { bookMarkColor } from "./WbwDetailBookMark";
|
|
|
import WbwFactorMeaning from "./WbwFactorMeaning";
|
|
|
import WbwFactors from "./WbwFactors";
|
|
|
import WbwMeaning from "./WbwMeaning";
|
|
|
import WbwPali from "./WbwPali";
|
|
|
-import WbwWord from "./WbwWord";
|
|
|
import "./wbw.css";
|
|
|
+import WbwPara from "./WbwPara";
|
|
|
+import WbwPage from "./WbwPage";
|
|
|
+import { useAppSelector } from "../../../hooks";
|
|
|
+import { add, wordList } from "../../../reducers/inline-dict";
|
|
|
+import { get } from "../../../request";
|
|
|
+import { IApiResponseDictList } from "../../api/Dict";
|
|
|
+import store from "../../../store";
|
|
|
|
|
|
export type TFieldName =
|
|
|
| "word"
|
|
|
@@ -53,6 +59,7 @@ export interface IWbw {
|
|
|
meaning?: WbwElement2;
|
|
|
type?: WbwElement;
|
|
|
grammar?: WbwElement;
|
|
|
+ style?: WbwElement;
|
|
|
case?: WbwElement2;
|
|
|
parent?: WbwElement;
|
|
|
factors?: WbwElement;
|
|
|
@@ -70,9 +77,10 @@ export interface IWbwFields {
|
|
|
factorMeaning?: boolean;
|
|
|
case?: boolean;
|
|
|
}
|
|
|
+export type TWbwDisplayMode = "block" | "inline";
|
|
|
interface IWidget {
|
|
|
data: IWbw;
|
|
|
- display?: "block" | "inline";
|
|
|
+ display?: TWbwDisplayMode;
|
|
|
fields?: IWbwFields;
|
|
|
onChange?: Function;
|
|
|
onSplit?: Function;
|
|
|
@@ -85,63 +93,154 @@ const Widget = ({
|
|
|
onSplit,
|
|
|
}: IWidget) => {
|
|
|
const [wordData, setWordData] = useState(data);
|
|
|
+ const [fieldDisplay, setFieldDisplay] = useState(fields);
|
|
|
+ const intervalRef = useRef<number | null>(null); //防抖计时器句柄
|
|
|
+ const inlineWords = useAppSelector(wordList);
|
|
|
+
|
|
|
useEffect(() => {
|
|
|
setWordData(data);
|
|
|
- }, [data]);
|
|
|
- const styleWbw: React.CSSProperties = {
|
|
|
- display: display === "block" ? "block" : "flex",
|
|
|
- };
|
|
|
+ setFieldDisplay(fields);
|
|
|
+ }, [data, fields]);
|
|
|
+
|
|
|
const color = wordData.bookMarkColor
|
|
|
? bookMarkColor[wordData.bookMarkColor.value]
|
|
|
: "unset";
|
|
|
- return (
|
|
|
- <div className={`wbw_word ${display}`} style={styleWbw}>
|
|
|
- <WbwPali
|
|
|
- data={wordData}
|
|
|
- onSave={(e: IWbw) => {
|
|
|
- console.log("save", e);
|
|
|
- const newData: IWbw = JSON.parse(JSON.stringify(e));
|
|
|
- setWordData(newData);
|
|
|
- if (typeof onChange !== "undefined") {
|
|
|
- onChange(e);
|
|
|
+ const wbwCtl = wordData.type?.value === ".ctl." ? "wbw_ctl" : "";
|
|
|
+ const wbwAnchor = wordData.grammar?.value === ".a." ? "wbw_anchor" : "";
|
|
|
+
|
|
|
+ const styleWbw: React.CSSProperties = {
|
|
|
+ display: display === "block" ? "block" : "flex",
|
|
|
+ };
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 停止查字典计时
|
|
|
+ * 在两种情况下停止计时
|
|
|
+ * 1. 开始查字典
|
|
|
+ * 2. 防抖时间内鼠标移出单词区
|
|
|
+ */
|
|
|
+ const stopLookup = () => {
|
|
|
+ if (intervalRef.current) {
|
|
|
+ window.clearInterval(intervalRef.current);
|
|
|
+ intervalRef.current = null;
|
|
|
+ }
|
|
|
+ };
|
|
|
+ /**
|
|
|
+ * 查字典
|
|
|
+ * @param word 要查的单词
|
|
|
+ */
|
|
|
+ const lookup = (word: string) => {
|
|
|
+ stopLookup();
|
|
|
+ //查询这个词在内存字典里是否有
|
|
|
+ if (inlineWords.has(word)) {
|
|
|
+ //已经有了,退出
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ get<IApiResponseDictList>(`/v2/wbwlookup?word=${word}`).then((json) => {
|
|
|
+ console.log("lookup ok", json.data.count);
|
|
|
+ store.dispatch(add([word, json.data.rows]));
|
|
|
+ });
|
|
|
+ console.log("lookup", word);
|
|
|
+ };
|
|
|
+ if (wordData.type?.value === ".ctl.") {
|
|
|
+ if (wordData.word.value.includes("para")) {
|
|
|
+ return <WbwPara data={wordData} />;
|
|
|
+ } else {
|
|
|
+ return <WbwPage data={wordData} />;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ return (
|
|
|
+ <div
|
|
|
+ className={`wbw_word ${display} ${wbwCtl} ${wbwAnchor} `}
|
|
|
+ style={styleWbw}
|
|
|
+ onMouseEnter={() => {
|
|
|
+ if (intervalRef.current === null) {
|
|
|
+ intervalRef.current = window.setInterval(
|
|
|
+ lookup,
|
|
|
+ 200,
|
|
|
+ wordData.word.value
|
|
|
+ );
|
|
|
}
|
|
|
}}
|
|
|
- />
|
|
|
- <div
|
|
|
- className="wbw_body"
|
|
|
- style={{
|
|
|
- background: `linear-gradient(90deg, rgba(255, 255, 255, 0), ${color})`,
|
|
|
+ onMouseLeave={() => {
|
|
|
+ stopLookup();
|
|
|
}}
|
|
|
>
|
|
|
- {fields?.meaning ? (
|
|
|
- <WbwMeaning
|
|
|
- data={wordData}
|
|
|
- onChange={(e: string) => {
|
|
|
- console.log("meaning change", e);
|
|
|
- const newData: IWbw = JSON.parse(JSON.stringify(wordData));
|
|
|
- newData.meaning = { value: [e], status: 5 };
|
|
|
- setWordData(newData);
|
|
|
- }}
|
|
|
- />
|
|
|
- ) : undefined}
|
|
|
- {fields?.factors ? <WbwFactors data={wordData} /> : undefined}
|
|
|
- {fields?.factorMeaning ? (
|
|
|
- <WbwFactorMeaning data={wordData} />
|
|
|
- ) : undefined}
|
|
|
- {fields?.case ? (
|
|
|
- <WbwCase
|
|
|
- data={wordData}
|
|
|
- onSplit={(e: boolean) => {
|
|
|
- console.log("onSplit", wordData.factors?.value);
|
|
|
- if (typeof onSplit !== "undefined") {
|
|
|
- onSplit(e);
|
|
|
- }
|
|
|
- }}
|
|
|
- />
|
|
|
- ) : undefined}
|
|
|
+ <WbwPali
|
|
|
+ data={wordData}
|
|
|
+ onSave={(e: IWbw) => {
|
|
|
+ console.log("save", e);
|
|
|
+ const newData: IWbw = JSON.parse(JSON.stringify(e));
|
|
|
+ setWordData(newData);
|
|
|
+ if (typeof onChange !== "undefined") {
|
|
|
+ onChange(e);
|
|
|
+ }
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ <div
|
|
|
+ className="wbw_body"
|
|
|
+ style={{
|
|
|
+ background: `linear-gradient(90deg, rgba(255, 255, 255, 0), ${color})`,
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ {fieldDisplay?.meaning ? (
|
|
|
+ <WbwMeaning
|
|
|
+ data={wordData}
|
|
|
+ display={display}
|
|
|
+ onChange={(e: string) => {
|
|
|
+ console.log("meaning change", e);
|
|
|
+ const newData: IWbw = JSON.parse(JSON.stringify(wordData));
|
|
|
+ newData.meaning = { value: [e], status: 5 };
|
|
|
+ setWordData(newData);
|
|
|
+ if (typeof onChange !== "undefined") {
|
|
|
+ onChange(newData);
|
|
|
+ }
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ ) : undefined}
|
|
|
+ {fieldDisplay?.factors ? (
|
|
|
+ <WbwFactors
|
|
|
+ data={wordData}
|
|
|
+ display={display}
|
|
|
+ onChange={(e: string) => {
|
|
|
+ console.log("factor change", e);
|
|
|
+ const newData: IWbw = JSON.parse(JSON.stringify(wordData));
|
|
|
+ newData.factors = { value: e, status: 5 };
|
|
|
+ setWordData(newData);
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ ) : undefined}
|
|
|
+ {fieldDisplay?.factorMeaning ? (
|
|
|
+ <WbwFactorMeaning
|
|
|
+ data={wordData}
|
|
|
+ display={display}
|
|
|
+ onChange={(e: string) => {
|
|
|
+ const newData: IWbw = JSON.parse(JSON.stringify(wordData));
|
|
|
+ newData.factorMeaning = { value: e, status: 5 };
|
|
|
+ setWordData(newData);
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ ) : undefined}
|
|
|
+ {fieldDisplay?.case ? (
|
|
|
+ <WbwCase
|
|
|
+ data={wordData}
|
|
|
+ display={display}
|
|
|
+ onSplit={(e: boolean) => {
|
|
|
+ console.log("onSplit", wordData.factors?.value);
|
|
|
+ if (typeof onSplit !== "undefined") {
|
|
|
+ onSplit(e);
|
|
|
+ }
|
|
|
+ }}
|
|
|
+ onChange={(e: string) => {
|
|
|
+ const newData: IWbw = JSON.parse(JSON.stringify(wordData));
|
|
|
+ newData.case = { value: e.split("+"), status: 5 };
|
|
|
+ setWordData(newData);
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ ) : undefined}
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
- );
|
|
|
+ );
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
export default Widget;
|