mirror of
https://github.com/BookStackApp/BookStack.git
synced 2025-01-19 08:42:48 +08:00
Lexical: Reorganised some logic into manager
This commit is contained in:
parent
f10ec3271a
commit
517c578a5f
|
@ -49,10 +49,10 @@ export class EditorDropdownButton extends EditorContainerUiElement {
|
||||||
|
|
||||||
handleDropdown(button, menu, () => {
|
handleDropdown(button, menu, () => {
|
||||||
this.open = true;
|
this.open = true;
|
||||||
this.getContext().manager.triggerStateUpdate(this.button);
|
this.getContext().manager.triggerStateUpdateForElement(this.button);
|
||||||
}, () => {
|
}, () => {
|
||||||
this.open = false;
|
this.open = false;
|
||||||
this.getContext().manager.triggerStateUpdate(this.button);
|
this.getContext().manager.triggerStateUpdateForElement(this.button);
|
||||||
});
|
});
|
||||||
|
|
||||||
return wrapper;
|
return wrapper;
|
||||||
|
|
|
@ -9,6 +9,7 @@ export type EditorUiStateUpdate = {
|
||||||
|
|
||||||
export type EditorUiContext = {
|
export type EditorUiContext = {
|
||||||
editor: LexicalEditor,
|
editor: LexicalEditor,
|
||||||
|
editorDOM: HTMLElement,
|
||||||
translate: (text: string) => string,
|
translate: (text: string) => string,
|
||||||
manager: EditorUIManager,
|
manager: EditorUIManager,
|
||||||
lastSelection: BaseSelection|null,
|
lastSelection: BaseSelection|null,
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
import {EditorFormModal, EditorFormModalDefinition} from "./modals";
|
import {EditorFormModal, EditorFormModalDefinition} from "./modals";
|
||||||
import {EditorUiContext, EditorUiElement} from "./core";
|
import {EditorContainerUiElement, EditorUiContext, EditorUiElement, EditorUiStateUpdate} from "./core";
|
||||||
import {EditorDecorator} from "./decorator";
|
import {EditorDecorator, EditorDecoratorAdapter} from "./decorator";
|
||||||
|
import {$getSelection, COMMAND_PRIORITY_LOW, LexicalEditor, SELECTION_CHANGE_COMMAND} from "lexical";
|
||||||
|
import {DecoratorListener} from "lexical/LexicalEditor";
|
||||||
|
import type {NodeKey} from "lexical/LexicalNode";
|
||||||
|
|
||||||
|
|
||||||
export class EditorUIManager {
|
export class EditorUIManager {
|
||||||
|
@ -9,9 +12,11 @@ export class EditorUIManager {
|
||||||
protected decoratorConstructorsByType: Record<string, typeof EditorDecorator> = {};
|
protected decoratorConstructorsByType: Record<string, typeof EditorDecorator> = {};
|
||||||
protected decoratorInstancesByNodeKey: Record<string, EditorDecorator> = {};
|
protected decoratorInstancesByNodeKey: Record<string, EditorDecorator> = {};
|
||||||
protected context: EditorUiContext|null = null;
|
protected context: EditorUiContext|null = null;
|
||||||
|
protected toolbar: EditorContainerUiElement|null = null;
|
||||||
|
|
||||||
setContext(context: EditorUiContext) {
|
setContext(context: EditorUiContext) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
this.setupEditor(context.editor);
|
||||||
}
|
}
|
||||||
|
|
||||||
getContext(): EditorUiContext {
|
getContext(): EditorUiContext {
|
||||||
|
@ -22,7 +27,7 @@ export class EditorUIManager {
|
||||||
return this.context;
|
return this.context;
|
||||||
}
|
}
|
||||||
|
|
||||||
triggerStateUpdate(element: EditorUiElement) {
|
triggerStateUpdateForElement(element: EditorUiElement) {
|
||||||
element.updateState({
|
element.updateState({
|
||||||
selection: null,
|
selection: null,
|
||||||
editor: this.getContext().editor
|
editor: this.getContext().editor
|
||||||
|
@ -49,7 +54,7 @@ export class EditorUIManager {
|
||||||
this.decoratorConstructorsByType[type] = decorator;
|
this.decoratorConstructorsByType[type] = decorator;
|
||||||
}
|
}
|
||||||
|
|
||||||
getDecorator(decoratorType: string, nodeKey: string): EditorDecorator {
|
protected getDecorator(decoratorType: string, nodeKey: string): EditorDecorator {
|
||||||
if (this.decoratorInstancesByNodeKey[nodeKey]) {
|
if (this.decoratorInstancesByNodeKey[nodeKey]) {
|
||||||
return this.decoratorInstancesByNodeKey[nodeKey];
|
return this.decoratorInstancesByNodeKey[nodeKey];
|
||||||
}
|
}
|
||||||
|
@ -64,4 +69,47 @@ export class EditorUIManager {
|
||||||
this.decoratorInstancesByNodeKey[nodeKey] = decorator;
|
this.decoratorInstancesByNodeKey[nodeKey] = decorator;
|
||||||
return decorator;
|
return decorator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setToolbar(toolbar: EditorContainerUiElement) {
|
||||||
|
if (this.toolbar) {
|
||||||
|
this.toolbar.getDOMElement().remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.toolbar = toolbar;
|
||||||
|
toolbar.setContext(this.getContext());
|
||||||
|
this.getContext().editorDOM.before(toolbar.getDOMElement());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected triggerStateUpdate(state: EditorUiStateUpdate): void {
|
||||||
|
const context = this.getContext();
|
||||||
|
context.lastSelection = state.selection;
|
||||||
|
this.toolbar?.updateState(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected setupEditor(editor: LexicalEditor) {
|
||||||
|
// Update button states on editor selection change
|
||||||
|
editor.registerCommand(SELECTION_CHANGE_COMMAND, () => {
|
||||||
|
this.triggerStateUpdate({
|
||||||
|
editor: editor,
|
||||||
|
selection: $getSelection(),
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}, COMMAND_PRIORITY_LOW);
|
||||||
|
|
||||||
|
// Register our DOM decorate listener with the editor
|
||||||
|
const domDecorateListener: DecoratorListener<EditorDecoratorAdapter> = (decorators: Record<NodeKey, EditorDecoratorAdapter>) => {
|
||||||
|
const keys = Object.keys(decorators);
|
||||||
|
for (const key of keys) {
|
||||||
|
const decoratedEl = editor.getElementByKey(key);
|
||||||
|
const adapter = decorators[key];
|
||||||
|
const decorator = this.getDecorator(adapter.type, key);
|
||||||
|
decorator.setNode(adapter.getNode());
|
||||||
|
const decoratorEl = decorator.render(this.getContext());
|
||||||
|
if (decoratedEl) {
|
||||||
|
decoratedEl.append(decoratorEl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
editor.registerDecoratorListener(domDecorateListener);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,15 +1,7 @@
|
||||||
import {
|
import {LexicalEditor} from "lexical";
|
||||||
$getSelection,
|
|
||||||
COMMAND_PRIORITY_LOW,
|
|
||||||
LexicalEditor,
|
|
||||||
SELECTION_CHANGE_COMMAND
|
|
||||||
} from "lexical";
|
|
||||||
import {getMainEditorFullToolbar} from "./toolbars";
|
import {getMainEditorFullToolbar} from "./toolbars";
|
||||||
import {EditorUIManager} from "./framework/manager";
|
import {EditorUIManager} from "./framework/manager";
|
||||||
import {image as imageFormDefinition, link as linkFormDefinition, source as sourceFormDefinition} from "./defaults/form-definitions";
|
import {image as imageFormDefinition, link as linkFormDefinition, source as sourceFormDefinition} from "./defaults/form-definitions";
|
||||||
import {DecoratorListener} from "lexical/LexicalEditor";
|
|
||||||
import type {NodeKey} from "lexical/LexicalNode";
|
|
||||||
import {EditorDecoratorAdapter} from "./framework/decorator";
|
|
||||||
import {ImageDecorator} from "./decorators/image";
|
import {ImageDecorator} from "./decorators/image";
|
||||||
import {EditorUiContext} from "./framework/core";
|
import {EditorUiContext} from "./framework/core";
|
||||||
|
|
||||||
|
@ -17,6 +9,7 @@ export function buildEditorUI(element: HTMLElement, editor: LexicalEditor) {
|
||||||
const manager = new EditorUIManager();
|
const manager = new EditorUIManager();
|
||||||
const context: EditorUiContext = {
|
const context: EditorUiContext = {
|
||||||
editor,
|
editor,
|
||||||
|
editorDOM: element,
|
||||||
manager,
|
manager,
|
||||||
translate: (text: string): string => text,
|
translate: (text: string): string => text,
|
||||||
lastSelection: null,
|
lastSelection: null,
|
||||||
|
@ -24,9 +17,7 @@ export function buildEditorUI(element: HTMLElement, editor: LexicalEditor) {
|
||||||
manager.setContext(context);
|
manager.setContext(context);
|
||||||
|
|
||||||
// Create primary toolbar
|
// Create primary toolbar
|
||||||
const toolbar = getMainEditorFullToolbar();
|
manager.setToolbar(getMainEditorFullToolbar());
|
||||||
toolbar.setContext(context);
|
|
||||||
element.before(toolbar.getDOMElement());
|
|
||||||
|
|
||||||
// Register modals
|
// Register modals
|
||||||
manager.registerModal('link', {
|
manager.registerModal('link', {
|
||||||
|
@ -42,29 +33,6 @@ export function buildEditorUI(element: HTMLElement, editor: LexicalEditor) {
|
||||||
form: sourceFormDefinition,
|
form: sourceFormDefinition,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Register decorator listener
|
// Register image decorator listener
|
||||||
// Maybe move to manager?
|
|
||||||
manager.registerDecoratorType('image', ImageDecorator);
|
manager.registerDecoratorType('image', ImageDecorator);
|
||||||
const domDecorateListener: DecoratorListener<EditorDecoratorAdapter> = (decorators: Record<NodeKey, EditorDecoratorAdapter>) => {
|
|
||||||
const keys = Object.keys(decorators);
|
|
||||||
for (const key of keys) {
|
|
||||||
const decoratedEl = editor.getElementByKey(key);
|
|
||||||
const adapter = decorators[key];
|
|
||||||
const decorator = manager.getDecorator(adapter.type, key);
|
|
||||||
decorator.setNode(adapter.getNode());
|
|
||||||
const decoratorEl = decorator.render(context);
|
|
||||||
if (decoratedEl) {
|
|
||||||
decoratedEl.append(decoratorEl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
editor.registerDecoratorListener(domDecorateListener);
|
|
||||||
|
|
||||||
// Update button states on editor selection change
|
|
||||||
editor.registerCommand(SELECTION_CHANGE_COMMAND, () => {
|
|
||||||
const selection = $getSelection();
|
|
||||||
toolbar.updateState({editor, selection});
|
|
||||||
context.lastSelection = selection;
|
|
||||||
return false;
|
|
||||||
}, COMMAND_PRIORITY_LOW);
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user