UNPKG

@cairn214/fluent-editor

Version:

A rich text editor based on Quill 2.0, which extends rich modules and formats on the basis of Quill. It's powerful and out-of-the-box.

309 lines (308 loc) 9.36 kB
"use strict"; const Quill = require("quill"); const editor_utils = require("../config/editor.utils.cjs.js"); const SnowTheme = Quill.imports["themes/snow"]; let optionsCounter = 0; function toggleAriaAttribute(element, attribute) { element.setAttribute( attribute, element.getAttribute(attribute) !== "true" ); } class Picker { constructor(select) { this.select = select; this.container = document.createElement("span"); this.buildPicker(); this.select.style.display = "none"; this.select.parentNode.insertBefore(this.container, this.select); this.label.addEventListener("mousedown", (e) => { this.togglePicker(); e.preventDefault(); }); this.label.addEventListener("keydown", (event) => { switch (event.key) { case "Enter": this.togglePicker(); break; case "Escape": this.escape(); event.preventDefault(); break; default: } }); this.select.addEventListener("change", this.update.bind(this)); } togglePicker() { this.container.classList.toggle("ql-expanded"); toggleAriaAttribute(this.label, "aria-expanded"); toggleAriaAttribute(this.options, "aria-hidden"); } buildItem(option) { const item = document.createElement("span"); item.tabIndex = 0; item.setAttribute("role", "button"); item.classList.add("ql-picker-item"); if (option.hasAttribute("value")) { item.setAttribute("data-value", option.getAttribute("value")); } if (option.textContent) { item.setAttribute("data-label", option.textContent); } item.addEventListener("click", () => { this.selectItem(item, true); }); item.addEventListener("keydown", (event) => { switch (event.key) { case "Enter": this.selectItem(item, true); event.preventDefault(); break; case "Escape": this.escape(); event.preventDefault(); break; default: } }); return item; } buildLabel() { const label = document.createElement("span"); label.classList.add("ql-picker-label"); label.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> `; label.tabIndex = 0; label.setAttribute("role", "button"); label.setAttribute("aria-expanded", "false"); this.container.appendChild(label); return label; } buildOptions() { const options = document.createElement("span"); options.classList.add("ql-picker-options"); options.setAttribute("aria-hidden", "true"); options.tabIndex = -1; options.id = `ql-picker-options-${optionsCounter}`; optionsCounter += 1; this.label.setAttribute("aria-controls", options.id); this.options = options; Array.from(this.select.options).forEach((option) => { const item = this.buildItem(option); options.appendChild(item); if (option.selected === true) { this.selectItem(item); } }); this.container.appendChild(options); } buildPicker() { Array.from(this.select.attributes).forEach((item) => { this.container.setAttribute(item.name, item.value); }); this.container.classList.add("ql-picker"); this.label = this.buildLabel(); this.buildOptions(); } escape() { this.close(); setTimeout(() => this.label.focus(), 1); } close() { this.container.classList.remove("ql-expanded"); this.label.setAttribute("aria-expanded", "false"); this.options.setAttribute("aria-hidden", "true"); } selectItem(item, trigger = false) { const selected = this.container.querySelector(".ql-selected"); if (item === selected) return; if (!editor_utils.isNullOrUndefined(selected)) { selected.classList.remove("ql-selected"); } if (editor_utils.isNullOrUndefined(item)) return; item.classList.add("ql-selected"); this.select.selectedIndex = Array.from(item.parentNode.children).indexOf( item ); if (item.hasAttribute("data-value")) { this.label.setAttribute("data-value", item.getAttribute("data-value")); } else { this.label.removeAttribute("data-value"); } if (item.hasAttribute("data-label")) { this.label.setAttribute("data-label", item.getAttribute("data-label")); } else { this.label.removeAttribute("data-label"); } if (trigger) { let ev; if (typeof Event === "function") { ev = new Event("change"); } else { ev = document.createEvent("Event"); ev.initEvent("change", true, true); } this.select.dispatchEvent(ev); this.close(); } } update() { let option; if (this.select.selectedIndex > -1) { const item = this.container.querySelector(".ql-picker-options").children[this.select.selectedIndex]; option = this.select.options[this.select.selectedIndex]; this.selectItem(item); } else { this.selectItem(null); } const isActive = !editor_utils.isNullOrUndefined(option) && option !== this.select.querySelector("option[selected]"); if (isActive) { this.label.classList.add("ql-active"); } else { this.label.classList.remove("ql-active"); } } } class IconPicker extends Picker { constructor(select, icons) { super(select); this.container.classList.add("ql-icon-picker"); Array.from(this.container.querySelectorAll(".ql-picker-item")).forEach( (item) => { item.innerHTML = icons[item.getAttribute("data-value") || ""]; } ); this.defaultItem = this.container.querySelector(".ql-selected"); this.selectItem(this.defaultItem, null); } selectItem(target, trigger) { super.selectItem(target, trigger); const item = target || this.defaultItem; if (this.label.innerHTML === item.innerHTML) return; this.label.innerHTML = item.innerHTML; } } class ColorPicker extends Picker { constructor(select, label) { super(select); this.label.innerHTML = label; this.container.classList.add("ql-color-picker"); Array.from(this.container.querySelectorAll(".ql-picker-item")).slice(0, 7).forEach((item) => { item.classList.add("ql-primary"); }); } buildItem(option) { const item = super.buildItem(option); item.style.backgroundColor = option.getAttribute("value") || ""; return item; } selectItem(item, trigger) { super.selectItem(item, trigger); const colorLabel = this.label.querySelector(".ql-color-label"); const value = item ? item.getAttribute("data-value") || "" : ""; if (colorLabel) { if (colorLabel.tagName === "line") { colorLabel.style.stroke = value; } else { colorLabel.style.fill = value; } } } } Quill.register("ui/picker", Picker, true); Quill.register("ui/icon-picker", IconPicker, true); Quill.register("ui/color-picker", ColorPicker, true); const ALIGNS = [false, "center", "right"]; const COLORS = [ "#000000", "#e60000", "#ff9900", "#ffff00", "#008a00", "#0066cc", "#9933ff", "#ffffff", "#facccc", "#ffebcc", "#ffffcc", "#cce8cc", "#cce0f5", "#ebd6ff", "#bbbbbb", "#f06666", "#ffc266", "#ffff66", "#66b966", "#66a3e0", "#c285ff", "#888888", "#a10000", "#b26b00", "#b2b200", "#006100", "#0047b2", "#6b24b2", "#444444", "#5c0000", "#663d00", "#666600", "#003700", "#002966", "#3d1466" ]; const FONTS = [false, "serif", "monospace"]; const HEADERS = ["1", "2", "3", false]; const SIZES = ["small", false, "large", "huge"]; SnowTheme.prototype.buildPickers = function(selects, icons) { this.pickers = Array.from(selects).map((select) => { if (select.classList.contains("ql-align")) { if (editor_utils.isNullOrUndefined(select.querySelector("option"))) { fillSelect(select, ALIGNS); } return new IconPicker(select, icons.align); } if (select.classList.contains("ql-background") || select.classList.contains("ql-color")) { const format = select.classList.contains("ql-background") ? "background" : "color"; if (editor_utils.isNullOrUndefined(select.querySelector("option"))) { fillSelect( select, COLORS ); } return new ColorPicker(select, icons[format]); } if (editor_utils.isNullOrUndefined(select.querySelector("option"))) { if (select.classList.contains("ql-font")) { fillSelect(select, FONTS); } else if (select.classList.contains("ql-header")) { fillSelect(select, HEADERS); } else if (select.classList.contains("ql-size")) { fillSelect(select, SIZES); } } return new Picker(select); }); const update = () => { this.pickers.forEach((picker) => { picker.update(); }); }; this.quill.on(Quill.events.EDITOR_CHANGE, update); }; function fillSelect(select, values, defaultValue = false) { values.forEach((value) => { const option = document.createElement("option"); if (value === defaultValue) { option.setAttribute("selected", "selected"); } else { option.setAttribute("value", value); } select.appendChild(option); }); } //# sourceMappingURL=better-picker.cjs.js.map