00381a0851c305a07fc5a07b516dc29e99bde5d3cf79f7c6bd25ac30cc5038d5430aebaf7eeab9d6995d2c75bc030d06263111e1732d9a0d3e3f5d987821e2 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. import Delta from 'quill-delta';
  2. import Module from '../core/module.js';
  3. import Quill from '../core/quill.js';
  4. import { deleteRange } from './keyboard.js';
  5. const INSERT_TYPES = ['insertText', 'insertReplacementText'];
  6. class Input extends Module {
  7. constructor(quill, options) {
  8. super(quill, options);
  9. quill.root.addEventListener('beforeinput', event => {
  10. this.handleBeforeInput(event);
  11. });
  12. // Gboard with English input on Android triggers `compositionstart` sometimes even
  13. // users are not going to type anything.
  14. if (!/Android/i.test(navigator.userAgent)) {
  15. quill.on(Quill.events.COMPOSITION_BEFORE_START, () => {
  16. this.handleCompositionStart();
  17. });
  18. }
  19. }
  20. deleteRange(range) {
  21. deleteRange({
  22. range,
  23. quill: this.quill
  24. });
  25. }
  26. replaceText(range) {
  27. let text = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
  28. if (range.length === 0) return false;
  29. if (text) {
  30. // Follow the native behavior that inherits the formats of the first character
  31. const formats = this.quill.getFormat(range.index, 1);
  32. this.deleteRange(range);
  33. this.quill.updateContents(new Delta().retain(range.index).insert(text, formats), Quill.sources.USER);
  34. } else {
  35. this.deleteRange(range);
  36. }
  37. this.quill.setSelection(range.index + text.length, 0, Quill.sources.SILENT);
  38. return true;
  39. }
  40. handleBeforeInput(event) {
  41. if (this.quill.composition.isComposing || event.defaultPrevented || !INSERT_TYPES.includes(event.inputType)) {
  42. return;
  43. }
  44. const staticRange = event.getTargetRanges ? event.getTargetRanges()[0] : null;
  45. if (!staticRange || staticRange.collapsed === true) {
  46. return;
  47. }
  48. const text = getPlainTextFromInputEvent(event);
  49. if (text == null) {
  50. return;
  51. }
  52. const normalized = this.quill.selection.normalizeNative(staticRange);
  53. const range = normalized ? this.quill.selection.normalizedToRange(normalized) : null;
  54. if (range && this.replaceText(range, text)) {
  55. event.preventDefault();
  56. }
  57. }
  58. handleCompositionStart() {
  59. const range = this.quill.getSelection();
  60. if (range) {
  61. this.replaceText(range);
  62. }
  63. }
  64. }
  65. function getPlainTextFromInputEvent(event) {
  66. // When `inputType` is "insertText":
  67. // - `event.data` should be string (Safari uses `event.dataTransfer`).
  68. // - `event.dataTransfer` should be null.
  69. // When `inputType` is "insertReplacementText":
  70. // - `event.data` should be null.
  71. // - `event.dataTransfer` should contain "text/plain" data.
  72. if (typeof event.data === 'string') {
  73. return event.data;
  74. }
  75. if (event.dataTransfer?.types.includes('text/plain')) {
  76. return event.dataTransfer.getData('text/plain');
  77. }
  78. return null;
  79. }
  80. export default Input;
  81. //# sourceMappingURL=input.js.map