]> BookStack Code Mirror - bookstack/blob - resources/js/wysiwyg/ui/framework/buttons.ts
2a6f5a976fd21532bab01b5341fecd9f8615ea78
[bookstack] / resources / js / wysiwyg / ui / framework / buttons.ts
1 import {BaseSelection, LexicalEditor} from "lexical";
2 import {EditorUiElement, EditorUiStateUpdate} from "./base-elements";
3 import {el} from "../../helpers";
4
5 export interface EditorButtonDefinition {
6     label: string;
7     action: (editor: LexicalEditor) => void;
8     isActive: (selection: BaseSelection|null) => boolean;
9 }
10
11 export class EditorButton extends EditorUiElement {
12     protected definition: EditorButtonDefinition;
13
14     constructor(definition: EditorButtonDefinition) {
15         super();
16         this.definition = definition;
17     }
18
19     protected buildDOM(): HTMLButtonElement {
20         const button = el('button', {
21             type: 'button',
22             class: 'editor-button',
23         }, [this.definition.label]) as HTMLButtonElement;
24
25         button.addEventListener('click', this.onClick.bind(this));
26
27         return button;
28     }
29
30     protected onClick() {
31         this.definition.action(this.getContext().editor);
32     }
33
34     updateActiveState(selection: BaseSelection|null) {
35         const isActive = this.definition.isActive(selection);
36         this.dom?.classList.toggle('editor-button-active', isActive);
37     }
38
39     updateState(state: EditorUiStateUpdate): void {
40         this.updateActiveState(state.selection);
41     }
42 }
43
44 export class FormatPreviewButton extends EditorButton {
45     protected previewSampleElement: HTMLElement;
46
47     constructor(previewSampleElement: HTMLElement,definition: EditorButtonDefinition) {
48         super(definition);
49         this.previewSampleElement = previewSampleElement;
50     }
51
52     protected buildDOM(): HTMLButtonElement {
53         const button = super.buildDOM();
54         button.innerHTML = '';
55
56         const preview = el('span', {
57             class: 'editor-button-format-preview'
58         }, [this.definition.label]);
59
60         const stylesToApply = this.getStylesFromPreview();
61         console.log(stylesToApply);
62         for (const style of Object.keys(stylesToApply)) {
63             preview.style.setProperty(style, stylesToApply[style]);
64         }
65
66         button.append(preview);
67         return button;
68     }
69
70     protected getStylesFromPreview(): Record<string, string> {
71         const wrap = el('div', {style: 'display: none', hidden: 'true', class: 'page-content'});
72         const sampleClone = this.previewSampleElement.cloneNode() as HTMLElement;
73         sampleClone.textContent = this.definition.label;
74         wrap.append(sampleClone);
75         document.body.append(wrap);
76
77         const propertiesToFetch = ['color', 'font-size', 'background-color', 'border-inline-start'];
78         const propertiesToReturn: Record<string, string> = {};
79
80         const computed = window.getComputedStyle(sampleClone);
81         for (const property of propertiesToFetch) {
82             propertiesToReturn[property] = computed.getPropertyValue(property);
83         }
84         wrap.remove();
85
86         return propertiesToReturn;
87     }
88 }