diff --git a/dictation_client/src/pages/LicensePage/cardLicenseActivatePopup.tsx b/dictation_client/src/pages/LicensePage/cardLicenseActivatePopup.tsx index 328e813..a41d16f 100644 --- a/dictation_client/src/pages/LicensePage/cardLicenseActivatePopup.tsx +++ b/dictation_client/src/pages/LicensePage/cardLicenseActivatePopup.tsx @@ -24,12 +24,15 @@ export const CardLicenseActivatePopup: React.FC< const { t } = useTranslation(); const dispatch: AppDispatch = useDispatch(); const isLoading = useSelector(selectIsLoading); + // 各テキストエリアの値 const [keyNumber1, setKeyNumber1] = useState(""); const [keyNumber2, setKeyNumber2] = useState(""); const [keyNumber3, setKeyNumber3] = useState(""); const [keyNumber4, setKeyNumber4] = useState(""); const [keyNumber5, setKeyNumber5] = useState(""); + // 1つのテキストエリアに入る最大文字数 const TEXTAREASIZE = 4; + // フォーカス操作時に使用 const ref1 = useRef(null); const ref2 = useRef(null); const ref3 = useRef(null); @@ -99,6 +102,7 @@ export const CardLicenseActivatePopup: React.FC< input = input.substring(TEXTAREASIZE); break; default: + // テキストエリア5つから溢れる文字は切り捨てる input = ""; } roopCount += 1; @@ -123,6 +127,26 @@ export const CardLicenseActivatePopup: React.FC< moveTextarea(input.length, areaNum); }; + // テキストエリア入力時(paste仕様) + const changeTextareaByPaste = ( + e: React.ClipboardEvent, + areaNum: number + ) => { + const input = e.clipboardData + .getData("text") + .toUpperCase() + .replace(/[^A-Z0-9]/g, "") + .substring(0, 20); + inputValueOnTextarea(input, areaNum); + moveFocusByPaste(input.length, areaNum); + if (e.clipboardData.getData("text").includes("\n")) { + setTimeout(() => { + onKeyDownEnter(); + }, 0); + } + e.preventDefault(); + }; + // フォーカスを移動する const moveFocus = (target: string) => { // stateの反映を同期してから実施 @@ -141,6 +165,32 @@ export const CardLicenseActivatePopup: React.FC< } }; + // カーソルを現在入力されている中での最後尾に移動する + // eslint-disable-next-line react-hooks/exhaustive-deps + const moveCursorToLast = () => { + if (keyNumber5) { + moveFocus("textarea5"); + } else if (keyNumber4) { + moveFocus("textarea4"); + } else if (keyNumber3) { + moveFocus("textarea3"); + } else if (keyNumber2) { + moveFocus("textarea2"); + } else { + moveFocus("textarea1"); + } + }; + + // ペースト時のフォーカスを設定する + const moveFocusByPaste = (length: number, areaNum: number) => { + let targetNum = areaNum + Math.floor(length / 4); + if (targetNum > 5) { + targetNum = 5; + } + const target = `textarea${targetNum.toString()}`; + moveFocus(target); + }; + // キー入力時判定 const keyDown = ( e: React.KeyboardEvent, @@ -158,7 +208,7 @@ export const CardLicenseActivatePopup: React.FC< moveFocus(`textarea${(areaNum - 1).toString()}`); } } else if (/^[a-zA-Z0-9]$/.test(e.key)) { - if (e.target.value.length === TEXTAREASIZE) { + if (e.target.value.length === TEXTAREASIZE && !e.ctrlKey) { e.preventDefault(); } } else if (/^[!-/:-@[-`{-~]$/.test(e.key)) { @@ -180,11 +230,7 @@ export const CardLicenseActivatePopup: React.FC< setIsPushActivateButton(true); const keyNumber = `${keyNumber1}${keyNumber2}${keyNumber3}${keyNumber4}${keyNumber5}`; if (keyNumber.length !== 20) { - const inputBox = document.getElementById("textarea5"); - // カーソルをテキストボックスに戻す - if (inputBox) { - inputBox.focus(); - } + moveCursorToLast(); return; } @@ -194,21 +240,30 @@ export const CardLicenseActivatePopup: React.FC< ); setIsPushActivateButton(false); - // カーソルをテキストボックスに戻す - const inputBox = document.getElementById("textarea1"); - if (inputBox) { - inputBox.focus(); - } - if (meta.requestStatus === "fulfilled") { + // カーソルを左端に戻す + const inputBox = document.getElementById("textarea1"); + if (inputBox) { + inputBox.focus(); + } dispatch(cleanupApps()); setKeyNumber1(""); setKeyNumber2(""); setKeyNumber3(""); setKeyNumber4(""); setKeyNumber5(""); + } else { + moveCursorToLast(); } - }, [keyNumber1, keyNumber2, keyNumber3, keyNumber4, keyNumber5, dispatch]); + }, [ + keyNumber1, + keyNumber2, + keyNumber3, + keyNumber4, + keyNumber5, + dispatch, + moveCursorToLast, + ]); // HTML return ( @@ -243,11 +298,12 @@ export const CardLicenseActivatePopup: React.FC< // eslint-disable-next-line jsx-a11y/no-autofocus autoFocus onChange={(e) => { - let cursorPos = 0; - cursorPos = e.target.selectionStart; + // カーソル位置保存 + const cursorPos = e.target.selectionStart; changeTextarea(e, 1); setTimeout(() => { if (ref1.current) { + // 保存したカーソル位置に設定 ref1.current.selectionStart = cursorPos; ref1.current.selectionEnd = cursorPos; } @@ -262,6 +318,9 @@ export const CardLicenseActivatePopup: React.FC< ref1.current.selectionEnd = e.target.value.length; } }} + onPaste={(e) => { + changeTextareaByPaste(e, 1); + }} />