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.
@@ -272,7 +272,7 @@ class SwapState {
272
272
  }
273
273
 
274
274
  /**
275
- * The script is part of JPInputGuard.
275
+ * The script is part of TextInputGuard.
276
276
  *
277
277
  * AUTHOR:
278
278
  * natade-jp (https://github.com/natade-jp)
@@ -622,6 +622,8 @@ class HistoryQueue {
622
622
  }
623
623
  }
624
624
 
625
+ let globalGuardId = 0; // デバッグ用のガードID生成
626
+
625
627
  class InputGuard {
626
628
  /**
627
629
  * InputGuard の内部状態を初期化する(DOM/設定/イベント/パイプラインを持つ)
@@ -629,6 +631,12 @@ class InputGuard {
629
631
  * @param {AttachOptions} options
630
632
  */
631
633
  constructor(element, options) {
634
+ /**
635
+ * ガードID(デバッグ用、インスタンスごとにユニーク)
636
+ * @type {number}
637
+ */
638
+ this.id = ++globalGuardId;
639
+
632
640
  /**
633
641
  * attach対象の元の要素(swap前の原本)
634
642
  * detach時の復元や基準参照に使う
@@ -710,7 +718,7 @@ class InputGuard {
710
718
  /**
711
719
  * 実際に送信を担う要素(swap時は hidden(raw) 側)
712
720
  * swapしない場合は originalElement と同一
713
- * @type {HTMLElement}
721
+ * @type {HTMLInputElement|HTMLTextAreaElement}
714
722
  */
715
723
  this.hostElement = element;
716
724
 
@@ -821,6 +829,11 @@ class InputGuard {
821
829
  */
822
830
  this.onFocus = this.onFocus.bind(this);
823
831
 
832
+ /**
833
+ * keydownイベントハンドラ(this固定)
834
+ */
835
+ this.onKeyDown = this.onKeyDown.bind(this);
836
+
824
837
  /**
825
838
  * キャレット/選択範囲の変化イベントハンドラ(this固定)
826
839
  */
@@ -876,6 +889,14 @@ class InputGuard {
876
889
  this.revertRequest = null;
877
890
  }
878
891
 
892
+ /**
893
+ * デバッグ用の文字列化
894
+ * @returns {string}
895
+ */
896
+ toString() {
897
+ return `[TextInputGuard#${this.id} kind=${this.kind} host=${this.hostElement.tagName.toLowerCase()}#${this.hostElement.id}] value=${this.hostElement.value}]`;
898
+ }
899
+
879
900
  /**
880
901
  * 初期化処理(swap適用 → パイプライン構築 → イベント登録 → 初回評価)
881
902
  * @returns {void}
@@ -1080,6 +1101,7 @@ class InputGuard {
1080
1101
  this.displayElement.addEventListener("beforeinput", this.onBeforeInput);
1081
1102
  this.displayElement.addEventListener("blur", this.onBlur);
1082
1103
  this.displayElement.addEventListener("focus", this.onFocus);
1104
+ this.displayElement.addEventListener("keydown", this.onKeyDown);
1083
1105
  }
1084
1106
 
1085
1107
  /**
@@ -1093,6 +1115,7 @@ class InputGuard {
1093
1115
  this.displayElement.removeEventListener("beforeinput", this.onBeforeInput);
1094
1116
  this.displayElement.removeEventListener("blur", this.onBlur);
1095
1117
  this.displayElement.removeEventListener("focus", this.onFocus);
1118
+ this.displayElement.removeEventListener("keydown", this.onKeyDown);
1096
1119
  }
1097
1120
 
1098
1121
  /**
@@ -1265,8 +1288,8 @@ class InputGuard {
1265
1288
  // アンドゥリドゥの特殊処理
1266
1289
  if (inputType === "historyUndo" || inputType === "historyRedo") {
1267
1290
  let newText = null;
1268
- console.log(inputType);
1269
- console.log(this.history.toString());
1291
+ // console.log(inputType);
1292
+ // console.log(this.history.toString());
1270
1293
  if (inputType === "historyUndo") {
1271
1294
  newText = this.history.undo();
1272
1295
  } else if (inputType === "historyRedo") {
@@ -1510,6 +1533,19 @@ class InputGuard {
1510
1533
  }
1511
1534
  this.existBeforeInputEvent = true;
1512
1535
  this.beforeInputSnapshot = { selection, inputType, insertedText };
1536
+
1537
+ // アンドゥリドゥの beforeinput はフォーカスされている要素以外にも発生することがあるため、
1538
+ // 正しく判定するために onKeyDown で捕まえて、必要なときだけ onBeforeInput のスナップを作る
1539
+ if (inputType === "historyUndo" || inputType === "historyRedo") {
1540
+ e.preventDefault();
1541
+
1542
+ // フォーカス中ではない要素に飛んできたUndo/Redoは止めるだけ
1543
+ if (document.activeElement !== this.displayElement) {
1544
+ return;
1545
+ }
1546
+
1547
+ this.evaluateInput();
1548
+ }
1513
1549
  }
1514
1550
 
1515
1551
  /**
@@ -1566,6 +1602,51 @@ class InputGuard {
1566
1602
  this.history.push(raw);
1567
1603
  }
1568
1604
 
1605
+ /**
1606
+ * keydownイベント:特殊な用途向けに提供(例:Enterで確定させたいなど)
1607
+ * @param {Event} e
1608
+ * @returns {void}
1609
+ */
1610
+ onKeyDown(e) {
1611
+ if (!(e instanceof KeyboardEvent)) {
1612
+ return;
1613
+ }
1614
+
1615
+ // アンドゥ及びリドゥの onBeforeInput はフォーカスされている要素以外にも発生することがあるため
1616
+ // 正しく判定するために onKeyDown で捕まえて、必要なときだけ onBeforeInput のスナップを作る
1617
+
1618
+ const isUndo = (e.ctrlKey || e.metaKey) && !e.shiftKey && e.key.toLowerCase() === "z";
1619
+ const isRedo =
1620
+ ((e.ctrlKey || e.metaKey) && e.shiftKey && e.key.toLowerCase() === "z") ||
1621
+ ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "y");
1622
+
1623
+ if (!isUndo && !isRedo) {
1624
+ return;
1625
+ }
1626
+
1627
+ // ここでチェックする
1628
+ if (document.activeElement !== this.displayElement) {
1629
+ return;
1630
+ }
1631
+
1632
+ // ブラウザのデフォルトの undo/redo をキャンセルして、自前でUndo/Redo を発生させる
1633
+ e.preventDefault();
1634
+
1635
+ // 擬似beforeinputのスナップを作る
1636
+ this.beforeInputSnapshot = {
1637
+ selection: this.readSelection(this.displayElement),
1638
+ inputType: isUndo ? "historyUndo" : "historyRedo",
1639
+ insertedText: ""
1640
+ };
1641
+
1642
+ this.existBeforeInputEvent = true;
1643
+ try {
1644
+ this.evaluateInput();
1645
+ } finally {
1646
+ this.existBeforeInputEvent = false;
1647
+ }
1648
+ }
1649
+
1569
1650
  /**
1570
1651
  * キャレット/選択範囲の変化を lastAcceptedSelection に反映する
1571
1652
  * - 値が変わっていない状態でもキャレットは動くため、block時に自然な位置へ戻すために使う
@@ -1909,7 +1990,7 @@ class InputGuard {
1909
1990
 
1910
1991
  /**
1911
1992
  * 外部に公開する Guard API を生成して返す
1912
- * - InputGuard 自体を公開せず、最小の操作だけを渡す
1993
+ * - TextInputGuard 自体を公開せず、最小の操作だけを渡す
1913
1994
  * @returns {Guard}
1914
1995
  */
1915
1996
  getGuard() {
@@ -7703,11 +7784,11 @@ const rules = {
7703
7784
 
7704
7785
  /**
7705
7786
  * バージョン(ビルド時に置換したいならここを差し替える)
7706
- * 例: rollup replace で ""1.2.0"" を package.json の version に置換
7787
+ * 例: rollup replace で ""1.2.2"" を package.json の version に置換
7707
7788
  */
7708
7789
  // @ts-ignore
7709
7790
  // eslint-disable-next-line no-undef
7710
- const version = "1.2.0" ;
7791
+ const version = "1.2.2" ;
7711
7792
 
7712
7793
  /**
7713
7794
  * UMD公開時のグローバルオブジェクト