mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-10-01 01:36:00 -04:00
Lexical: Further fixes
- Improved node resizer positioning to be more accurate - Fixed drop handling not running within editor margin space - Made media dom update smarter to reduce reloads - Fixed media alignment, broken due to added wrapper
This commit is contained in:
parent
16518a4f89
commit
fd07aa0f05
@ -13,7 +13,7 @@ import {registerTaskListHandler} from "./ui/framework/helpers/task-list-handler"
|
|||||||
import {registerTableSelectionHandler} from "./ui/framework/helpers/table-selection-handler";
|
import {registerTableSelectionHandler} from "./ui/framework/helpers/table-selection-handler";
|
||||||
import {el} from "./utils/dom";
|
import {el} from "./utils/dom";
|
||||||
import {registerShortcuts} from "./services/shortcuts";
|
import {registerShortcuts} from "./services/shortcuts";
|
||||||
import {registerNodeResizer} from "./ui/framework/helpers/image-resizer";
|
import {registerNodeResizer} from "./ui/framework/helpers/node-resizer";
|
||||||
|
|
||||||
export function createPageEditorInstance(container: HTMLElement, htmlContent: string, options: Record<string, any> = {}): SimpleWysiwygEditorInterface {
|
export function createPageEditorInstance(container: HTMLElement, htmlContent: string, options: Record<string, any> = {}): SimpleWysiwygEditorInterface {
|
||||||
const config: CreateEditorArgs = {
|
const config: CreateEditorArgs = {
|
||||||
|
@ -4,18 +4,17 @@ import {
|
|||||||
ElementNode,
|
ElementNode,
|
||||||
LexicalEditor,
|
LexicalEditor,
|
||||||
LexicalNode,
|
LexicalNode,
|
||||||
SerializedElementNode, Spread
|
Spread
|
||||||
} from 'lexical';
|
} from 'lexical';
|
||||||
import type {EditorConfig} from "lexical/LexicalEditor";
|
import type {EditorConfig} from "lexical/LexicalEditor";
|
||||||
|
|
||||||
import {el, sizeToPixels} from "../utils/dom";
|
import {el, setOrRemoveAttribute, sizeToPixels} from "../utils/dom";
|
||||||
import {
|
import {
|
||||||
CommonBlockAlignment,
|
CommonBlockAlignment,
|
||||||
SerializedCommonBlockNode,
|
SerializedCommonBlockNode,
|
||||||
setCommonBlockPropsFromElement,
|
setCommonBlockPropsFromElement,
|
||||||
updateElementWithCommonBlockProps
|
updateElementWithCommonBlockProps
|
||||||
} from "./_common";
|
} from "./_common";
|
||||||
import {elem} from "../../services/dom";
|
|
||||||
import {$selectSingleNode} from "../utils/selection";
|
import {$selectSingleNode} from "../utils/selection";
|
||||||
|
|
||||||
export type MediaNodeTag = 'iframe' | 'embed' | 'object' | 'video' | 'audio';
|
export type MediaNodeTag = 'iframe' | 'embed' | 'object' | 'video' | 'audio';
|
||||||
@ -218,10 +217,39 @@ export class MediaNode extends ElementNode {
|
|||||||
return wrap;
|
return wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateDOM(prevNode: unknown, dom: HTMLElement) {
|
updateDOM(prevNode: MediaNode, dom: HTMLElement): boolean {
|
||||||
|
if (prevNode.__tag !== this.__tag) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (JSON.stringify(prevNode.__sources) !== JSON.stringify(this.__sources)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (JSON.stringify(prevNode.__attributes) !== JSON.stringify(this.__attributes)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const mediaEl = dom.firstElementChild as HTMLElement;
|
||||||
|
|
||||||
|
if (prevNode.__id !== this.__id) {
|
||||||
|
setOrRemoveAttribute(mediaEl, 'id', this.__id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prevNode.__alignment !== this.__alignment) {
|
||||||
|
if (prevNode.__alignment) {
|
||||||
|
dom.classList.remove(`align-${prevNode.__alignment}`);
|
||||||
|
mediaEl.classList.remove(`align-${prevNode.__alignment}`);
|
||||||
|
}
|
||||||
|
if (this.__alignment) {
|
||||||
|
dom.classList.add(`align-${this.__alignment}`);
|
||||||
|
mediaEl.classList.add(`align-${this.__alignment}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static importDOM(): DOMConversionMap|null {
|
static importDOM(): DOMConversionMap|null {
|
||||||
|
|
||||||
const buildConverter = (tag: MediaNodeTag) => {
|
const buildConverter = (tag: MediaNodeTag) => {
|
||||||
|
@ -103,6 +103,7 @@ function createDropListener(context: EditorUiContext): (event: DragEvent) => boo
|
|||||||
if (templateId) {
|
if (templateId) {
|
||||||
insertTemplateToEditor(editor, templateId, event);
|
insertTemplateToEditor(editor, templateId, event);
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,6 +115,7 @@ function createDropListener(context: EditorUiContext): (event: DragEvent) => boo
|
|||||||
$insertNodesAtEvent(newNodes, event, editor);
|
$insertNodesAtEvent(newNodes, event, editor);
|
||||||
});
|
});
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,6 +123,7 @@ function createDropListener(context: EditorUiContext): (event: DragEvent) => boo
|
|||||||
const handled = handleMediaInsert(event.dataTransfer, context);
|
const handled = handleMediaInsert(event.dataTransfer, context);
|
||||||
if (handled) {
|
if (handled) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -150,9 +153,11 @@ export function registerDropPasteHandling(context: EditorUiContext): () => void
|
|||||||
|
|
||||||
const unregisterDrop = context.editor.registerCommand(DROP_COMMAND, dropListener, COMMAND_PRIORITY_HIGH);
|
const unregisterDrop = context.editor.registerCommand(DROP_COMMAND, dropListener, COMMAND_PRIORITY_HIGH);
|
||||||
const unregisterPaste = context.editor.registerCommand(PASTE_COMMAND, pasteListener, COMMAND_PRIORITY_HIGH);
|
const unregisterPaste = context.editor.registerCommand(PASTE_COMMAND, pasteListener, COMMAND_PRIORITY_HIGH);
|
||||||
|
context.scrollDOM.addEventListener('drop', dropListener);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
unregisterDrop();
|
unregisterDrop();
|
||||||
unregisterPaste();
|
unregisterPaste();
|
||||||
|
context.scrollDOM.removeEventListener('drop', dropListener);
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -16,4 +16,4 @@
|
|||||||
|
|
||||||
## Bugs
|
## Bugs
|
||||||
|
|
||||||
- Template drag/drop not handled when outside core editor area (ignored in margin area).
|
//
|
@ -73,11 +73,15 @@ class NodeResizer {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const nodeDOMBounds = nodeDOM.getBoundingClientRect();
|
const scrollAreaRect = this.scrollContainer.getBoundingClientRect();
|
||||||
this.dom.style.left = nodeDOM.offsetLeft + 'px';
|
const nodeRect = nodeDOM.getBoundingClientRect();
|
||||||
this.dom.style.top = nodeDOM.offsetTop + 'px';
|
const top = nodeRect.top - (scrollAreaRect.top - this.scrollContainer.scrollTop);
|
||||||
this.dom.style.width = nodeDOMBounds.width + 'px';
|
const left = nodeRect.left - scrollAreaRect.left;
|
||||||
this.dom.style.height = nodeDOMBounds.height + 'px';
|
|
||||||
|
this.dom.style.top = `${top}px`;
|
||||||
|
this.dom.style.left = `${left}px`;
|
||||||
|
this.dom.style.width = nodeRect.width + 'px';
|
||||||
|
this.dom.style.height = nodeRect.height + 'px';
|
||||||
}
|
}
|
||||||
|
|
||||||
protected updateDOMSize(width: number, height: number): void {
|
protected updateDOMSize(width: number, height: number): void {
|
@ -71,3 +71,11 @@ export function extractStyleMapFromElement(element: HTMLElement): StyleMap {
|
|||||||
|
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function setOrRemoveAttribute(element: HTMLElement, name: string, value: string|null|undefined) {
|
||||||
|
if (value) {
|
||||||
|
element.setAttribute(name, value);
|
||||||
|
} else {
|
||||||
|
element.removeAttribute(name);
|
||||||
|
}
|
||||||
|
}
|
@ -374,10 +374,21 @@ body.editor-is-fullscreen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.editor-media-wrap {
|
.editor-media-wrap {
|
||||||
|
display: inline-block;
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
iframe {
|
iframe {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
&.align-left {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
&.align-right {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
&.align-center {
|
||||||
|
display: block;
|
||||||
|
margin-inline: auto;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user