mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-10-01 01:36:00 -04:00
Lexical: Split helpers to utils, refactored files
This commit is contained in:
parent
e94ad78ea7
commit
efec752985
@ -4,14 +4,14 @@ import {registerRichText} from '@lexical/rich-text';
|
||||
import {mergeRegister} from '@lexical/utils';
|
||||
import {getNodesForPageEditor, registerCommonNodeMutationListeners} from './nodes';
|
||||
import {buildEditorUI} from "./ui";
|
||||
import {getEditorContentAsHtml, setEditorContentFromHtml} from "./actions";
|
||||
import {getEditorContentAsHtml, setEditorContentFromHtml} from "./utils/actions";
|
||||
import {registerTableResizer} from "./ui/framework/helpers/table-resizer";
|
||||
import {el} from "./helpers";
|
||||
import {EditorUiContext} from "./ui/framework/core";
|
||||
import {listen as listenToCommonEvents} from "./common-events";
|
||||
import {handleDropEvents} from "./drop-handling";
|
||||
import {listen as listenToCommonEvents} from "./services/common-events";
|
||||
import {handleDropEvents} from "./services/drop-handling";
|
||||
import {registerTaskListHandler} from "./ui/framework/helpers/task-list-handler";
|
||||
import {registerTableSelectionHandler} from "./ui/framework/helpers/table-selection-handler";
|
||||
import {el} from "./utils/dom";
|
||||
|
||||
export function createPageEditorInstance(container: HTMLElement, htmlContent: string, options: Record<string, any> = {}): SimpleWysiwygEditorInterface {
|
||||
const config: CreateEditorArgs = {
|
||||
|
@ -8,9 +8,9 @@ import {
|
||||
Spread
|
||||
} from "lexical";
|
||||
import type {EditorConfig} from "lexical/LexicalEditor";
|
||||
import {el} from "../helpers";
|
||||
import {EditorDecoratorAdapter} from "../ui/framework/decorator";
|
||||
import {CodeEditor} from "../../components";
|
||||
import {el} from "../utils/dom";
|
||||
|
||||
export type SerializedCodeBlockNode = Spread<{
|
||||
language: string;
|
||||
|
@ -1,7 +1,8 @@
|
||||
import {$isListNode, ListItemNode, SerializedListItemNode} from "@lexical/list";
|
||||
import {EditorConfig} from "lexical/LexicalEditor";
|
||||
import {DOMExportOutput, LexicalEditor, LexicalNode} from "lexical";
|
||||
import {el} from "../helpers";
|
||||
|
||||
import {el} from "../utils/dom";
|
||||
|
||||
function updateListItemChecked(
|
||||
dom: HTMLElement,
|
||||
|
@ -1,7 +1,8 @@
|
||||
import {SerializedTableNode, TableNode, TableRowNode} from "@lexical/table";
|
||||
import {DOMConversion, DOMConversionMap, DOMConversionOutput, LexicalEditor, LexicalNode, Spread} from "lexical";
|
||||
import {EditorConfig} from "lexical/LexicalEditor";
|
||||
import {el} from "../helpers";
|
||||
|
||||
import {el} from "../utils/dom";
|
||||
|
||||
export type SerializedCustomTableNode = Spread<{
|
||||
id: string;
|
||||
|
@ -7,7 +7,8 @@ import {
|
||||
SerializedElementNode,
|
||||
} from 'lexical';
|
||||
import type {EditorConfig} from "lexical/LexicalEditor";
|
||||
import {el} from "../helpers";
|
||||
|
||||
import {el} from "../utils/dom";
|
||||
|
||||
export class DetailsNode extends ElementNode {
|
||||
|
||||
|
@ -8,11 +8,11 @@ import {
|
||||
Spread
|
||||
} from "lexical";
|
||||
import type {EditorConfig} from "lexical/LexicalEditor";
|
||||
import {el} from "../helpers";
|
||||
import {EditorDecoratorAdapter} from "../ui/framework/decorator";
|
||||
import * as DrawIO from '../../services/drawio';
|
||||
import {EditorUiContext} from "../ui/framework/core";
|
||||
import {HttpError} from "../../services/http";
|
||||
import {el} from "../utils/dom";
|
||||
|
||||
export type SerializedDiagramNode = Spread<{
|
||||
id: string;
|
||||
|
@ -8,8 +8,8 @@ import {
|
||||
Spread
|
||||
} from "lexical";
|
||||
import type {EditorConfig} from "lexical/LexicalEditor";
|
||||
import {el} from "../helpers";
|
||||
import {EditorDecoratorAdapter} from "../ui/framework/decorator";
|
||||
import {el} from "../utils/dom";
|
||||
|
||||
export interface ImageNodeOptions {
|
||||
alt?: string;
|
||||
|
@ -7,7 +7,8 @@ import {
|
||||
SerializedElementNode, Spread
|
||||
} from 'lexical';
|
||||
import type {EditorConfig} from "lexical/LexicalEditor";
|
||||
import {el} from "../helpers";
|
||||
|
||||
import {el} from "../utils/dom";
|
||||
|
||||
export type MediaNodeTag = 'iframe' | 'embed' | 'object' | 'video' | 'audio';
|
||||
export type MediaNodeSource = {
|
||||
|
@ -5,7 +5,7 @@ import {
|
||||
insertHtmlIntoEditor,
|
||||
prependHtmlToEditor,
|
||||
setEditorContentFromHtml
|
||||
} from "./actions";
|
||||
} from "../utils/actions";
|
||||
|
||||
type EditorEventContent = {
|
||||
html: string;
|
@ -3,12 +3,8 @@ import {
|
||||
LexicalEditor,
|
||||
LexicalNode
|
||||
} from "lexical";
|
||||
import {
|
||||
$getNearestBlockNodeForCoords,
|
||||
$htmlToBlockNodes,
|
||||
$insertNewBlockNodesAtSelection,
|
||||
$selectSingleNode
|
||||
} from "./helpers";
|
||||
import {$insertNewBlockNodesAtSelection, $selectSingleNode} from "../utils/selection";
|
||||
import {$getNearestBlockNodeForCoords, $htmlToBlockNodes} from "../utils/nodes";
|
||||
|
||||
function $getNodeFromMouseEvent(event: MouseEvent, editor: LexicalEditor): LexicalNode|null {
|
||||
const x = event.clientX;
|
@ -1,8 +1,8 @@
|
||||
import {EditorDecorator} from "../framework/decorator";
|
||||
import {EditorUiContext} from "../framework/core";
|
||||
import {$openCodeEditorForNode, CodeBlockNode} from "../../nodes/code-block";
|
||||
import {$selectionContainsNode, $selectSingleNode} from "../../helpers";
|
||||
import {BaseSelection} from "lexical";
|
||||
import {$selectionContainsNode, $selectSingleNode} from "../../utils/selection";
|
||||
|
||||
|
||||
export class CodeBlockDecorator extends EditorDecorator {
|
||||
|
@ -1,8 +1,8 @@
|
||||
import {EditorDecorator} from "../framework/decorator";
|
||||
import {EditorUiContext} from "../framework/core";
|
||||
import {$selectionContainsNode, $selectSingleNode} from "../../helpers";
|
||||
import {BaseSelection} from "lexical";
|
||||
import {$openDrawingEditorForNode, DiagramNode} from "../../nodes/diagram";
|
||||
import {$selectionContainsNode, $selectSingleNode} from "../../utils/selection";
|
||||
|
||||
|
||||
export class DiagramDecorator extends EditorDecorator {
|
||||
|
@ -1,9 +1,10 @@
|
||||
import {EditorDecorator} from "../framework/decorator";
|
||||
import {el, $selectSingleNode} from "../../helpers";
|
||||
import {$createNodeSelection, $setSelection} from "lexical";
|
||||
import {EditorUiContext} from "../framework/core";
|
||||
import {ImageNode} from "../../nodes/image";
|
||||
import {MouseDragTracker, MouseDragTrackerDistance} from "../framework/helpers/mouse-drag-tracker";
|
||||
import {$selectSingleNode} from "../../utils/selection";
|
||||
import {el} from "../../utils/dom";
|
||||
|
||||
|
||||
export class ImageDecorator extends EditorDecorator {
|
||||
|
@ -1,11 +1,11 @@
|
||||
import {$getSelection, BaseSelection, ElementFormatType} from "lexical";
|
||||
import {$getBlockElementNodesInSelection, $selectionContainsElementFormat} from "../../../helpers";
|
||||
import {EditorButtonDefinition} from "../../framework/buttons";
|
||||
import alignLeftIcon from "@icons/editor/align-left.svg";
|
||||
import {EditorUiContext} from "../../framework/core";
|
||||
import alignCenterIcon from "@icons/editor/align-center.svg";
|
||||
import alignRightIcon from "@icons/editor/align-right.svg";
|
||||
import alignJustifyIcon from "@icons/editor/align-justify.svg";
|
||||
import {$getBlockElementNodesInSelection, $selectionContainsElementFormat} from "../../../utils/selection";
|
||||
|
||||
|
||||
function setAlignmentForSection(alignment: ElementFormatType): void {
|
||||
|
@ -1,7 +1,6 @@
|
||||
import {$createCalloutNode, $isCalloutNodeOfCategory, CalloutCategory} from "../../../nodes/callout";
|
||||
import {EditorButtonDefinition} from "../../framework/buttons";
|
||||
import {EditorUiContext} from "../../framework/core";
|
||||
import {$selectionContainsNodeType, $toggleSelectionBlockNodeType} from "../../../helpers";
|
||||
import {$createParagraphNode, $isParagraphNode, BaseSelection, LexicalNode} from "lexical";
|
||||
import {
|
||||
$createHeadingNode,
|
||||
@ -11,6 +10,7 @@ import {
|
||||
HeadingNode,
|
||||
HeadingTagType
|
||||
} from "@lexical/rich-text";
|
||||
import {$selectionContainsNodeType, $toggleSelectionBlockNodeType} from "../../../utils/selection";
|
||||
|
||||
function buildCalloutButton(category: CalloutCategory, name: string): EditorButtonDefinition {
|
||||
return {
|
||||
|
@ -11,7 +11,7 @@ import {
|
||||
} from "lexical";
|
||||
import redoIcon from "@icons/editor/redo.svg";
|
||||
import sourceIcon from "@icons/editor/source-view.svg";
|
||||
import {getEditorContentAsHtml} from "../../../actions";
|
||||
import {getEditorContentAsHtml} from "../../../utils/actions";
|
||||
import fullscreenIcon from "@icons/editor/fullscreen.svg";
|
||||
|
||||
export const undo: EditorButtonDefinition = {
|
||||
|
@ -1,7 +1,6 @@
|
||||
import {$getSelection, $isTextNode, BaseSelection, FORMAT_TEXT_COMMAND, TextFormatType} from "lexical";
|
||||
import {EditorBasicButtonDefinition, EditorButtonDefinition} from "../../framework/buttons";
|
||||
import {EditorUiContext} from "../../framework/core";
|
||||
import {$selectionContainsTextFormat} from "../../../helpers";
|
||||
import boldIcon from "@icons/editor/bold.svg";
|
||||
import italicIcon from "@icons/editor/italic.svg";
|
||||
import underlinedIcon from "@icons/editor/underlined.svg";
|
||||
@ -12,6 +11,7 @@ import superscriptIcon from "@icons/editor/superscript.svg";
|
||||
import subscriptIcon from "@icons/editor/subscript.svg";
|
||||
import codeIcon from "@icons/editor/code.svg";
|
||||
import formatClearIcon from "@icons/editor/format-clear.svg";
|
||||
import {$selectionContainsTextFormat} from "../../../utils/selection";
|
||||
|
||||
function buildFormatButton(label: string, format: TextFormatType, icon: string): EditorButtonDefinition {
|
||||
return {
|
||||
|
@ -2,10 +2,10 @@ import {$isListNode, insertList, ListNode, ListType, removeList} from "@lexical/
|
||||
import {EditorButtonDefinition} from "../../framework/buttons";
|
||||
import {EditorUiContext} from "../../framework/core";
|
||||
import {$getSelection, BaseSelection, LexicalNode} from "lexical";
|
||||
import {$selectionContainsNodeType} from "../../../helpers";
|
||||
import listBulletIcon from "@icons/editor/list-bullet.svg";
|
||||
import listNumberedIcon from "@icons/editor/list-numbered.svg";
|
||||
import listCheckIcon from "@icons/editor/list-check.svg";
|
||||
import {$selectionContainsNodeType} from "../../../utils/selection";
|
||||
|
||||
|
||||
function buildListButton(label: string, type: ListType, icon: string): EditorButtonDefinition {
|
||||
|
@ -10,7 +10,6 @@ import {
|
||||
BaseSelection,
|
||||
ElementNode
|
||||
} from "lexical";
|
||||
import {$getNodeFromSelection, $insertNewBlockNodeAtSelection, $selectionContainsNodeType} from "../../../helpers";
|
||||
import {$isLinkNode, LinkNode} from "@lexical/link";
|
||||
import unlinkIcon from "@icons/editor/unlink.svg";
|
||||
import imageIcon from "@icons/editor/image.svg";
|
||||
@ -26,6 +25,11 @@ import detailsIcon from "@icons/editor/details.svg";
|
||||
import mediaIcon from "@icons/editor/media.svg";
|
||||
import {$createDetailsNode, $isDetailsNode} from "../../../nodes/details";
|
||||
import {$isMediaNode, MediaNode} from "../../../nodes/media";
|
||||
import {
|
||||
$getNodeFromSelection,
|
||||
$insertNewBlockNodeAtSelection,
|
||||
$selectionContainsNodeType
|
||||
} from "../../../utils/selection";
|
||||
|
||||
export const link: EditorButtonDefinition = {
|
||||
label: 'Insert/edit link',
|
||||
|
@ -8,10 +8,6 @@ import insertColumnBeforeIcon from "@icons/editor/table-insert-column-before.svg
|
||||
import insertRowAboveIcon from "@icons/editor/table-insert-row-above.svg";
|
||||
import insertRowBelowIcon from "@icons/editor/table-insert-row-below.svg";
|
||||
import {EditorUiContext} from "../../framework/core";
|
||||
import {
|
||||
$getNodeFromSelection, $getParentOfType,
|
||||
$selectionContainsNodeType
|
||||
} from "../../../helpers";
|
||||
import {$getSelection, BaseSelection} from "lexical";
|
||||
import {$isCustomTableNode} from "../../../nodes/custom-table";
|
||||
import {
|
||||
@ -22,6 +18,8 @@ import {
|
||||
$insertTableRow__EXPERIMENTAL, $isTableCellNode,
|
||||
$isTableNode, $isTableRowNode, $isTableSelection, $unmergeCell, TableCellNode, TableNode,
|
||||
} from "@lexical/table";
|
||||
import {$getNodeFromSelection, $selectionContainsNodeType} from "../../../utils/selection";
|
||||
import {$getParentOfType} from "../../../utils/nodes";
|
||||
|
||||
const neverActive = (): boolean => false;
|
||||
const cellNotSelected = (selection: BaseSelection|null) => !$selectionContainsNodeType(selection, $isTableCellNode);
|
||||
|
@ -1,6 +1,6 @@
|
||||
import {EditorFormDefinition} from "../../framework/forms";
|
||||
import {EditorUiContext} from "../../framework/core";
|
||||
import {setEditorContentFromHtml} from "../../../actions";
|
||||
import {setEditorContentFromHtml} from "../../../utils/actions";
|
||||
|
||||
export const source: EditorFormDefinition = {
|
||||
submitText: 'Save',
|
||||
|
@ -4,8 +4,8 @@ import {$createTextNode, $getSelection} from "lexical";
|
||||
import {$createImageNode} from "../../../nodes/image";
|
||||
import {$createLinkNode} from "@lexical/link";
|
||||
import {$createMediaNodeFromHtml, $createMediaNodeFromSrc, $isMediaNode, MediaNode} from "../../../nodes/media";
|
||||
import {$getNodeFromSelection} from "../../../helpers";
|
||||
import {$insertNodeToNearestRoot} from "@lexical/utils";
|
||||
import {$getNodeFromSelection} from "../../../utils/selection";
|
||||
|
||||
export const image: EditorFormDefinition = {
|
||||
submitText: 'Apply',
|
||||
|
@ -1,7 +1,7 @@
|
||||
import {el} from "../../../helpers";
|
||||
import {EditorUiElement} from "../core";
|
||||
import {$getSelection} from "lexical";
|
||||
import {$patchStyleText} from "@lexical/selection";
|
||||
import {el} from "../../../utils/dom";
|
||||
|
||||
const colorChoices = [
|
||||
'#000000',
|
||||
|
@ -1,7 +1,7 @@
|
||||
import {el} from "../../../helpers";
|
||||
import {handleDropdown} from "../helpers/dropdowns";
|
||||
import {EditorContainerUiElement, EditorUiElement} from "../core";
|
||||
import {EditorBasicButtonDefinition, EditorButton} from "../buttons";
|
||||
import {el} from "../../../utils/dom";
|
||||
|
||||
export type EditorDropdownButtonOptions = {
|
||||
showOnHover?: boolean;
|
||||
|
@ -1,7 +1,7 @@
|
||||
import {el} from "../../../helpers";
|
||||
import {EditorUiStateUpdate, EditorContainerUiElement} from "../core";
|
||||
import {EditorButton} from "../buttons";
|
||||
import {handleDropdown} from "../helpers/dropdowns";
|
||||
import {el} from "../../../utils/dom";
|
||||
|
||||
export class EditorFormatMenu extends EditorContainerUiElement {
|
||||
buildDOM(): HTMLElement {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import {el} from "../../../helpers";
|
||||
import {EditorButton, EditorButtonDefinition} from "../buttons";
|
||||
import {el} from "../../../utils/dom";
|
||||
|
||||
export class FormatPreviewButton extends EditorButton {
|
||||
protected previewSampleElement: HTMLElement;
|
||||
|
@ -1,7 +1,7 @@
|
||||
import {EditorContainerUiElement, EditorUiElement} from "../core";
|
||||
import {el} from "../../../helpers";
|
||||
import {EditorDropdownButton} from "./dropdown-button";
|
||||
import moreHorizontal from "@icons/editor/more-horizontal.svg"
|
||||
import {el} from "../../../utils/dom";
|
||||
|
||||
|
||||
export class EditorOverflowContainer extends EditorContainerUiElement {
|
||||
|
@ -1,7 +1,8 @@
|
||||
import {el, $insertNewBlockNodeAtSelection} from "../../../helpers";
|
||||
import {EditorUiElement} from "../core";
|
||||
import {$createTableNodeWithDimensions} from "@lexical/table";
|
||||
import {CustomTableNode} from "../../../nodes/custom-table";
|
||||
import {$insertNewBlockNodeAtSelection} from "../../../utils/selection";
|
||||
import {el} from "../../../utils/dom";
|
||||
|
||||
|
||||
export class EditorTableCreator extends EditorUiElement {
|
||||
|
@ -1,6 +1,7 @@
|
||||
import {BaseSelection} from "lexical";
|
||||
import {EditorUiContext, EditorUiElement, EditorUiStateUpdate} from "./core";
|
||||
import {el} from "../../helpers";
|
||||
|
||||
import {el} from "../../utils/dom";
|
||||
|
||||
export interface EditorBasicButtonDefinition {
|
||||
label: string;
|
||||
|
@ -1,6 +1,7 @@
|
||||
import {BaseSelection, LexicalEditor} from "lexical";
|
||||
import {EditorUIManager} from "./manager";
|
||||
import {el} from "../../helpers";
|
||||
|
||||
import {el} from "../../utils/dom";
|
||||
|
||||
export type EditorUiStateUpdate = {
|
||||
editor: LexicalEditor;
|
||||
|
@ -5,8 +5,8 @@ import {
|
||||
EditorUiBuilderDefinition,
|
||||
isUiBuilderDefinition
|
||||
} from "./core";
|
||||
import {el} from "../../helpers";
|
||||
import {uniqueId} from "../../../services/util";
|
||||
import {el} from "../../utils/dom";
|
||||
|
||||
export interface EditorFormFieldDefinition {
|
||||
label: string;
|
||||
|
@ -1,8 +1,8 @@
|
||||
import {$getNearestNodeFromDOMNode, LexicalEditor} from "lexical";
|
||||
import {el} from "../../../helpers";
|
||||
import {MouseDragTracker, MouseDragTrackerDistance} from "./mouse-drag-tracker";
|
||||
import {$getTableColumnWidth, $setTableColumnWidth, CustomTableNode} from "../../../nodes/custom-table";
|
||||
import {TableRowNode} from "@lexical/table";
|
||||
import {el} from "../../../utils/dom";
|
||||
|
||||
type MarkerDomRecord = {x: HTMLElement, y: HTMLElement};
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import {EditorForm, EditorFormDefinition} from "./forms";
|
||||
import {el} from "../../helpers";
|
||||
import {EditorContainerUiElement} from "./core";
|
||||
import closeIcon from "@icons/close.svg";
|
||||
import {el} from "../../utils/dom";
|
||||
|
||||
export interface EditorModalDefinition {
|
||||
title: string;
|
||||
|
@ -1,5 +1,6 @@
|
||||
import {EditorContainerUiElement, EditorUiElement} from "./core";
|
||||
import {el} from "../../helpers";
|
||||
|
||||
import {el} from "../../utils/dom";
|
||||
|
||||
export type EditorContextToolbarDefinition = {
|
||||
selector: string;
|
||||
|
@ -1,6 +1,5 @@
|
||||
import {EditorButton} from "./framework/buttons";
|
||||
import {EditorContainerUiElement, EditorSimpleClassContainer, EditorUiElement} from "./framework/core";
|
||||
import {$selectionContainsNodeType, el} from "../helpers";
|
||||
import {EditorFormatMenu} from "./framework/blocks/format-menu";
|
||||
import {FormatPreviewButton} from "./framework/blocks/format-preview-button";
|
||||
import {EditorDropdownButton} from "./framework/blocks/dropdown-button";
|
||||
@ -65,6 +64,8 @@ import {
|
||||
unlink
|
||||
} from "./defaults/buttons/objects";
|
||||
import {$isTableNode} from "@lexical/table";
|
||||
import {$selectionContainsNodeType} from "../utils/selection";
|
||||
import {el} from "../utils/dom";
|
||||
|
||||
export function getMainEditorFullToolbar(): EditorContainerUiElement {
|
||||
return new EditorSimpleClassContainer('editor-toolbar-main', [
|
||||
|
@ -1,8 +1,6 @@
|
||||
import {$getRoot, $getSelection, LexicalEditor} from "lexical";
|
||||
import {$generateHtmlFromNodes} from "@lexical/html";
|
||||
import {$htmlToBlockNodes} from "./helpers";
|
||||
|
||||
|
||||
import {$htmlToBlockNodes} from "./nodes";
|
||||
|
||||
export function setEditorContentFromHtml(editor: LexicalEditor, html: string) {
|
||||
editor.update(() => {
|
24
resources/js/wysiwyg/utils/dom.ts
Normal file
24
resources/js/wysiwyg/utils/dom.ts
Normal file
@ -0,0 +1,24 @@
|
||||
export function el(tag: string, attrs: Record<string, string | null> = {}, children: (string | HTMLElement)[] = []): HTMLElement {
|
||||
const el = document.createElement(tag);
|
||||
const attrKeys = Object.keys(attrs);
|
||||
for (const attr of attrKeys) {
|
||||
if (attrs[attr] !== null) {
|
||||
el.setAttribute(attr, attrs[attr] as string);
|
||||
}
|
||||
}
|
||||
|
||||
for (const child of children) {
|
||||
if (typeof child === 'string') {
|
||||
el.append(document.createTextNode(child));
|
||||
} else {
|
||||
el.append(child);
|
||||
}
|
||||
}
|
||||
|
||||
return el;
|
||||
}
|
||||
|
||||
export function htmlToDom(html: string): Document {
|
||||
const parser = new DOMParser();
|
||||
return parser.parseFromString(html, 'text/html');
|
||||
}
|
53
resources/js/wysiwyg/utils/nodes.ts
Normal file
53
resources/js/wysiwyg/utils/nodes.ts
Normal file
@ -0,0 +1,53 @@
|
||||
import {$getRoot, $isTextNode, LexicalEditor, LexicalNode} from "lexical";
|
||||
import {LexicalNodeMatcher} from "../nodes";
|
||||
import {$createCustomParagraphNode} from "../nodes/custom-paragraph";
|
||||
import {$generateNodesFromDOM} from "@lexical/html";
|
||||
import {htmlToDom} from "./dom";
|
||||
|
||||
function wrapTextNodes(nodes: LexicalNode[]): LexicalNode[] {
|
||||
return nodes.map(node => {
|
||||
if ($isTextNode(node)) {
|
||||
const paragraph = $createCustomParagraphNode();
|
||||
paragraph.append(node);
|
||||
return paragraph;
|
||||
}
|
||||
return node;
|
||||
});
|
||||
}
|
||||
|
||||
export function $htmlToBlockNodes(editor: LexicalEditor, html: string): LexicalNode[] {
|
||||
const dom = htmlToDom(html);
|
||||
const nodes = $generateNodesFromDOM(editor, dom);
|
||||
return wrapTextNodes(nodes);
|
||||
}
|
||||
|
||||
export function $getParentOfType(node: LexicalNode, matcher: LexicalNodeMatcher): LexicalNode | null {
|
||||
for (const parent of node.getParents()) {
|
||||
if (matcher(parent)) {
|
||||
return parent;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the nearest root/block level node for the given position.
|
||||
*/
|
||||
export function $getNearestBlockNodeForCoords(editor: LexicalEditor, x: number, y: number): LexicalNode | null {
|
||||
// TODO - Take into account x for floated blocks?
|
||||
const rootNodes = $getRoot().getChildren();
|
||||
for (const node of rootNodes) {
|
||||
const nodeDom = editor.getElementByKey(node.__key);
|
||||
if (!nodeDom) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const bounds = nodeDom.getBoundingClientRect();
|
||||
if (y <= bounds.bottom) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
@ -1,64 +1,28 @@
|
||||
import {
|
||||
$createNodeSelection,
|
||||
$createParagraphNode, $getRoot,
|
||||
$getSelection, $isElementNode,
|
||||
$isTextNode, $setSelection,
|
||||
BaseSelection, ElementFormatType, ElementNode, LexicalEditor,
|
||||
LexicalNode, TextFormatType
|
||||
$createParagraphNode,
|
||||
$getRoot,
|
||||
$getSelection,
|
||||
$isElementNode,
|
||||
$isTextNode,
|
||||
$setSelection,
|
||||
BaseSelection,
|
||||
ElementFormatType,
|
||||
ElementNode,
|
||||
LexicalNode,
|
||||
TextFormatType
|
||||
} from "lexical";
|
||||
import {LexicalElementNodeCreator, LexicalNodeMatcher} from "./nodes";
|
||||
import {$findMatchingParent, $getNearestBlockElementAncestorOrThrow} from "@lexical/utils";
|
||||
import {LexicalElementNodeCreator, LexicalNodeMatcher} from "../nodes";
|
||||
import {$setBlocksType} from "@lexical/selection";
|
||||
import {$createCustomParagraphNode} from "./nodes/custom-paragraph";
|
||||
import {$generateNodesFromDOM} from "@lexical/html";
|
||||
|
||||
export function el(tag: string, attrs: Record<string, string|null> = {}, children: (string|HTMLElement)[] = []): HTMLElement {
|
||||
const el = document.createElement(tag);
|
||||
const attrKeys = Object.keys(attrs);
|
||||
for (const attr of attrKeys) {
|
||||
if (attrs[attr] !== null) {
|
||||
el.setAttribute(attr, attrs[attr] as string);
|
||||
}
|
||||
}
|
||||
import {$getParentOfType} from "./nodes";
|
||||
|
||||
for (const child of children) {
|
||||
if (typeof child === 'string') {
|
||||
el.append(document.createTextNode(child));
|
||||
} else {
|
||||
el.append(child);
|
||||
}
|
||||
}
|
||||
|
||||
return el;
|
||||
}
|
||||
|
||||
function htmlToDom(html: string): Document {
|
||||
const parser = new DOMParser();
|
||||
return parser.parseFromString(html, 'text/html');
|
||||
}
|
||||
|
||||
function wrapTextNodes(nodes: LexicalNode[]): LexicalNode[] {
|
||||
return nodes.map(node => {
|
||||
if ($isTextNode(node)) {
|
||||
const paragraph = $createCustomParagraphNode();
|
||||
paragraph.append(node);
|
||||
return paragraph;
|
||||
}
|
||||
return node;
|
||||
});
|
||||
}
|
||||
|
||||
export function $htmlToBlockNodes(editor: LexicalEditor, html: string): LexicalNode[] {
|
||||
const dom = htmlToDom(html);
|
||||
const nodes = $generateNodesFromDOM(editor, dom);
|
||||
return wrapTextNodes(nodes);
|
||||
}
|
||||
|
||||
export function $selectionContainsNodeType(selection: BaseSelection|null, matcher: LexicalNodeMatcher): boolean {
|
||||
export function $selectionContainsNodeType(selection: BaseSelection | null, matcher: LexicalNodeMatcher): boolean {
|
||||
return $getNodeFromSelection(selection, matcher) !== null;
|
||||
}
|
||||
|
||||
export function $getNodeFromSelection(selection: BaseSelection|null, matcher: LexicalNodeMatcher): LexicalNode|null {
|
||||
export function $getNodeFromSelection(selection: BaseSelection | null, matcher: LexicalNodeMatcher): LexicalNode | null {
|
||||
if (!selection) {
|
||||
return null;
|
||||
}
|
||||
@ -77,17 +41,7 @@ export function $getNodeFromSelection(selection: BaseSelection|null, matcher: Le
|
||||
return null;
|
||||
}
|
||||
|
||||
export function $getParentOfType(node: LexicalNode, matcher: LexicalNodeMatcher): LexicalNode|null {
|
||||
for (const parent of node.getParents()) {
|
||||
if (matcher(parent)) {
|
||||
return parent;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function $selectionContainsTextFormat(selection: BaseSelection|null, format: TextFormatType): boolean {
|
||||
export function $selectionContainsTextFormat(selection: BaseSelection | null, format: TextFormatType): boolean {
|
||||
if (!selection) {
|
||||
return false;
|
||||
}
|
||||
@ -140,7 +94,7 @@ export function $selectSingleNode(node: LexicalNode) {
|
||||
$setSelection(nodeSelection);
|
||||
}
|
||||
|
||||
export function $selectionContainsNode(selection: BaseSelection|null, node: LexicalNode): boolean {
|
||||
export function $selectionContainsNode(selection: BaseSelection | null, node: LexicalNode): boolean {
|
||||
if (!selection) {
|
||||
return false;
|
||||
}
|
||||
@ -155,7 +109,7 @@ export function $selectionContainsNode(selection: BaseSelection|null, node: Lexi
|
||||
return false;
|
||||
}
|
||||
|
||||
export function $selectionContainsElementFormat(selection: BaseSelection|null, format: ElementFormatType): boolean {
|
||||
export function $selectionContainsElementFormat(selection: BaseSelection | null, format: ElementFormatType): boolean {
|
||||
const nodes = $getBlockElementNodesInSelection(selection);
|
||||
for (const node of nodes) {
|
||||
if (node.getFormatType() === format) {
|
||||
@ -166,7 +120,7 @@ export function $selectionContainsElementFormat(selection: BaseSelection|null, f
|
||||
return false;
|
||||
}
|
||||
|
||||
export function $getBlockElementNodesInSelection(selection: BaseSelection|null): ElementNode[] {
|
||||
export function $getBlockElementNodesInSelection(selection: BaseSelection | null): ElementNode[] {
|
||||
if (!selection) {
|
||||
return [];
|
||||
}
|
||||
@ -175,7 +129,7 @@ export function $getBlockElementNodesInSelection(selection: BaseSelection|null):
|
||||
for (const node of selection.getNodes()) {
|
||||
const blockElement = $findMatchingParent(node, (node) => {
|
||||
return $isElementNode(node) && !node.isInline();
|
||||
}) as ElementNode|null;
|
||||
}) as ElementNode | null;
|
||||
|
||||
if (blockElement) {
|
||||
blockNodes.set(blockElement.getKey(), blockElement);
|
||||
@ -183,25 +137,4 @@ export function $getBlockElementNodesInSelection(selection: BaseSelection|null):
|
||||
}
|
||||
|
||||
return Array.from(blockNodes.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the nearest root/block level node for the given position.
|
||||
*/
|
||||
export function $getNearestBlockNodeForCoords(editor: LexicalEditor, x: number, y: number): LexicalNode|null {
|
||||
// TODO - Take into account x for floated blocks?
|
||||
const rootNodes = $getRoot().getChildren();
|
||||
for (const node of rootNodes) {
|
||||
const nodeDom = editor.getElementByKey(node.__key);
|
||||
if (!nodeDom) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const bounds = nodeDom.getBoundingClientRect();
|
||||
if (y <= bounds.bottom) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
Loading…
Reference in New Issue
Block a user