mirror of
https://github.com/BookStackApp/BookStack.git
synced 2025-06-22 21:51:50 +08:00
Lexical: Fixed strange paragraph formatting behaviour
Some checks failed
test-js / build (push) Has been cancelled
Some checks failed
test-js / build (push) Has been cancelled
Formatting was not persisted on empty paragraphs, and was instead based upon last format encountered in selection. This was due to overly-hasty removal of other formatting code, which this got caught it. Restored required parts from prior codebase. Also updated inline format button active indicator to reflect formats using the above, so correct buttons are shown as active even when just in an empty paragraph.
This commit is contained in:
@ -84,7 +84,7 @@ export function createPageEditorInstance(container: HTMLElement, htmlContent: st
|
|||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
window.debugEditorState = () => {
|
window.debugEditorState = () => {
|
||||||
console.log(editor.getEditorState().toJSON());
|
return editor.getEditorState().toJSON();
|
||||||
};
|
};
|
||||||
|
|
||||||
registerCommonNodeMutationListeners(context);
|
registerCommonNodeMutationListeners(context);
|
||||||
|
@ -355,6 +355,7 @@ function onSelectionChange(
|
|||||||
lastNode instanceof ParagraphNode &&
|
lastNode instanceof ParagraphNode &&
|
||||||
lastNode.getChildrenSize() === 0
|
lastNode.getChildrenSize() === 0
|
||||||
) {
|
) {
|
||||||
|
selection.format = lastNode.getTextFormat();
|
||||||
selection.style = lastNode.getTextStyle();
|
selection.style = lastNode.getTextStyle();
|
||||||
} else {
|
} else {
|
||||||
selection.format = 0;
|
selection.format = 0;
|
||||||
|
@ -19,7 +19,7 @@ import type {
|
|||||||
LexicalNode,
|
LexicalNode,
|
||||||
NodeKey,
|
NodeKey,
|
||||||
} from '../LexicalNode';
|
} from '../LexicalNode';
|
||||||
import type {RangeSelection} from 'lexical';
|
import {RangeSelection, TEXT_TYPE_TO_FORMAT, TextFormatType} from 'lexical';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
$applyNodeReplacement,
|
$applyNodeReplacement,
|
||||||
@ -36,6 +36,7 @@ import {CommonBlockNode, copyCommonBlockProperties, SerializedCommonBlockNode} f
|
|||||||
|
|
||||||
export type SerializedParagraphNode = Spread<
|
export type SerializedParagraphNode = Spread<
|
||||||
{
|
{
|
||||||
|
textFormat: number;
|
||||||
textStyle: string;
|
textStyle: string;
|
||||||
},
|
},
|
||||||
SerializedCommonBlockNode
|
SerializedCommonBlockNode
|
||||||
@ -45,10 +46,12 @@ export type SerializedParagraphNode = Spread<
|
|||||||
export class ParagraphNode extends CommonBlockNode {
|
export class ParagraphNode extends CommonBlockNode {
|
||||||
['constructor']!: KlassConstructor<typeof ParagraphNode>;
|
['constructor']!: KlassConstructor<typeof ParagraphNode>;
|
||||||
/** @internal */
|
/** @internal */
|
||||||
|
__textFormat: number;
|
||||||
__textStyle: string;
|
__textStyle: string;
|
||||||
|
|
||||||
constructor(key?: NodeKey) {
|
constructor(key?: NodeKey) {
|
||||||
super(key);
|
super(key);
|
||||||
|
this.__textFormat = 0;
|
||||||
this.__textStyle = '';
|
this.__textStyle = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,6 +59,22 @@ export class ParagraphNode extends CommonBlockNode {
|
|||||||
return 'paragraph';
|
return 'paragraph';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getTextFormat(): number {
|
||||||
|
const self = this.getLatest();
|
||||||
|
return self.__textFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
setTextFormat(type: number): this {
|
||||||
|
const self = this.getWritable();
|
||||||
|
self.__textFormat = type;
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasTextFormat(type: TextFormatType): boolean {
|
||||||
|
const formatFlag = TEXT_TYPE_TO_FORMAT[type];
|
||||||
|
return (this.getTextFormat() & formatFlag) !== 0;
|
||||||
|
}
|
||||||
|
|
||||||
getTextStyle(): string {
|
getTextStyle(): string {
|
||||||
const self = this.getLatest();
|
const self = this.getLatest();
|
||||||
return self.__textStyle;
|
return self.__textStyle;
|
||||||
@ -73,6 +92,7 @@ export class ParagraphNode extends CommonBlockNode {
|
|||||||
|
|
||||||
afterCloneFrom(prevNode: this) {
|
afterCloneFrom(prevNode: this) {
|
||||||
super.afterCloneFrom(prevNode);
|
super.afterCloneFrom(prevNode);
|
||||||
|
this.__textFormat = prevNode.__textFormat;
|
||||||
this.__textStyle = prevNode.__textStyle;
|
this.__textStyle = prevNode.__textStyle;
|
||||||
copyCommonBlockProperties(prevNode, this);
|
copyCommonBlockProperties(prevNode, this);
|
||||||
}
|
}
|
||||||
@ -125,12 +145,14 @@ export class ParagraphNode extends CommonBlockNode {
|
|||||||
static importJSON(serializedNode: SerializedParagraphNode): ParagraphNode {
|
static importJSON(serializedNode: SerializedParagraphNode): ParagraphNode {
|
||||||
const node = $createParagraphNode();
|
const node = $createParagraphNode();
|
||||||
deserializeCommonBlockNode(serializedNode, node);
|
deserializeCommonBlockNode(serializedNode, node);
|
||||||
|
node.setTextFormat(serializedNode.textFormat);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
exportJSON(): SerializedParagraphNode {
|
exportJSON(): SerializedParagraphNode {
|
||||||
return {
|
return {
|
||||||
...super.exportJSON(),
|
...super.exportJSON(),
|
||||||
|
textFormat: this.getTextFormat(),
|
||||||
textStyle: this.getTextStyle(),
|
textStyle: this.getTextStyle(),
|
||||||
type: 'paragraph',
|
type: 'paragraph',
|
||||||
version: 1,
|
version: 1,
|
||||||
@ -144,6 +166,7 @@ export class ParagraphNode extends CommonBlockNode {
|
|||||||
restoreSelection: boolean,
|
restoreSelection: boolean,
|
||||||
): ParagraphNode {
|
): ParagraphNode {
|
||||||
const newElement = $createParagraphNode();
|
const newElement = $createParagraphNode();
|
||||||
|
newElement.setTextFormat(rangeSelection.format);
|
||||||
newElement.setTextStyle(rangeSelection.style);
|
newElement.setTextStyle(rangeSelection.style);
|
||||||
const direction = this.getDirection();
|
const direction = this.getDirection();
|
||||||
newElement.setDirection(direction);
|
newElement.setDirection(direction);
|
||||||
|
@ -3,7 +3,7 @@ import {
|
|||||||
$createParagraphNode, $createRangeSelection,
|
$createParagraphNode, $createRangeSelection,
|
||||||
$getRoot,
|
$getRoot,
|
||||||
$getSelection, $isBlockElementNode, $isDecoratorNode,
|
$getSelection, $isBlockElementNode, $isDecoratorNode,
|
||||||
$isElementNode,
|
$isElementNode, $isParagraphNode,
|
||||||
$isTextNode,
|
$isTextNode,
|
||||||
$setSelection,
|
$setSelection,
|
||||||
BaseSelection, DecoratorNode,
|
BaseSelection, DecoratorNode,
|
||||||
@ -60,12 +60,19 @@ export function $selectionContainsTextFormat(selection: BaseSelection | null, fo
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const node of selection.getNodes()) {
|
// Check text nodes
|
||||||
|
const nodes = selection.getNodes();
|
||||||
|
for (const node of nodes) {
|
||||||
if ($isTextNode(node) && node.hasFormat(format)) {
|
if ($isTextNode(node) && node.hasFormat(format)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we're in an empty paragraph, check the paragraph format
|
||||||
|
if (nodes.length === 1 && $isParagraphNode(nodes[0]) && nodes[0].hasTextFormat(format)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user