You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
114 lines
4.0 KiB
114 lines
4.0 KiB
import { merge } from 'lodash-es'; |
|
import Emitter from '../core/emitter.js'; |
|
import BaseTheme, { BaseTooltip } from './base.js'; |
|
import { Range } from '../core/selection.js'; |
|
import icons from '../ui/icons.js'; |
|
import Quill from '../core/quill.js'; |
|
const TOOLBAR_CONFIG = [['bold', 'italic', 'link'], [{ |
|
header: 1 |
|
}, { |
|
header: 2 |
|
}, 'blockquote']]; |
|
class BubbleTooltip extends BaseTooltip { |
|
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(''); |
|
constructor(quill, bounds) { |
|
super(quill, bounds); |
|
this.quill.on(Emitter.events.EDITOR_CHANGE, (type, range, oldRange, source) => { |
|
if (type !== Emitter.events.SELECTION_CHANGE) return; |
|
if (range != null && range.length > 0 && source === Emitter.sources.USER) { |
|
this.show(); |
|
// Lock our width so we will expand beyond our offsetParent boundaries |
|
this.root.style.left = '0px'; |
|
this.root.style.width = ''; |
|
this.root.style.width = `${this.root.offsetWidth}px`; |
|
const lines = this.quill.getLines(range.index, range.length); |
|
if (lines.length === 1) { |
|
const bounds = this.quill.getBounds(range); |
|
if (bounds != null) { |
|
this.position(bounds); |
|
} |
|
} else { |
|
const lastLine = lines[lines.length - 1]; |
|
const index = this.quill.getIndex(lastLine); |
|
const length = Math.min(lastLine.length() - 1, range.index + range.length - index); |
|
const indexBounds = this.quill.getBounds(new Range(index, length)); |
|
if (indexBounds != null) { |
|
this.position(indexBounds); |
|
} |
|
} |
|
} else if (document.activeElement !== this.textbox && this.quill.hasFocus()) { |
|
this.hide(); |
|
} |
|
}); |
|
} |
|
listen() { |
|
super.listen(); |
|
// @ts-expect-error Fix me later |
|
this.root.querySelector('.ql-close').addEventListener('click', () => { |
|
this.root.classList.remove('ql-editing'); |
|
}); |
|
this.quill.on(Emitter.events.SCROLL_OPTIMIZE, () => { |
|
// Let selection be restored by toolbar handlers before repositioning |
|
setTimeout(() => { |
|
if (this.root.classList.contains('ql-hidden')) return; |
|
const range = this.quill.getSelection(); |
|
if (range != null) { |
|
const bounds = this.quill.getBounds(range); |
|
if (bounds != null) { |
|
this.position(bounds); |
|
} |
|
} |
|
}, 1); |
|
}); |
|
} |
|
cancel() { |
|
this.show(); |
|
} |
|
position(reference) { |
|
const shift = super.position(reference); |
|
const arrow = this.root.querySelector('.ql-tooltip-arrow'); |
|
// @ts-expect-error |
|
arrow.style.marginLeft = ''; |
|
if (shift !== 0) { |
|
// @ts-expect-error |
|
arrow.style.marginLeft = `${-1 * shift - arrow.offsetWidth / 2}px`; |
|
} |
|
return shift; |
|
} |
|
} |
|
class BubbleTheme extends BaseTheme { |
|
constructor(quill, options) { |
|
if (options.modules.toolbar != null && options.modules.toolbar.container == null) { |
|
options.modules.toolbar.container = TOOLBAR_CONFIG; |
|
} |
|
super(quill, options); |
|
this.quill.container.classList.add('ql-bubble'); |
|
} |
|
extendToolbar(toolbar) { |
|
// @ts-expect-error |
|
this.tooltip = new BubbleTooltip(this.quill, this.options.bounds); |
|
if (toolbar.container != null) { |
|
this.tooltip.root.appendChild(toolbar.container); |
|
this.buildButtons(toolbar.container.querySelectorAll('button'), icons); |
|
this.buildPickers(toolbar.container.querySelectorAll('select'), icons); |
|
} |
|
} |
|
} |
|
BubbleTheme.DEFAULTS = merge({}, BaseTheme.DEFAULTS, { |
|
modules: { |
|
toolbar: { |
|
handlers: { |
|
link(value) { |
|
if (!value) { |
|
this.quill.format('link', false, Quill.sources.USER); |
|
} else { |
|
// @ts-expect-error |
|
this.quill.theme.tooltip.edit(); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
}); |
|
export { BubbleTooltip, BubbleTheme as default }; |
|
//# sourceMappingURL=bubble.js.map
|