snow.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. import merge from 'lodash.merge';
  2. import Emitter from '../core/emitter';
  3. import BaseTheme, { BaseTooltip } from './base';
  4. import LinkBlot from '../formats/link';
  5. import { Range } from '../core/selection';
  6. import icons from '../ui/icons';
  7. const TOOLBAR_CONFIG = [
  8. [{ header: ['1', '2', '3', false] }],
  9. ['bold', 'italic', 'underline', 'link'],
  10. [{ list: 'ordered' }, { list: 'bullet' }],
  11. ['clean'],
  12. ];
  13. class SnowTooltip extends BaseTooltip {
  14. constructor(quill, bounds) {
  15. super(quill, bounds);
  16. this.preview = this.root.querySelector('a.ql-preview');
  17. }
  18. listen() {
  19. super.listen();
  20. this.root.querySelector('a.ql-action').addEventListener('click', event => {
  21. if (this.root.classList.contains('ql-editing')) {
  22. this.save();
  23. } else {
  24. this.edit('link', this.preview.textContent);
  25. }
  26. event.preventDefault();
  27. });
  28. this.root.querySelector('a.ql-remove').addEventListener('click', event => {
  29. if (this.linkRange != null) {
  30. const range = this.linkRange;
  31. this.restoreFocus();
  32. this.quill.formatText(range, 'link', false, Emitter.sources.USER);
  33. delete this.linkRange;
  34. }
  35. event.preventDefault();
  36. this.hide();
  37. });
  38. this.quill.on(
  39. Emitter.events.SELECTION_CHANGE,
  40. (range, oldRange, source) => {
  41. if (range == null) return;
  42. if (range.length === 0 && source === Emitter.sources.USER) {
  43. const [link, offset] = this.quill.scroll.descendant(
  44. LinkBlot,
  45. range.index,
  46. );
  47. if (link != null) {
  48. this.linkRange = new Range(range.index - offset, link.length());
  49. const preview = LinkBlot.formats(link.domNode);
  50. this.preview.textContent = preview;
  51. this.preview.setAttribute('href', preview);
  52. this.show();
  53. this.position(this.quill.getBounds(this.linkRange));
  54. return;
  55. }
  56. } else {
  57. delete this.linkRange;
  58. }
  59. this.hide();
  60. },
  61. );
  62. }
  63. show() {
  64. super.show();
  65. this.root.removeAttribute('data-mode');
  66. }
  67. }
  68. SnowTooltip.TEMPLATE = [
  69. '<a class="ql-preview" rel="noopener noreferrer" target="_blank" href="about:blank"></a>',
  70. '<input type="text" data-formula="e=mc^2" data-link="https://quilljs.com" data-video="Embed URL">',
  71. '<a class="ql-action"></a>',
  72. '<a class="ql-remove"></a>',
  73. ].join('');
  74. class SnowTheme extends BaseTheme {
  75. constructor(quill, options) {
  76. if (
  77. options.modules.toolbar != null &&
  78. options.modules.toolbar.container == null
  79. ) {
  80. options.modules.toolbar.container = TOOLBAR_CONFIG;
  81. }
  82. super(quill, options);
  83. this.quill.container.classList.add('ql-snow');
  84. }
  85. extendToolbar(toolbar) {
  86. toolbar.container.classList.add('ql-snow');
  87. this.buildButtons(toolbar.container.querySelectorAll('button'), icons);
  88. this.buildPickers(toolbar.container.querySelectorAll('select'), icons);
  89. this.tooltip = new SnowTooltip(this.quill, this.options.bounds);
  90. if (toolbar.container.querySelector('.ql-link')) {
  91. this.quill.keyboard.addBinding(
  92. { key: 'k', shortKey: true },
  93. (range, context) => {
  94. toolbar.handlers.link.call(toolbar, !context.format.link);
  95. },
  96. );
  97. }
  98. }
  99. }
  100. SnowTheme.DEFAULTS = merge({}, BaseTheme.DEFAULTS, {
  101. modules: {
  102. toolbar: {
  103. handlers: {
  104. link(value) {
  105. if (value) {
  106. const range = this.quill.getSelection();
  107. if (range == null || range.length === 0) return;
  108. let preview = this.quill.getText(range);
  109. if (
  110. /^\S+@\S+\.\S+$/.test(preview) &&
  111. preview.indexOf('mailto:') !== 0
  112. ) {
  113. preview = `mailto:${preview}`;
  114. }
  115. const { tooltip } = this.quill.theme;
  116. tooltip.edit('link', preview);
  117. } else {
  118. this.quill.format('link', false);
  119. }
  120. },
  121. },
  122. },
  123. },
  124. });
  125. export default SnowTheme;