From c9c0a7b2cfacae9ee69ece07e5e287c953840e63 Mon Sep 17 00:00:00 2001 From: Artur Arseniev Date: Thu, 18 May 2023 13:29:45 +0400 Subject: [PATCH] Add custom to RichTextEditor --- src/rich_text_editor/config/config.ts | 6 +++ src/rich_text_editor/index.ts | 43 +++++++++++++++++++- src/rich_text_editor/model/RichTextEditor.ts | 20 +++++++-- 3 files changed, 64 insertions(+), 5 deletions(-) diff --git a/src/rich_text_editor/config/config.ts b/src/rich_text_editor/config/config.ts index ea0d0341d..303b635d0 100644 --- a/src/rich_text_editor/config/config.ts +++ b/src/rich_text_editor/config/config.ts @@ -16,12 +16,18 @@ export interface RichTextEditorConfig { * @default ['bold', 'italic', 'underline', 'strikethrough', 'link', 'wrap'] */ actions?: string[]; + /** + * Avoid rendering the default RTE UI. + * @default false + */ + custom?: boolean; } const config: RichTextEditorConfig = { stylePrefix: 'rte-', adjustToolbar: true, actions: ['bold', 'italic', 'underline', 'strikethrough', 'link', 'wrap'], + custom: false, }; export default config; diff --git a/src/rich_text_editor/index.ts b/src/rich_text_editor/index.ts index a332a40f1..5aaff2371 100644 --- a/src/rich_text_editor/index.ts +++ b/src/rich_text_editor/index.ts @@ -36,8 +36,9 @@ * @module RichTextEditor */ -import { isString } from 'underscore'; +import { debounce, isString } from 'underscore'; import { Module } from '../abstract'; +import { Debounced, Model } from '../common'; import ComponentView from '../dom_components/view/ComponentView'; import EditorModel from '../editor/model/Editor'; import { removeEl } from '../utils/dom'; @@ -45,10 +46,20 @@ import { hasWin, isDef, on } from '../utils/mixins'; import defaults, { RichTextEditorConfig } from './config/config'; import RichTextEditor, { RichTextEditorAction } from './model/RichTextEditor'; -export type RichTextEditorEvent = 'rte:enable' | 'rte:disable'; +export type RichTextEditorEvent = 'rte:enable' | 'rte:disable' | 'rte:custom'; const eventsUp = 'change:canvasOffset frame:scroll component:update'; +export const evEnable = 'rte:enable'; +export const evDisable = 'rte:disable'; +export const evCustom = 'rte:custom'; + +const events = { + enable: evEnable, + disable: evDisable, + custom: evCustom, +}; + export interface CustomRTE { /** * If true, the returned HTML content will be parsed into Components, allowing @@ -78,6 +89,10 @@ export interface CustomRTE { [key: string]: unknown; } +interface ModelRTE { + enabled: boolean; +} + export default class RichTextEditorModule extends Module { pfx: string; toolbar!: HTMLElement; @@ -86,6 +101,9 @@ export default class RichTextEditorModule extends Module; + __dbdTrgCustom: Debounced; + events = events; /** * Get configuration object @@ -105,6 +123,12 @@ export default class RichTextEditorModule extends Module this.__trgCustom(), 0); if (!hasWin()) return this; const toolbar = document.createElement('div'); toolbar.className = `${ppfx}rte-toolbar ${ppfx}one-bg`; @@ -115,9 +139,20 @@ export default class RichTextEditorModule extends Module e.stopPropagation()); } + __trgCustom() { + const { model, em, events } = this; + em.trigger(events.custom, { + enabled: !!model.get('enabled'), + container: this.getToolbarEl(), + actions: this.getAll(), + }); + } + destroy() { this.globalRte?.destroy(); this.customRte?.destroy?.(); + this.model.stopListening().clear({ silent: true }); + this.__dbdTrgCustom.cancel(); removeEl(this.toolbar); } @@ -340,6 +375,8 @@ export default class RichTextEditorModule extends Module number; state?: (rte: RichTextEditor, doc: Document) => number; btn?: HTMLElement; + currentState?: RichTextEditorActionState; +} + +export enum RichTextEditorActionState { + ACTIVE = 1, + INACTIVE = 0, + DISABLED = -1, } export interface RichTextEditorOptions { @@ -181,7 +188,8 @@ export default class RichTextEditor { } updateActiveActions() { - this.getActions().forEach(action => { + const actions = this.getActions(); + actions.forEach(action => { const { update } = action; const btn = action.btn!; const { active, inactive, disabled } = this.classes; @@ -191,11 +199,14 @@ export default class RichTextEditor { btn.className = btn.className.replace(active, '').trim(); btn.className = btn.className.replace(inactive, '').trim(); btn.className = btn.className.replace(disabled, '').trim(); + let currentState = RichTextEditorActionState.INACTIVE; // if there is a state function, which depicts the state, // i.e. `active`, `disabled`, then call it if (state) { - switch (state(this, doc)) { + const newState = state(this, doc); + currentState = newState; + switch (newState) { case btnState.ACTIVE: btn.className += ` ${active}`; break; @@ -210,11 +221,14 @@ export default class RichTextEditor { // otherwise default to checking if the name command is supported & enabled if (doc.queryCommandSupported(name) && doc.queryCommandState(name)) { btn.className += ` ${active}`; + currentState = RichTextEditorActionState.ACTIVE; } } - + action.currentState = currentState; update?.(this, action); }); + + actions.length && this.em.RichTextEditor.__dbdTrgCustom(); } enable(opts: EffectOptions) {