Merged PR 235: [POデモ指摘]カーソルの移動を手入力とコピペ時で同じにする

## 概要
[Task2202: [POデモ指摘]カーソルの移動を手入力とコピペ時で同じにする](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/2202)

以下の対応を行いました。
・コピペ入力時、カーソルがコピペで入力された文字があるボックスの最後尾に移動するように修正
(すでに文字が入力されていた場合、厳密には手入力と異なる動作となってしまうが、影響は小さいと判断しました。)
・API呼び出し時、文字数が20桁に満たない場合のカーソル位置が、現在入力されている文字の最後尾になるように修正
・コメント追加

## レビューポイント
なし

## UIの変更
なし

## 動作確認状況
ローカルで動作確認済み

## 補足
なし
This commit is contained in:
oura.a 2023-07-19 08:25:51 +00:00
parent a9ad7ded0a
commit 478d454259

View File

@ -24,12 +24,15 @@ export const CardLicenseActivatePopup: React.FC<
const { t } = useTranslation();
const dispatch: AppDispatch = useDispatch();
const isLoading = useSelector(selectIsLoading);
// 各テキストエリアの値
const [keyNumber1, setKeyNumber1] = useState<string>("");
const [keyNumber2, setKeyNumber2] = useState<string>("");
const [keyNumber3, setKeyNumber3] = useState<string>("");
const [keyNumber4, setKeyNumber4] = useState<string>("");
const [keyNumber5, setKeyNumber5] = useState<string>("");
// 1つのテキストエリアに入る最大文字数
const TEXTAREASIZE = 4;
// フォーカス操作時に使用
const ref1 = useRef<HTMLTextAreaElement>(null);
const ref2 = useRef<HTMLTextAreaElement>(null);
const ref3 = useRef<HTMLTextAreaElement>(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<HTMLTextAreaElement>,
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<HTMLTextAreaElement>,
@ -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);
}}
/>
<textarea
id="textarea2"
@ -270,11 +329,12 @@ export const CardLicenseActivatePopup: React.FC<
className={styles.formInputKey}
ref={ref2}
onChange={(e) => {
let cursorPos = 0;
cursorPos = e.target.selectionStart;
// カーソル位置保存
const cursorPos = e.target.selectionStart;
changeTextarea(e, 2);
setTimeout(() => {
if (ref2.current) {
// 保存したカーソル位置に設定
ref2.current.selectionStart = cursorPos;
ref2.current.selectionEnd = cursorPos;
}
@ -289,6 +349,9 @@ export const CardLicenseActivatePopup: React.FC<
ref2.current.selectionEnd = e.target.value.length;
}
}}
onPaste={(e) => {
changeTextareaByPaste(e, 2);
}}
/>
<textarea
id="textarea3"
@ -297,11 +360,12 @@ export const CardLicenseActivatePopup: React.FC<
className={styles.formInputKey}
ref={ref3}
onChange={(e) => {
let cursorPos = 0;
cursorPos = e.target.selectionStart;
// カーソル位置保存
const cursorPos = e.target.selectionStart;
changeTextarea(e, 3);
setTimeout(() => {
if (ref3.current) {
// 保存したカーソル位置に設定
ref3.current.selectionStart = cursorPos;
ref3.current.selectionEnd = cursorPos;
}
@ -316,6 +380,9 @@ export const CardLicenseActivatePopup: React.FC<
ref3.current.selectionEnd = e.target.value.length;
}
}}
onPaste={(e) => {
changeTextareaByPaste(e, 3);
}}
/>
<textarea
id="textarea4"
@ -324,11 +391,12 @@ export const CardLicenseActivatePopup: React.FC<
className={styles.formInputKey}
ref={ref4}
onChange={(e) => {
let cursorPos = 0;
cursorPos = e.target.selectionStart;
// カーソル位置保存
const cursorPos = e.target.selectionStart;
changeTextarea(e, 4);
setTimeout(() => {
if (ref4.current) {
// 保存したカーソル位置に設定
ref4.current.selectionStart = cursorPos;
ref4.current.selectionEnd = cursorPos;
}
@ -343,6 +411,9 @@ export const CardLicenseActivatePopup: React.FC<
ref4.current.selectionEnd = e.target.value.length;
}
}}
onPaste={(e) => {
changeTextareaByPaste(e, 4);
}}
/>
<textarea
id="textarea5"
@ -351,11 +422,12 @@ export const CardLicenseActivatePopup: React.FC<
className={styles.formInputKey}
ref={ref5}
onChange={(e) => {
let cursorPos = 0;
cursorPos = e.target.selectionStart;
// カーソル位置保存
const cursorPos = e.target.selectionStart;
changeTextarea(e, 5);
setTimeout(() => {
if (ref5.current) {
// 保存したカーソル位置に設定
ref5.current.selectionStart = cursorPos;
ref5.current.selectionEnd = cursorPos;
}
@ -370,6 +442,9 @@ export const CardLicenseActivatePopup: React.FC<
ref5.current.selectionEnd = e.target.value.length;
}
}}
onPaste={(e) => {
changeTextareaByPaste(e, 5);
}}
/>
{isPushActivateButton &&
keyNumber1.length +