From 478d4542592dc78ac485b008969b36694d0d3163 Mon Sep 17 00:00:00 2001 From: "oura.a" Date: Wed, 19 Jul 2023 08:25:51 +0000 Subject: [PATCH] =?UTF-8?q?Merged=20PR=20235:=20[PO=E3=83=87=E3=83=A2?= =?UTF-8?q?=E6=8C=87=E6=91=98]=E3=82=AB=E3=83=BC=E3=82=BD=E3=83=AB?= =?UTF-8?q?=E3=81=AE=E7=A7=BB=E5=8B=95=E3=82=92=E6=89=8B=E5=85=A5=E5=8A=9B?= =?UTF-8?q?=E3=81=A8=E3=82=B3=E3=83=94=E3=83=9A=E6=99=82=E3=81=A7=E5=90=8C?= =?UTF-8?q?=E3=81=98=E3=81=AB=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 概要 [Task2202: [POデモ指摘]カーソルの移動を手入力とコピペ時で同じにする](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/2202) 以下の対応を行いました。 ・コピペ入力時、カーソルがコピペで入力された文字があるボックスの最後尾に移動するように修正 (すでに文字が入力されていた場合、厳密には手入力と異なる動作となってしまうが、影響は小さいと判断しました。) ・API呼び出し時、文字数が20桁に満たない場合のカーソル位置が、現在入力されている文字の最後尾になるように修正 ・コメント追加 ## レビューポイント なし ## UIの変更 なし ## 動作確認状況 ローカルで動作確認済み ## 補足 なし --- .../LicensePage/cardLicenseActivatePopup.tsx | 121 ++++++++++++++---- 1 file changed, 98 insertions(+), 23 deletions(-) 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); + }} />