mirror of
https://github.com/BookStackApp/BookStack.git
synced 2025-12-14 19:42:14 +03:00
Lexical: Started dev API outline
This commit is contained in:
8
dev/docs/wysiwyg-js-api.md
Normal file
8
dev/docs/wysiwyg-js-api.md
Normal file
@@ -0,0 +1,8 @@
|
||||
# WYSIWYG JavaScript API
|
||||
|
||||
TODO - Link to this from JS code doc.
|
||||
TODO - Create JS events and add to the js public events doc.
|
||||
|
||||
TODO - Document the JS API.
|
||||
|
||||
TODO - Add testing coverage
|
||||
11
resources/js/wysiwyg/api/api.ts
Normal file
11
resources/js/wysiwyg/api/api.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import {EditorApiUiModule} from "./ui";
|
||||
import {EditorUiContext} from "../ui/framework/core";
|
||||
|
||||
export class EditorApi {
|
||||
|
||||
public ui: EditorApiUiModule;
|
||||
|
||||
constructor(context: EditorUiContext) {
|
||||
this.ui = new EditorApiUiModule(context);
|
||||
}
|
||||
}
|
||||
79
resources/js/wysiwyg/api/ui.ts
Normal file
79
resources/js/wysiwyg/api/ui.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import {EditorButton} from "../ui/framework/buttons";
|
||||
import {EditorUiContext} from "../ui/framework/core";
|
||||
import {EditorOverflowContainer} from "../ui/framework/blocks/overflow-container";
|
||||
|
||||
type EditorApiButtonOptions = {
|
||||
label?: string;
|
||||
icon?: string;
|
||||
onClick: () => void;
|
||||
};
|
||||
|
||||
class EditorApiButton {
|
||||
#button: EditorButton;
|
||||
#isActive: boolean = false;
|
||||
|
||||
constructor(options: EditorApiButtonOptions, context: EditorUiContext) {
|
||||
this.#button = new EditorButton({
|
||||
label: options.label || '',
|
||||
icon: options.icon || '',
|
||||
action: () => {
|
||||
options.onClick();
|
||||
},
|
||||
isActive: () => this.#isActive,
|
||||
});
|
||||
this.#button.setContext(context);
|
||||
}
|
||||
|
||||
setActive(active: boolean = true): void {
|
||||
this.#isActive = active;
|
||||
this.#button.setActiveState(active);
|
||||
}
|
||||
|
||||
_getOriginalModel() {
|
||||
return this.#button;
|
||||
}
|
||||
}
|
||||
|
||||
class EditorApiToolbarSection {
|
||||
#section: EditorOverflowContainer;
|
||||
label: string;
|
||||
|
||||
constructor(section: EditorOverflowContainer) {
|
||||
this.#section = section;
|
||||
this.label = section.getLabel();
|
||||
}
|
||||
|
||||
getLabel(): string {
|
||||
return this.#section.getLabel();
|
||||
}
|
||||
|
||||
addButton(button: EditorApiButton, targetIndex: number = -1): void {
|
||||
this.#section.addChild(button._getOriginalModel(), targetIndex);
|
||||
this.#section.rebuildDOM();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class EditorApiUiModule {
|
||||
#context: EditorUiContext;
|
||||
|
||||
constructor(context: EditorUiContext) {
|
||||
this.#context = context;
|
||||
}
|
||||
|
||||
createButton(options: EditorApiButtonOptions): EditorApiButton {
|
||||
return new EditorApiButton(options, this.#context);
|
||||
}
|
||||
|
||||
getToolbarSections(): EditorApiToolbarSection[] {
|
||||
const toolbar = this.#context.manager.getToolbar();
|
||||
if (!toolbar) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const sections = toolbar.getChildren();
|
||||
return sections.filter(section => {
|
||||
return section instanceof EditorOverflowContainer;
|
||||
}).map(section => new EditorApiToolbarSection(section));
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ import {CodeBlockDecorator} from "./ui/decorators/code-block";
|
||||
import {DiagramDecorator} from "./ui/decorators/diagram";
|
||||
import {registerMouseHandling} from "./services/mouse-handling";
|
||||
import {registerSelectionHandling} from "./services/selection-handling";
|
||||
import {EditorApi} from "./api/api";
|
||||
|
||||
const theme = {
|
||||
text: {
|
||||
@@ -94,6 +95,12 @@ export function createPageEditorInstance(container: HTMLElement, htmlContent: st
|
||||
|
||||
registerCommonNodeMutationListeners(context);
|
||||
|
||||
// TODO - Emit this as a public event instead
|
||||
// TODO - Add support to basic editor below
|
||||
const api = new EditorApi(context);
|
||||
// @ts-ignore
|
||||
window.editorApi = api;
|
||||
|
||||
return new SimpleWysiwygEditorInterface(context);
|
||||
}
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ export function getMainEditorFullToolbar(context: EditorUiContext): EditorContai
|
||||
return new EditorSimpleClassContainer('editor-toolbar-main', [
|
||||
|
||||
// History state
|
||||
new EditorOverflowContainer(2, [
|
||||
new EditorOverflowContainer('history', 2, [
|
||||
new EditorButton(undo),
|
||||
new EditorButton(redo),
|
||||
]),
|
||||
@@ -110,7 +110,7 @@ export function getMainEditorFullToolbar(context: EditorUiContext): EditorContai
|
||||
]),
|
||||
|
||||
// Inline formats
|
||||
new EditorOverflowContainer(6, [
|
||||
new EditorOverflowContainer('inline_formats', 6, [
|
||||
new EditorButton(bold),
|
||||
new EditorButton(italic),
|
||||
new EditorButton(underline),
|
||||
@@ -128,7 +128,7 @@ export function getMainEditorFullToolbar(context: EditorUiContext): EditorContai
|
||||
]),
|
||||
|
||||
// Alignment
|
||||
new EditorOverflowContainer(6, [
|
||||
new EditorOverflowContainer('alignment', 6, [
|
||||
new EditorButton(alignLeft),
|
||||
new EditorButton(alignCenter),
|
||||
new EditorButton(alignRight),
|
||||
@@ -138,7 +138,7 @@ export function getMainEditorFullToolbar(context: EditorUiContext): EditorContai
|
||||
].filter(x => x !== null)),
|
||||
|
||||
// Lists
|
||||
new EditorOverflowContainer(3, [
|
||||
new EditorOverflowContainer('lists', 3, [
|
||||
new EditorButton(bulletList),
|
||||
new EditorButton(numberList),
|
||||
new EditorButton(taskList),
|
||||
@@ -147,7 +147,7 @@ export function getMainEditorFullToolbar(context: EditorUiContext): EditorContai
|
||||
]),
|
||||
|
||||
// Insert types
|
||||
new EditorOverflowContainer(4, [
|
||||
new EditorOverflowContainer('inserts', 4, [
|
||||
new EditorButton(link),
|
||||
|
||||
new EditorDropdownButton({button: table, direction: 'vertical', showAside: false}, [
|
||||
@@ -200,7 +200,7 @@ export function getMainEditorFullToolbar(context: EditorUiContext): EditorContai
|
||||
]),
|
||||
|
||||
// Meta elements
|
||||
new EditorOverflowContainer(3, [
|
||||
new EditorOverflowContainer('meta', 3, [
|
||||
new EditorButton(source),
|
||||
new EditorButton(about),
|
||||
new EditorButton(fullscreen),
|
||||
@@ -261,16 +261,16 @@ export const contextToolbars: Record<string, EditorContextToolbarDefinition> = {
|
||||
selector: 'td,th',
|
||||
content() {
|
||||
return [
|
||||
new EditorOverflowContainer(2, [
|
||||
new EditorOverflowContainer('table', 2, [
|
||||
new EditorButton(tableProperties),
|
||||
new EditorButton(deleteTable),
|
||||
]),
|
||||
new EditorOverflowContainer(3, [
|
||||
new EditorOverflowContainer('table_row',3, [
|
||||
new EditorButton(insertRowAbove),
|
||||
new EditorButton(insertRowBelow),
|
||||
new EditorButton(deleteRow),
|
||||
]),
|
||||
new EditorOverflowContainer(3, [
|
||||
new EditorOverflowContainer('table_column', 3, [
|
||||
new EditorButton(insertColumnBefore),
|
||||
new EditorButton(insertColumnAfter),
|
||||
new EditorButton(deleteColumn),
|
||||
|
||||
@@ -9,9 +9,11 @@ export class EditorOverflowContainer extends EditorContainerUiElement {
|
||||
protected size: number;
|
||||
protected overflowButton: EditorDropdownButton;
|
||||
protected content: EditorUiElement[];
|
||||
protected label: string;
|
||||
|
||||
constructor(size: number, children: EditorUiElement[]) {
|
||||
constructor(label: string, size: number, children: EditorUiElement[]) {
|
||||
super(children);
|
||||
this.label = label;
|
||||
this.size = size;
|
||||
this.content = children;
|
||||
this.overflowButton = new EditorDropdownButton({
|
||||
@@ -24,6 +26,11 @@ export class EditorOverflowContainer extends EditorContainerUiElement {
|
||||
this.addChildren(this.overflowButton);
|
||||
}
|
||||
|
||||
addChild(child: EditorUiElement, targetIndex: number = -1): void {
|
||||
this.content.splice(targetIndex, 0, child);
|
||||
this.addChildren(child);
|
||||
}
|
||||
|
||||
protected buildDOM(): HTMLElement {
|
||||
const slicePosition = this.content.length > this.size ? this.size - 1 : this.size;
|
||||
const visibleChildren = this.content.slice(0, slicePosition);
|
||||
@@ -41,5 +48,8 @@ export class EditorOverflowContainer extends EditorContainerUiElement {
|
||||
}, visibleElements);
|
||||
}
|
||||
|
||||
getLabel(): string {
|
||||
return this.label;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -109,6 +109,10 @@ export class EditorUIManager {
|
||||
this.getContext().containerDOM.prepend(toolbar.getDOMElement());
|
||||
}
|
||||
|
||||
getToolbar(): EditorContainerUiElement|null {
|
||||
return this.toolbar;
|
||||
}
|
||||
|
||||
registerContextToolbar(key: string, definition: EditorContextToolbarDefinition) {
|
||||
this.contextToolbarDefinitionsByKey[key] = definition;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user