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.
@@ -276,7 +276,7 @@
276
276
  }
277
277
 
278
278
  /**
279
- * The script is part of JPInputGuard.
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 {HTMLElement}
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
- * - InputGuard 自体を公開せず、最小の操作だけを渡す
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.0"" を package.json の version に置換
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.0" ;
7795
+ const version = "1.2.2" ;
7715
7796
 
7716
7797
  /**
7717
7798
  * UMD公開時のグローバルオブジェクト