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