handleFormElement.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. import { keyDefinitions } from '@/utils/USKeyboardLayout';
  2. import simulateEvent from './simulateEvent';
  3. const nativeInputValueSetter = Object.getOwnPropertyDescriptor(
  4. window.HTMLInputElement.prototype,
  5. 'value'
  6. ).set;
  7. function reactJsEvent(element, value) {
  8. if (!element._valueTracker) return;
  9. nativeInputValueSetter.call(element, value);
  10. }
  11. function formEvent(element, data) {
  12. if (data.type === 'text-field') {
  13. const currentKey = /\s/.test(data.value) ? 'Space' : data.value;
  14. const { key, keyCode, code } = keyDefinitions[currentKey] || {
  15. key: currentKey,
  16. keyCode: 0,
  17. code: `Key${currentKey}`,
  18. };
  19. simulateEvent(element, 'keydown', {
  20. key,
  21. code,
  22. keyCode,
  23. bubbles: true,
  24. cancelable: true,
  25. });
  26. simulateEvent(element, 'keyup', {
  27. key,
  28. code,
  29. keyCode,
  30. bubbles: true,
  31. cancelable: true,
  32. });
  33. }
  34. simulateEvent(element, 'input', {
  35. inputType: 'insertText',
  36. data: data.value,
  37. bubbles: true,
  38. cancelable: true,
  39. });
  40. if (data.type !== 'text-field') {
  41. element.dispatchEvent(
  42. new Event('change', { bubbles: true, cancelable: true })
  43. );
  44. }
  45. }
  46. async function inputText({ data, element, isEditable }) {
  47. const elementKey = isEditable ? 'textContent' : 'value';
  48. if (data.delay > 0 && !document.hidden) {
  49. for (let index = 0; index < data.value.length; index += 1) {
  50. const currentChar = data.value[index];
  51. element[elementKey] += currentChar;
  52. if (elementKey === 'value') reactJsEvent(element, element.value);
  53. formEvent(element, {
  54. type: 'text-field',
  55. value: currentChar,
  56. isEditable,
  57. });
  58. await new Promise((r) => setTimeout(r, data.delay));
  59. }
  60. } else {
  61. element[elementKey] += data.value;
  62. if (elementKey === 'value') reactJsEvent(element, element.value);
  63. formEvent(element, {
  64. isEditable,
  65. type: 'text-field',
  66. value: data.value[0] ?? '',
  67. });
  68. }
  69. element.dispatchEvent(
  70. new Event('change', { bubbles: true, cancelable: true })
  71. );
  72. }
  73. export default async function (element, data) {
  74. const textFields = ['INPUT', 'TEXTAREA'];
  75. const isEditable =
  76. element.hasAttribute('contenteditable') && element.isContentEditable;
  77. if (isEditable) {
  78. if (data.clearValue) element.innerText = '';
  79. await inputText({ data, element, isEditable });
  80. return;
  81. }
  82. if (data.type === 'text-field' && textFields.includes(element.tagName)) {
  83. if (data.clearValue) element.value = '';
  84. await inputText({ data, element });
  85. return;
  86. }
  87. if (data.type === 'checkbox' || data.type === 'radio') {
  88. element.checked = data.selected;
  89. formEvent(element, { type: data.type, value: data.selected });
  90. return;
  91. }
  92. if (data.type === 'select') {
  93. element.value = data.value;
  94. formEvent(element, data);
  95. }
  96. }