UNPKG

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