]> BookStack Code Mirror - bookstack/blob - resources/js/wysiwyg/ui/defaults/buttons/alignments.ts
Opensearch: Fixed XML declaration when php short tags enabled
[bookstack] / resources / js / wysiwyg / ui / defaults / buttons / alignments.ts
1 import {$isElementNode, BaseSelection} from "lexical";
2 import {EditorButtonDefinition} from "../../framework/buttons";
3 import alignLeftIcon from "@icons/editor/align-left.svg";
4 import {EditorUiContext} from "../../framework/core";
5 import alignCenterIcon from "@icons/editor/align-center.svg";
6 import alignRightIcon from "@icons/editor/align-right.svg";
7 import alignJustifyIcon from "@icons/editor/align-justify.svg";
8 import ltrIcon from "@icons/editor/direction-ltr.svg";
9 import rtlIcon from "@icons/editor/direction-rtl.svg";
10 import {
11     $getBlockElementNodesInSelection,
12     $selectionContainsAlignment, $selectionContainsDirection, $selectSingleNode, getLastSelection
13 } from "../../../utils/selection";
14 import {CommonBlockAlignment} from "lexical/nodes/common";
15 import {nodeHasAlignment} from "../../../utils/nodes";
16
17
18 function setAlignmentForSelection(context: EditorUiContext, alignment: CommonBlockAlignment): void {
19     const selection = getLastSelection(context.editor);
20     const selectionNodes = selection?.getNodes() || [];
21
22     // Handle inline node selection alignment
23     if (selectionNodes.length === 1 && $isElementNode(selectionNodes[0]) && selectionNodes[0].isInline() && nodeHasAlignment(selectionNodes[0])) {
24         selectionNodes[0].setAlignment(alignment);
25         $selectSingleNode(selectionNodes[0]);
26         context.manager.triggerFutureStateRefresh();
27         return;
28     }
29
30     // Handle normal block/range alignment
31     const elements = $getBlockElementNodesInSelection(selection);
32     const alignmentNodes = elements.filter(n => nodeHasAlignment(n));
33     const allAlreadyAligned = alignmentNodes.every(n => n.getAlignment() === alignment);
34     const newAlignment = allAlreadyAligned ? '' : alignment;
35     for (const node of alignmentNodes) {
36         node.setAlignment(newAlignment);
37     }
38
39     context.manager.triggerFutureStateRefresh();
40 }
41
42 function setDirectionForSelection(context: EditorUiContext, direction: 'ltr' | 'rtl'): void {
43     const selection = getLastSelection(context.editor);
44
45     const elements = $getBlockElementNodesInSelection(selection);
46     for (const node of elements) {
47         node.setDirection(direction);
48     }
49
50     context.manager.triggerFutureStateRefresh();
51 }
52
53 export const alignLeft: EditorButtonDefinition = {
54     label: 'Align left',
55     icon: alignLeftIcon,
56     action(context: EditorUiContext) {
57         context.editor.update(() => setAlignmentForSelection(context, 'left'));
58     },
59     isActive(selection: BaseSelection|null) {
60         return $selectionContainsAlignment(selection, 'left');
61     }
62 };
63
64 export const alignCenter: EditorButtonDefinition = {
65     label: 'Align center',
66     icon: alignCenterIcon,
67     action(context: EditorUiContext) {
68         context.editor.update(() => setAlignmentForSelection(context, 'center'));
69     },
70     isActive(selection: BaseSelection|null) {
71         return $selectionContainsAlignment(selection, 'center');
72     }
73 };
74
75 export const alignRight: EditorButtonDefinition = {
76     label: 'Align right',
77     icon: alignRightIcon,
78     action(context: EditorUiContext) {
79         context.editor.update(() => setAlignmentForSelection(context, 'right'));
80     },
81     isActive(selection: BaseSelection|null) {
82         return $selectionContainsAlignment(selection, 'right');
83     }
84 };
85
86 export const alignJustify: EditorButtonDefinition = {
87     label: 'Justify',
88     icon: alignJustifyIcon,
89     action(context: EditorUiContext) {
90         context.editor.update(() => setAlignmentForSelection(context, 'justify'));
91     },
92     isActive(selection: BaseSelection|null) {
93         return $selectionContainsAlignment(selection, 'justify');
94     }
95 };
96
97 export const directionLTR: EditorButtonDefinition = {
98     label: 'Left to right',
99     icon: ltrIcon,
100     action(context: EditorUiContext) {
101         context.editor.update(() => setDirectionForSelection(context, 'ltr'));
102     },
103     isActive(selection: BaseSelection|null) {
104         return $selectionContainsDirection(selection, 'ltr');
105     }
106 };
107
108 export const directionRTL: EditorButtonDefinition = {
109     label: 'Right to left',
110     icon: rtlIcon,
111     action(context: EditorUiContext) {
112         context.editor.update(() => setDirectionForSelection(context, 'rtl'));
113     },
114     isActive(selection: BaseSelection|null) {
115         return $selectionContainsDirection(selection, 'rtl');
116     }
117 };