Browse Source

Add custom to RichTextEditor

pull/5649/head
Artur Arseniev 3 years ago
parent
commit
c9c0a7b2cf
  1. 6
      src/rich_text_editor/config/config.ts
  2. 43
      src/rich_text_editor/index.ts
  3. 20
      src/rich_text_editor/model/RichTextEditor.ts

6
src/rich_text_editor/config/config.ts

@ -16,12 +16,18 @@ export interface RichTextEditorConfig {
* @default ['bold', 'italic', 'underline', 'strikethrough', 'link', 'wrap'] * @default ['bold', 'italic', 'underline', 'strikethrough', 'link', 'wrap']
*/ */
actions?: string[]; actions?: string[];
/**
* Avoid rendering the default RTE UI.
* @default false
*/
custom?: boolean;
} }
const config: RichTextEditorConfig = { const config: RichTextEditorConfig = {
stylePrefix: 'rte-', stylePrefix: 'rte-',
adjustToolbar: true, adjustToolbar: true,
actions: ['bold', 'italic', 'underline', 'strikethrough', 'link', 'wrap'], actions: ['bold', 'italic', 'underline', 'strikethrough', 'link', 'wrap'],
custom: false,
}; };
export default config; export default config;

43
src/rich_text_editor/index.ts

@ -36,8 +36,9 @@
* @module RichTextEditor * @module RichTextEditor
*/ */
import { isString } from 'underscore'; import { debounce, isString } from 'underscore';
import { Module } from '../abstract'; import { Module } from '../abstract';
import { Debounced, Model } from '../common';
import ComponentView from '../dom_components/view/ComponentView'; import ComponentView from '../dom_components/view/ComponentView';
import EditorModel from '../editor/model/Editor'; import EditorModel from '../editor/model/Editor';
import { removeEl } from '../utils/dom'; import { removeEl } from '../utils/dom';
@ -45,10 +46,20 @@ import { hasWin, isDef, on } from '../utils/mixins';
import defaults, { RichTextEditorConfig } from './config/config'; import defaults, { RichTextEditorConfig } from './config/config';
import RichTextEditor, { RichTextEditorAction } from './model/RichTextEditor'; 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'; 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<T = any> { export interface CustomRTE<T = any> {
/** /**
* If true, the returned HTML content will be parsed into Components, allowing * If true, the returned HTML content will be parsed into Components, allowing
@ -78,6 +89,10 @@ export interface CustomRTE<T = any> {
[key: string]: unknown; [key: string]: unknown;
} }
interface ModelRTE {
enabled: boolean;
}
export default class RichTextEditorModule extends Module<RichTextEditorConfig & { pStylePrefix?: string }> { export default class RichTextEditorModule extends Module<RichTextEditorConfig & { pStylePrefix?: string }> {
pfx: string; pfx: string;
toolbar!: HTMLElement; toolbar!: HTMLElement;
@ -86,6 +101,9 @@ export default class RichTextEditorModule extends Module<RichTextEditorConfig &
lastEl?: HTMLElement; lastEl?: HTMLElement;
actions?: (RichTextEditorAction | string)[]; actions?: (RichTextEditorAction | string)[];
customRte?: CustomRTE; customRte?: CustomRTE;
model: Model<ModelRTE>;
__dbdTrgCustom: Debounced;
events = events;
/** /**
* Get configuration object * Get configuration object
@ -105,6 +123,12 @@ export default class RichTextEditorModule extends Module<RichTextEditorConfig &
this.pfx = config.stylePrefix!; this.pfx = config.stylePrefix!;
this.actions = config.actions || []; this.actions = config.actions || [];
const model = new Model({
enabled: false,
});
this.model = model;
model.on('change:enabled', this.__trgCustom, this);
this.__dbdTrgCustom = debounce(() => this.__trgCustom(), 0);
if (!hasWin()) return this; if (!hasWin()) return this;
const toolbar = document.createElement('div'); const toolbar = document.createElement('div');
toolbar.className = `${ppfx}rte-toolbar ${ppfx}one-bg`; toolbar.className = `${ppfx}rte-toolbar ${ppfx}one-bg`;
@ -115,9 +139,20 @@ export default class RichTextEditorModule extends Module<RichTextEditorConfig &
on(toolbar, 'mousedown', e => e.stopPropagation()); on(toolbar, 'mousedown', e => e.stopPropagation());
} }
__trgCustom() {
const { model, em, events } = this;
em.trigger(events.custom, {
enabled: !!model.get('enabled'),
container: this.getToolbarEl(),
actions: this.getAll(),
});
}
destroy() { destroy() {
this.globalRte?.destroy(); this.globalRte?.destroy();
this.customRte?.destroy?.(); this.customRte?.destroy?.();
this.model.stopListening().clear({ silent: true });
this.__dbdTrgCustom.cancel();
removeEl(this.toolbar); removeEl(this.toolbar);
} }
@ -340,6 +375,8 @@ export default class RichTextEditorModule extends Module<RichTextEditorConfig &
em.trigger('rte:enable', view, rteInst); em.trigger('rte:enable', view, rteInst);
} }
this.model.set({ enabled: true });
return rteInst; return rteInst;
} }
@ -375,5 +412,7 @@ export default class RichTextEditorModule extends Module<RichTextEditorConfig &
em.off(eventsUp, this.updatePosition, this); em.off(eventsUp, this.updatePosition, this);
em.trigger('rte:disable', view, rte); em.trigger('rte:disable', view, rte);
} }
this.model.set({ enabled: false });
} }
} }

20
src/rich_text_editor/model/RichTextEditor.ts

@ -14,6 +14,13 @@ export interface RichTextEditorAction {
update?: (rte: RichTextEditor, action: RichTextEditorAction) => number; update?: (rte: RichTextEditor, action: RichTextEditorAction) => number;
state?: (rte: RichTextEditor, doc: Document) => number; state?: (rte: RichTextEditor, doc: Document) => number;
btn?: HTMLElement; btn?: HTMLElement;
currentState?: RichTextEditorActionState;
}
export enum RichTextEditorActionState {
ACTIVE = 1,
INACTIVE = 0,
DISABLED = -1,
} }
export interface RichTextEditorOptions { export interface RichTextEditorOptions {
@ -181,7 +188,8 @@ export default class RichTextEditor {
} }
updateActiveActions() { updateActiveActions() {
this.getActions().forEach(action => { const actions = this.getActions();
actions.forEach(action => {
const { update } = action; const { update } = action;
const btn = action.btn!; const btn = action.btn!;
const { active, inactive, disabled } = this.classes; 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(active, '').trim();
btn.className = btn.className.replace(inactive, '').trim(); btn.className = btn.className.replace(inactive, '').trim();
btn.className = btn.className.replace(disabled, '').trim(); btn.className = btn.className.replace(disabled, '').trim();
let currentState = RichTextEditorActionState.INACTIVE;
// if there is a state function, which depicts the state, // if there is a state function, which depicts the state,
// i.e. `active`, `disabled`, then call it // i.e. `active`, `disabled`, then call it
if (state) { if (state) {
switch (state(this, doc)) { const newState = state(this, doc);
currentState = newState;
switch (newState) {
case btnState.ACTIVE: case btnState.ACTIVE:
btn.className += ` ${active}`; btn.className += ` ${active}`;
break; break;
@ -210,11 +221,14 @@ export default class RichTextEditor {
// otherwise default to checking if the name command is supported & enabled // otherwise default to checking if the name command is supported & enabled
if (doc.queryCommandSupported(name) && doc.queryCommandState(name)) { if (doc.queryCommandSupported(name) && doc.queryCommandState(name)) {
btn.className += ` ${active}`; btn.className += ` ${active}`;
currentState = RichTextEditorActionState.ACTIVE;
} }
} }
action.currentState = currentState;
update?.(this, action); update?.(this, action);
}); });
actions.length && this.em.RichTextEditor.__dbdTrgCustom();
} }
enable(opts: EffectOptions) { enable(opts: EffectOptions) {

Loading…
Cancel
Save