ed79793842b2c5e12e436c7059d031674813b516ac78900f5f409368321c8b582e1e45bbf7a9ca22cec13fa4cde65f50079f28c2c835065c69f75e038b5fe6 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. import { merge } from 'lodash-es';
  2. import Emitter from '../core/emitter.js';
  3. import BaseTheme, { BaseTooltip } from './base.js';
  4. import { Range } from '../core/selection.js';
  5. import icons from '../ui/icons.js';
  6. import Quill from '../core/quill.js';
  7. const TOOLBAR_CONFIG = [['bold', 'italic', 'link'], [{
  8. header: 1
  9. }, {
  10. header: 2
  11. }, 'blockquote']];
  12. class BubbleTooltip extends BaseTooltip {
  13. static TEMPLATE = ['<span class="ql-tooltip-arrow"></span>', '<div class="ql-tooltip-editor">', '<input type="text" data-formula="e=mc^2" data-link="https://quilljs.com" data-video="Embed URL">', '<a class="ql-close"></a>', '</div>'].join('');
  14. constructor(quill, bounds) {
  15. super(quill, bounds);
  16. this.quill.on(Emitter.events.EDITOR_CHANGE, (type, range, oldRange, source) => {
  17. if (type !== Emitter.events.SELECTION_CHANGE) return;
  18. if (range != null && range.length > 0 && source === Emitter.sources.USER) {
  19. this.show();
  20. // Lock our width so we will expand beyond our offsetParent boundaries
  21. this.root.style.left = '0px';
  22. this.root.style.width = '';
  23. this.root.style.width = `${this.root.offsetWidth}px`;
  24. const lines = this.quill.getLines(range.index, range.length);
  25. if (lines.length === 1) {
  26. const bounds = this.quill.getBounds(range);
  27. if (bounds != null) {
  28. this.position(bounds);
  29. }
  30. } else {
  31. const lastLine = lines[lines.length - 1];
  32. const index = this.quill.getIndex(lastLine);
  33. const length = Math.min(lastLine.length() - 1, range.index + range.length - index);
  34. const indexBounds = this.quill.getBounds(new Range(index, length));
  35. if (indexBounds != null) {
  36. this.position(indexBounds);
  37. }
  38. }
  39. } else if (document.activeElement !== this.textbox && this.quill.hasFocus()) {
  40. this.hide();
  41. }
  42. });
  43. }
  44. listen() {
  45. super.listen();
  46. // @ts-expect-error Fix me later
  47. this.root.querySelector('.ql-close').addEventListener('click', () => {
  48. this.root.classList.remove('ql-editing');
  49. });
  50. this.quill.on(Emitter.events.SCROLL_OPTIMIZE, () => {
  51. // Let selection be restored by toolbar handlers before repositioning
  52. setTimeout(() => {
  53. if (this.root.classList.contains('ql-hidden')) return;
  54. const range = this.quill.getSelection();
  55. if (range != null) {
  56. const bounds = this.quill.getBounds(range);
  57. if (bounds != null) {
  58. this.position(bounds);
  59. }
  60. }
  61. }, 1);
  62. });
  63. }
  64. cancel() {
  65. this.show();
  66. }
  67. position(reference) {
  68. const shift = super.position(reference);
  69. const arrow = this.root.querySelector('.ql-tooltip-arrow');
  70. // @ts-expect-error
  71. arrow.style.marginLeft = '';
  72. if (shift !== 0) {
  73. // @ts-expect-error
  74. arrow.style.marginLeft = `${-1 * shift - arrow.offsetWidth / 2}px`;
  75. }
  76. return shift;
  77. }
  78. }
  79. class BubbleTheme extends BaseTheme {
  80. constructor(quill, options) {
  81. if (options.modules.toolbar != null && options.modules.toolbar.container == null) {
  82. options.modules.toolbar.container = TOOLBAR_CONFIG;
  83. }
  84. super(quill, options);
  85. this.quill.container.classList.add('ql-bubble');
  86. }
  87. extendToolbar(toolbar) {
  88. // @ts-expect-error
  89. this.tooltip = new BubbleTooltip(this.quill, this.options.bounds);
  90. if (toolbar.container != null) {
  91. this.tooltip.root.appendChild(toolbar.container);
  92. this.buildButtons(toolbar.container.querySelectorAll('button'), icons);
  93. this.buildPickers(toolbar.container.querySelectorAll('select'), icons);
  94. }
  95. }
  96. }
  97. BubbleTheme.DEFAULTS = merge({}, BaseTheme.DEFAULTS, {
  98. modules: {
  99. toolbar: {
  100. handlers: {
  101. link(value) {
  102. if (!value) {
  103. this.quill.format('link', false, Quill.sources.USER);
  104. } else {
  105. // @ts-expect-error
  106. this.quill.theme.tooltip.edit();
  107. }
  108. }
  109. }
  110. }
  111. }
  112. });
  113. export { BubbleTooltip, BubbleTheme as default };
  114. //# sourceMappingURL=bubble.js.map