/** @class Abstract class representing a tool for a Quill Editor toolbar. */
class QuillToolbarItem {
constructor(options) {
const me = this
me.options = options
me.qlFormatsEl = document.createElement("span")
me.qlFormatsEl.className = "ql-formats"
}
/**
* Attaches this tool to the given Quill Editor instance.
*
* @param {Quill} quill - The Quill Editor instance that this tool should get added to.
*/
attach(quill) {
const me = this
me.quill = quill
me.toolbar = quill.getModule('toolbar')
me.toolbarEl = me.toolbar.container
me.toolbarEl.appendChild(me.qlFormatsEl)
}
/**
* Detaches this tool from the given Quill Editor instance.
*
* @param {Quill} quill - The Quill Editor instance that this tool should get added to.
*/
detach(quill) {
const me = this
me.toolbarEl.removeChild(me.qlFormatsEl)
}
/**
* Calculate the width of text.
*
* @param {string} text - The text of which the length should be calculated.
* @param {string} [font="500 14px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"] - The font css that shuold be applied to the text before calculating the width.
*/
_getTextWidth(text, font="500 14px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif") {
const canvas = this._getTextWidth.canvas || (this._getTextWidth.canvas = document.createElement("canvas"))
const context = canvas.getContext("2d")
context.font = font
const metrics = context.measureText(text)
return metrics.width
}
/**
* Add a global css rule to the document.
*
* @param {string} cssRule - CSS rules
*/
_addCssRule(cssRule) {
const style = document.createElement("style");
document.head.appendChild(style);
style.sheet.insertRule(cssRule, 0)
}
/**
* Generate a random ID.
*
* @returns {string} random 10 digit ID
*/
_generateId() {
return Math.random().toString().substr(2, 10)
}
}
/** @class Class representing a dropdown tool for a Quill Editor toolbar. */
class QuillToolbarDropDown extends QuillToolbarItem {
/**
* Creates an instance of QuillToolbarDropDown.
*
* @constructor
* @param {object} [options] - The options/settings for this QuillToolbarDropDown.
* @param {string} [options.id=`dropdown-${random10digitNumber}`] - The id of the quill tool.
* @param {string} [options.label=""] - The default label that is being displayed before making a selection.
* @param {boolean} [options.rememberSelection=true] - Automatically change the label to the current selection.
* @param {object} [options.items={}] - The default items this dropdown will have. Needs to be a key-value-object (key=visible label; value=actual value).
*/
constructor(options) {
super(options)
const me = this
me.id = me.options.id || `dropdown-${me._generateId()}`
const qlPicker = document.createElement("span")
qlPicker.className = `ql-${me.id} ql-picker`
me.qlFormatsEl.appendChild(qlPicker)
const qlPickerLabel = document.createElement("span")
qlPickerLabel.className = "ql-picker-label"
qlPicker.appendChild(qlPickerLabel)
qlPickerLabel.addEventListener('click', function(e) {
qlPicker.classList.toggle('ql-expanded')
})
window.addEventListener('click', function(e){
if (!qlPicker.contains(e.target)){
qlPicker.classList.remove('ql-expanded')
}
})
const qlPickerOptions = document.createElement("span")
qlPickerOptions.className = "ql-picker-options"
qlPicker.appendChild(qlPickerOptions)
me.dropDownEl = qlPicker
me.dropDownPickerEl = me.dropDownEl.querySelector('.ql-picker-options')
me.dropDownPickerLabelEl = me.dropDownEl.querySelector('.ql-picker-label')
me.dropDownPickerLabelEl.innerHTML = `<svg viewBox="0 0 18 18"> <polygon class="ql-stroke" points="7 11 9 13 11 11 7 11"></polygon> <polygon class="ql-stroke" points="7 7 9 5 11 7 7 7"></polygon> </svg>`
me.setLabel(me.options.label || "")
me.setItems(me.options.items || {})
me._addCssRule(`
.ql-snow .ql-picker.ql-${me.id} .ql-picker-label::before, .ql-${me.id} .ql-picker.ql-size .ql-picker-item::before {
content: attr(data-label);
}
`)
}
/**
* Set the items for this dropdown tool.
*
* @param {object} items - Needs to be a key-value-object (key=visible label; value=actual value).
*/
setItems(items) {
const me = this
for (const [label,value] of Object.entries(items)) {
const newItemEl = document.createElement("span")
newItemEl.className = "ql-picker-item"
newItemEl.innerHTML = label
newItemEl.setAttribute('data-value', value)
newItemEl.onclick = function(e) {
me.dropDownEl.classList.remove('ql-expanded')
if (me.options.rememberSelection)
me.setLabel(label)
if (me.onSelect)
me.onSelect(label, value, me.quill)
}
me.dropDownPickerEl.appendChild(newItemEl)
}
}
/**
* Set the label for this dropdown tool and automatically adjust the width to fit the label.
*
* @param {String} newLabel - The new label that should be set.
*/
setLabel(newLabel) {
const me = this
const requiredWidth = `${me._getTextWidth(newLabel)+30}px`
me.dropDownPickerLabelEl.style.width = requiredWidth
me.dropDownPickerLabelEl.setAttribute('data-label', newLabel)
}
/**
* A callback that gets called automatically when the dropdown selection changes. This callback is expected to be overwritten.
*
* @param {string} label - The label of the newly selected item.
* @param {string} value - The value of the newly selected item.
* @param {Quill} quill - The quill instance the dropdown tool is attached to.
*/
onSelect(label, value, quill) {
}
}
/** @class Class representing a button tool for a Quill Editor toolbar. */
class QuillToolbarButton extends QuillToolbarItem {
/**
* Creates an instance of QuillToolbarButton.
*
* @constructor
* @param {object} [options] - The options/settings for this QuillToolbarButton.
* @param {string} [options.id=`button-${random10digitNumber}`] - The id of the quill tool.
* @param {string} [options.value] - The default hidden value of the button.
* @param {string} options.icon - The default icon this button tool will have.
*/
constructor(options) {
super(options)
const me = this
me.id = me.options.id || `button-${me._generateId()}`
me.qlButton = document.createElement("button")
me.qlButton.className = `ql-${me.id}`
me.setValue(me.options.value)
me.setIcon(me.options.icon)
me.qlButton.onclick = function() {
me.onClick(me.quill)
}
me.qlFormatsEl.appendChild(me.qlButton)
}
/**
* Set the icon for this button tool.
*
* @param {string} newLabel - The <svg> or <img> html tag to use as an icon. (Make sure it's 18x18 in size.)
*/
setIcon(imageHtml) {
const me = this
me.qlButton.innerHTML = imageHtml
}
/**
* Set the hidden value of this button tool.
*
* @param {string} newLabel - The <svg> or <img> html tag to use as an icon. (Make sure it's 18x18 in size.)
*/
setValue(value) {
const me = this
me.qlButton.value = value
}
/**
* Set the hidden value of this button tool.
*
* @param {string} newLabel - The <svg> or <img> html tag to use as an icon. (Make sure it's 18x18 in size.)
*/
getValue() {
const me = this
return me.qlButton.value
}
/**
* A callback that gets called automatically when the button is clicked, tapped or triggered witht he keyboard etc. This callback is expected to be overwritten.
*
* @param {Quill} quill - The quill instance the dropdown tool is attached to.
*/
onClick(button, quill) {
}
}