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,8 +217,37 @@ export class MediaNode extends ElementNode { | ||||||
|         return wrap; |         return wrap; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     updateDOM(prevNode: unknown, dom: HTMLElement) { |     updateDOM(prevNode: MediaNode, dom: HTMLElement): boolean { | ||||||
|         return true; |         if (prevNode.__tag !== this.__tag) { | ||||||
|  |             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 { | ||||||
|  |  | ||||||
|  | @ -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 { | ||||||
|  | @ -70,4 +70,12 @@ 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