text-input-guard 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/text-input-guard.cjs +44 -47
- package/dist/cjs/text-input-guard.min.cjs +1 -1
- package/dist/esm/text-input-guard.js +44 -47
- package/dist/esm/text-input-guard.min.js +1 -1
- package/dist/umd/text-input-guard.js +44 -47
- package/dist/umd/text-input-guard.min.js +1 -1
- package/package.json +1 -1
|
@@ -735,6 +735,11 @@ class InputGuard {
|
|
|
735
735
|
*/
|
|
736
736
|
this.beforeInputSnapshot = null;
|
|
737
737
|
|
|
738
|
+
/**
|
|
739
|
+
* onBeforeInput イベントが発生したか否か
|
|
740
|
+
*/
|
|
741
|
+
this.existBeforeInputEvent = false;
|
|
742
|
+
|
|
738
743
|
/**
|
|
739
744
|
* ルールからのrevert要求
|
|
740
745
|
* @type {RevertRequest|null}
|
|
@@ -991,12 +996,12 @@ class InputGuard {
|
|
|
991
996
|
*/
|
|
992
997
|
createCtx({ useSnapshot = true } = {}) {
|
|
993
998
|
const snap = useSnapshot ? this.beforeInputSnapshot : null;
|
|
994
|
-
|
|
995
|
-
|
|
999
|
+
let inputType = snap?.inputType ?? "";
|
|
1000
|
+
let insertedText = snap?.insertedText ?? "";
|
|
996
1001
|
|
|
997
1002
|
// 受理済み(正規化済み)の全文を「今回の編集の基準」として使う
|
|
998
1003
|
// display.value はブラウザ側の編集結果が混ざるので、差分再構成の基準にはしない
|
|
999
|
-
|
|
1004
|
+
let beforeText = this.lastAcceptedValue ?? "";
|
|
1000
1005
|
|
|
1001
1006
|
// selection は2系統ある:
|
|
1002
1007
|
// - snapSel: beforeinput 時点で取得した selection(今回の編集の基準点になり得る)
|
|
@@ -1032,6 +1037,38 @@ class InputGuard {
|
|
|
1032
1037
|
baseSel = lastSel;
|
|
1033
1038
|
}
|
|
1034
1039
|
|
|
1040
|
+
// beforeinput がない環境では、差分再構成の基準が「前回の受理値」しかないため、そこから今回の編集内容を推測する必要がある。
|
|
1041
|
+
if (beforeText.length === 0 || !this.existBeforeInputEvent) {
|
|
1042
|
+
const display = /** @type {HTMLInputElement|HTMLTextAreaElement} */ (this.displayElement);
|
|
1043
|
+
const current = display.value;
|
|
1044
|
+
// 前回の値がとれないものの、何かしら入力情報がある状態
|
|
1045
|
+
if (current.length > 0) {
|
|
1046
|
+
// 文字列の先頭が前回の受理値と同じなら、末尾に何かしら入力されたと考えられる(オートコンプリート等)
|
|
1047
|
+
if (current.toLocaleLowerCase().startsWith(beforeText.toLocaleLowerCase())) {
|
|
1048
|
+
if (!current.startsWith(beforeText)) {
|
|
1049
|
+
// 文字は同じだが、大文字と小文字の情報が替わっているなどのパターン
|
|
1050
|
+
// 差し代わりが起きているため、前回値は基準にならないと判断して、差分全体を insertedText とする
|
|
1051
|
+
beforeText = "";
|
|
1052
|
+
insertedText = current;
|
|
1053
|
+
} else {
|
|
1054
|
+
// 末尾に追加されたと考えられる部分を insertedText とする
|
|
1055
|
+
// 例: beforeText="abc" → current="abcde" なら、"de" が insertedText
|
|
1056
|
+
insertedText = current.slice(beforeText.length);
|
|
1057
|
+
}
|
|
1058
|
+
// キャレットは前回値の末尾にあると推測する
|
|
1059
|
+
baseSel = /** @type {SelectionState} */ {
|
|
1060
|
+
start: beforeText.length,
|
|
1061
|
+
end: beforeText.length,
|
|
1062
|
+
direction: "none"
|
|
1063
|
+
};
|
|
1064
|
+
inputType = "insertText";
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
// existBeforeInputEvent は、少なくとも1回 beforeinput が発生したかどうかのフラグ
|
|
1069
|
+
// これが false の場合、上記のような「beforeinputがない環境での推測ロジック」を走らせる。
|
|
1070
|
+
this.existBeforeInputEvent = false;
|
|
1071
|
+
|
|
1035
1072
|
let replaceStart = baseSel.start ?? 0;
|
|
1036
1073
|
let replaceEnd = baseSel.end ?? 0;
|
|
1037
1074
|
|
|
@@ -1257,9 +1294,7 @@ class InputGuard {
|
|
|
1257
1294
|
try {
|
|
1258
1295
|
this.evaluateInput();
|
|
1259
1296
|
} finally {
|
|
1260
|
-
|
|
1261
|
-
// 古い snapshot を使い回さないよう、1イベントごとに破棄する
|
|
1262
|
-
this.beforeInputSnapshot = null;
|
|
1297
|
+
this.existBeforeInputEvent = false;
|
|
1263
1298
|
}
|
|
1264
1299
|
}
|
|
1265
1300
|
|
|
@@ -1280,6 +1315,7 @@ class InputGuard {
|
|
|
1280
1315
|
const inputType = typeof e.inputType === "string" ? e.inputType : null;
|
|
1281
1316
|
/** @type {string|null} */
|
|
1282
1317
|
const insertedText = typeof e.data === "string" ? e.data : null;
|
|
1318
|
+
this.existBeforeInputEvent = true;
|
|
1283
1319
|
this.beforeInputSnapshot = { selection, inputType, insertedText };
|
|
1284
1320
|
}
|
|
1285
1321
|
|
|
@@ -1419,45 +1455,6 @@ class InputGuard {
|
|
|
1419
1455
|
const ctx = this.createCtx();
|
|
1420
1456
|
ctx.afterText = current;
|
|
1421
1457
|
|
|
1422
|
-
/**
|
|
1423
|
-
* 入力値情報のみを使用するフォールバック
|
|
1424
|
-
* @returns {GuardContext}
|
|
1425
|
-
*/
|
|
1426
|
-
const applyFullNormalizeFromCurrent = () => {
|
|
1427
|
-
let newText = current;
|
|
1428
|
-
ctx.beforeText = "";
|
|
1429
|
-
newText = this.runNormalizeChar(newText, ctx);
|
|
1430
|
-
newText = this.runNormalizeStructure(newText, ctx);
|
|
1431
|
-
this.setDisplayValuePreserveCaret(display, newText, ctx);
|
|
1432
|
-
ctx.afterText = newText;
|
|
1433
|
-
return ctx;
|
|
1434
|
-
};
|
|
1435
|
-
|
|
1436
|
-
// beforeinput が取得できない経路(初回評価)では
|
|
1437
|
-
// 差分再構成を行うと lastAcceptedValue 基準で値を落とす可能性があるため、
|
|
1438
|
-
// 現在の全文を正規化して扱うフォールバックへ切り替える。
|
|
1439
|
-
if (!this.beforeInputSnapshot) {
|
|
1440
|
-
return applyFullNormalizeFromCurrent();
|
|
1441
|
-
}
|
|
1442
|
-
|
|
1443
|
-
// オートコンプリート等では beforeinput は来ても data が空のことがあり、
|
|
1444
|
-
// 差分情報だけでは再構成不能になる。表示値がすでに変わっている場合は
|
|
1445
|
-
// 再構成を諦めて current 全体の正規化に切り替える。
|
|
1446
|
-
const isDeleteInput =
|
|
1447
|
-
ctx.inputType === "deleteContentBackward" ||
|
|
1448
|
-
ctx.inputType === "deleteContentForward";
|
|
1449
|
-
const isInsertLikeInput =
|
|
1450
|
-
ctx.inputType === "" ||
|
|
1451
|
-
ctx.inputType?.startsWith("insert");
|
|
1452
|
-
const lacksDelta =
|
|
1453
|
-
ctx.insertedText === "" &&
|
|
1454
|
-
ctx.beforeText !== current &&
|
|
1455
|
-
isInsertLikeInput &&
|
|
1456
|
-
!isDeleteInput;
|
|
1457
|
-
if (lacksDelta) {
|
|
1458
|
-
return applyFullNormalizeFromCurrent();
|
|
1459
|
-
}
|
|
1460
|
-
|
|
1461
1458
|
// 元のテキスト
|
|
1462
1459
|
const beforeText = ctx.beforeText;
|
|
1463
1460
|
|
|
@@ -7489,10 +7486,10 @@ const rules = {
|
|
|
7489
7486
|
|
|
7490
7487
|
/**
|
|
7491
7488
|
* バージョン(ビルド時に置換したいならここを差し替える)
|
|
7492
|
-
* 例: rollup replace で ""1.0.
|
|
7489
|
+
* 例: rollup replace で ""1.0.2"" を package.json の version に置換
|
|
7493
7490
|
*/
|
|
7494
7491
|
// @ts-ignore
|
|
7495
7492
|
// eslint-disable-next-line no-undef
|
|
7496
|
-
const version = "1.0.
|
|
7493
|
+
const version = "1.0.2" ;
|
|
7497
7494
|
|
|
7498
7495
|
export { ascii, attach, attachAll, autoAttach, bytes, comma, digits, filter, imeOff, kana, length, numeric, prefix, rules, suffix, trim, version, width };
|