snow.js 3.8 KB

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