text-input-guard 1.2.0 → 1.2.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 +88 -7
- package/dist/cjs/text-input-guard.min.cjs +1 -1
- package/dist/esm/text-input-guard.js +88 -7
- package/dist/esm/text-input-guard.min.js +1 -1
- package/dist/umd/text-input-guard.js +88 -7
- package/dist/umd/text-input-guard.min.js +1 -1
- package/package.json +1 -1
|
@@ -276,7 +276,7 @@
|
|
|
276
276
|
}
|
|
277
277
|
|
|
278
278
|
/**
|
|
279
|
-
* The script is part of
|
|
279
|
+
* The script is part of TextInputGuard.
|
|
280
280
|
*
|
|
281
281
|
* AUTHOR:
|
|
282
282
|
* natade-jp (https://github.com/natade-jp)
|
|
@@ -626,6 +626,8 @@
|
|
|
626
626
|
}
|
|
627
627
|
}
|
|
628
628
|
|
|
629
|
+
let globalGuardId = 0; // デバッグ用のガードID生成
|
|
630
|
+
|
|
629
631
|
class InputGuard {
|
|
630
632
|
/**
|
|
631
633
|
* InputGuard の内部状態を初期化する(DOM/設定/イベント/パイプラインを持つ)
|
|
@@ -633,6 +635,12 @@
|
|
|
633
635
|
* @param {AttachOptions} options
|
|
634
636
|
*/
|
|
635
637
|
constructor(element, options) {
|
|
638
|
+
/**
|
|
639
|
+
* ガードID(デバッグ用、インスタンスごとにユニーク)
|
|
640
|
+
* @type {number}
|
|
641
|
+
*/
|
|
642
|
+
this.id = ++globalGuardId;
|
|
643
|
+
|
|
636
644
|
/**
|
|
637
645
|
* attach対象の元の要素(swap前の原本)
|
|
638
646
|
* detach時の復元や基準参照に使う
|
|
@@ -714,7 +722,7 @@
|
|
|
714
722
|
/**
|
|
715
723
|
* 実際に送信を担う要素(swap時は hidden(raw) 側)
|
|
716
724
|
* swapしない場合は originalElement と同一
|
|
717
|
-
* @type {
|
|
725
|
+
* @type {HTMLInputElement|HTMLTextAreaElement}
|
|
718
726
|
*/
|
|
719
727
|
this.hostElement = element;
|
|
720
728
|
|
|
@@ -825,6 +833,11 @@
|
|
|
825
833
|
*/
|
|
826
834
|
this.onFocus = this.onFocus.bind(this);
|
|
827
835
|
|
|
836
|
+
/**
|
|
837
|
+
* keydownイベントハンドラ(this固定)
|
|
838
|
+
*/
|
|
839
|
+
this.onKeyDown = this.onKeyDown.bind(this);
|
|
840
|
+
|
|
828
841
|
/**
|
|
829
842
|
* キャレット/選択範囲の変化イベントハンドラ(this固定)
|
|
830
843
|
*/
|
|
@@ -880,6 +893,14 @@
|
|
|
880
893
|
this.revertRequest = null;
|
|
881
894
|
}
|
|
882
895
|
|
|
896
|
+
/**
|
|
897
|
+
* デバッグ用の文字列化
|
|
898
|
+
* @returns {string}
|
|
899
|
+
*/
|
|
900
|
+
toString() {
|
|
901
|
+
return `[TextInputGuard#${this.id} kind=${this.kind} host=${this.hostElement.tagName.toLowerCase()}#${this.hostElement.id}] value=${this.hostElement.value}]`;
|
|
902
|
+
}
|
|
903
|
+
|
|
883
904
|
/**
|
|
884
905
|
* 初期化処理(swap適用 → パイプライン構築 → イベント登録 → 初回評価)
|
|
885
906
|
* @returns {void}
|
|
@@ -1084,6 +1105,7 @@
|
|
|
1084
1105
|
this.displayElement.addEventListener("beforeinput", this.onBeforeInput);
|
|
1085
1106
|
this.displayElement.addEventListener("blur", this.onBlur);
|
|
1086
1107
|
this.displayElement.addEventListener("focus", this.onFocus);
|
|
1108
|
+
this.displayElement.addEventListener("keydown", this.onKeyDown);
|
|
1087
1109
|
}
|
|
1088
1110
|
|
|
1089
1111
|
/**
|
|
@@ -1097,6 +1119,7 @@
|
|
|
1097
1119
|
this.displayElement.removeEventListener("beforeinput", this.onBeforeInput);
|
|
1098
1120
|
this.displayElement.removeEventListener("blur", this.onBlur);
|
|
1099
1121
|
this.displayElement.removeEventListener("focus", this.onFocus);
|
|
1122
|
+
this.displayElement.removeEventListener("keydown", this.onKeyDown);
|
|
1100
1123
|
}
|
|
1101
1124
|
|
|
1102
1125
|
/**
|
|
@@ -1269,8 +1292,8 @@
|
|
|
1269
1292
|
// アンドゥリドゥの特殊処理
|
|
1270
1293
|
if (inputType === "historyUndo" || inputType === "historyRedo") {
|
|
1271
1294
|
let newText = null;
|
|
1272
|
-
console.log(inputType);
|
|
1273
|
-
console.log(this.history.toString());
|
|
1295
|
+
// console.log(inputType);
|
|
1296
|
+
// console.log(this.history.toString());
|
|
1274
1297
|
if (inputType === "historyUndo") {
|
|
1275
1298
|
newText = this.history.undo();
|
|
1276
1299
|
} else if (inputType === "historyRedo") {
|
|
@@ -1514,6 +1537,19 @@
|
|
|
1514
1537
|
}
|
|
1515
1538
|
this.existBeforeInputEvent = true;
|
|
1516
1539
|
this.beforeInputSnapshot = { selection, inputType, insertedText };
|
|
1540
|
+
|
|
1541
|
+
// アンドゥリドゥの beforeinput はフォーカスされている要素以外にも発生することがあるため、
|
|
1542
|
+
// 正しく判定するために onKeyDown で捕まえて、必要なときだけ onBeforeInput のスナップを作る
|
|
1543
|
+
if (inputType === "historyUndo" || inputType === "historyRedo") {
|
|
1544
|
+
e.preventDefault();
|
|
1545
|
+
|
|
1546
|
+
// フォーカス中ではない要素に飛んできたUndo/Redoは止めるだけ
|
|
1547
|
+
if (document.activeElement !== this.displayElement) {
|
|
1548
|
+
return;
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1551
|
+
this.evaluateInput();
|
|
1552
|
+
}
|
|
1517
1553
|
}
|
|
1518
1554
|
|
|
1519
1555
|
/**
|
|
@@ -1570,6 +1606,51 @@
|
|
|
1570
1606
|
this.history.push(raw);
|
|
1571
1607
|
}
|
|
1572
1608
|
|
|
1609
|
+
/**
|
|
1610
|
+
* keydownイベント:特殊な用途向けに提供(例:Enterで確定させたいなど)
|
|
1611
|
+
* @param {Event} e
|
|
1612
|
+
* @returns {void}
|
|
1613
|
+
*/
|
|
1614
|
+
onKeyDown(e) {
|
|
1615
|
+
if (!(e instanceof KeyboardEvent)) {
|
|
1616
|
+
return;
|
|
1617
|
+
}
|
|
1618
|
+
|
|
1619
|
+
// アンドゥ及びリドゥの onBeforeInput はフォーカスされている要素以外にも発生することがあるため
|
|
1620
|
+
// 正しく判定するために onKeyDown で捕まえて、必要なときだけ onBeforeInput のスナップを作る
|
|
1621
|
+
|
|
1622
|
+
const isUndo = (e.ctrlKey || e.metaKey) && !e.shiftKey && e.key.toLowerCase() === "z";
|
|
1623
|
+
const isRedo =
|
|
1624
|
+
((e.ctrlKey || e.metaKey) && e.shiftKey && e.key.toLowerCase() === "z") ||
|
|
1625
|
+
((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "y");
|
|
1626
|
+
|
|
1627
|
+
if (!isUndo && !isRedo) {
|
|
1628
|
+
return;
|
|
1629
|
+
}
|
|
1630
|
+
|
|
1631
|
+
// ここでチェックする
|
|
1632
|
+
if (document.activeElement !== this.displayElement) {
|
|
1633
|
+
return;
|
|
1634
|
+
}
|
|
1635
|
+
|
|
1636
|
+
// ブラウザのデフォルトの undo/redo をキャンセルして、自前でUndo/Redo を発生させる
|
|
1637
|
+
e.preventDefault();
|
|
1638
|
+
|
|
1639
|
+
// 擬似beforeinputのスナップを作る
|
|
1640
|
+
this.beforeInputSnapshot = {
|
|
1641
|
+
selection: this.readSelection(this.displayElement),
|
|
1642
|
+
inputType: isUndo ? "historyUndo" : "historyRedo",
|
|
1643
|
+
insertedText: ""
|
|
1644
|
+
};
|
|
1645
|
+
|
|
1646
|
+
this.existBeforeInputEvent = true;
|
|
1647
|
+
try {
|
|
1648
|
+
this.evaluateInput();
|
|
1649
|
+
} finally {
|
|
1650
|
+
this.existBeforeInputEvent = false;
|
|
1651
|
+
}
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1573
1654
|
/**
|
|
1574
1655
|
* キャレット/選択範囲の変化を lastAcceptedSelection に反映する
|
|
1575
1656
|
* - 値が変わっていない状態でもキャレットは動くため、block時に自然な位置へ戻すために使う
|
|
@@ -1913,7 +1994,7 @@
|
|
|
1913
1994
|
|
|
1914
1995
|
/**
|
|
1915
1996
|
* 外部に公開する Guard API を生成して返す
|
|
1916
|
-
* -
|
|
1997
|
+
* - TextInputGuard 自体を公開せず、最小の操作だけを渡す
|
|
1917
1998
|
* @returns {Guard}
|
|
1918
1999
|
*/
|
|
1919
2000
|
getGuard() {
|
|
@@ -7707,11 +7788,11 @@
|
|
|
7707
7788
|
|
|
7708
7789
|
/**
|
|
7709
7790
|
* バージョン(ビルド時に置換したいならここを差し替える)
|
|
7710
|
-
* 例: rollup replace で ""1.2.
|
|
7791
|
+
* 例: rollup replace で ""1.2.2"" を package.json の version に置換
|
|
7711
7792
|
*/
|
|
7712
7793
|
// @ts-ignore
|
|
7713
7794
|
// eslint-disable-next-line no-undef
|
|
7714
|
-
const version = "1.2.
|
|
7795
|
+
const version = "1.2.2" ;
|
|
7715
7796
|
|
|
7716
7797
|
/**
|
|
7717
7798
|
* UMD公開時のグローバルオブジェクト
|