return true;
}
+ isParentRequired(): boolean {
+ return true;
+ }
+
createInnerDOM() {
const sources = (this.__tag === 'video' || this.__tag === 'audio') ? this.__sources : [];
const sourceEls = sources.map(source => el('source', source));
const videoExtensions = ['mp4', 'mpeg', 'm4v', 'm4p', 'mov'];
const audioExtensions = ['3gp', 'aac', 'flac', 'mp3', 'm4a', 'ogg', 'wav', 'webm'];
-const iframeExtensions = ['html', 'htm', 'php', 'asp', 'aspx'];
+const iframeExtensions = ['html', 'htm', 'php', 'asp', 'aspx', ''];
export function $createMediaNodeFromSrc(src: string): MediaNode {
let nodeTag: MediaNodeTag = 'iframe';
const srcEnd = src.split('?')[0].split('/').pop() || '';
- const extension = (srcEnd.split('.').pop() || '').toLowerCase();
+ const srcEndSplit = srcEnd.split('.');
+ const extension = (srcEndSplit.length > 1 ? srcEndSplit[srcEndSplit.length - 1] : '').toLowerCase();
if (videoExtensions.includes(extension)) {
nodeTag = 'video';
} else if (audioExtensions.includes(extension)) {
COMMAND_PRIORITY_LOW,
KEY_BACKSPACE_COMMAND,
KEY_DELETE_COMMAND,
- LexicalEditor
+ KEY_ENTER_COMMAND,
+ LexicalEditor,
+ LexicalNode
} from "lexical";
import {$isImageNode} from "../nodes/image";
import {$isMediaNode} from "../nodes/media";
import {getLastSelection} from "../utils/selection";
+import {$getNearestNodeBlockParent} from "../utils/nodes";
+import {$createCustomParagraphNode} from "../nodes/custom-paragraph";
+
+function isSingleSelectedNode(nodes: LexicalNode[]): boolean {
+ if (nodes.length === 1) {
+ const node = nodes[0];
+ if ($isDecoratorNode(node) || $isImageNode(node) || $isMediaNode(node)) {
+ return true;
+ }
+ }
+
+ return false;
+}
function deleteSingleSelectedNode(editor: LexicalEditor) {
const selectionNodes = getLastSelection(editor)?.getNodes() || [];
- if (selectionNodes.length === 1) {
+ if (isSingleSelectedNode(selectionNodes)) {
+ editor.update(() => {
+ selectionNodes[0].remove();
+ });
+ }
+}
+
+function insertAfterSingleSelectedNode(editor: LexicalEditor, event: KeyboardEvent|null): boolean {
+ const selectionNodes = getLastSelection(editor)?.getNodes() || [];
+ if (isSingleSelectedNode(selectionNodes)) {
const node = selectionNodes[0];
- if ($isDecoratorNode(node) || $isImageNode(node) || $isMediaNode(node)) {
- editor.update(() => {
- node.remove();
+ const nearestBlock = $getNearestNodeBlockParent(node) || node;
+ if (nearestBlock) {
+ requestAnimationFrame(() => {
+ editor.update(() => {
+ const newParagraph = $createCustomParagraphNode();
+ nearestBlock.insertAfter(newParagraph);
+ newParagraph.select();
+ });
});
+ event?.preventDefault();
+ return true;
}
}
+
+ return false;
}
export function registerKeyboardHandling(context: EditorUiContext): () => void {
return false;
}, COMMAND_PRIORITY_LOW);
+ const unregisterEnter = context.editor.registerCommand(KEY_ENTER_COMMAND, (event): boolean => {
+ return insertAfterSingleSelectedNode(context.editor, event);
+ }, COMMAND_PRIORITY_LOW);
+
return () => {
- unregisterBackspace();
- unregisterDelete();
+ unregisterBackspace();
+ unregisterDelete();
+ unregisterEnter();
};
}
\ No newline at end of file
if (selectedNode && node) {
selectedNode.replace(node)
} else if (node) {
- $insertNodeToNearestRoot(node);
+ $insertNodes([node]);
}
});
updateNode.setSrc(src);
updateNode.setWidthAndHeight(width, height);
if (!selectedNode) {
- $insertNodeToNearestRoot(updateNode);
+ $insertNodes([updateNode]);
}
});
-import {$getRoot, $isElementNode, $isTextNode, ElementNode, LexicalEditor, LexicalNode} from "lexical";
+import {
+ $getRoot,
+ $isDecoratorNode,
+ $isElementNode,
+ $isTextNode,
+ ElementNode,
+ LexicalEditor,
+ LexicalNode
+} from "lexical";
import {LexicalNodeMatcher} from "../nodes";
import {$createCustomParagraphNode} from "../nodes/custom-paragraph";
import {$generateNodesFromDOM} from "@lexical/html";
import {htmlToDom} from "./dom";
import {NodeHasAlignment} from "../nodes/_common";
+import {$findMatchingParent} from "@lexical/utils";
function wrapTextNodes(nodes: LexicalNode[]): LexicalNode[] {
return nodes.map(node => {
return null;
}
+export function $getNearestNodeBlockParent(node: LexicalNode): LexicalNode|null {
+ const isBlockNode = (node: LexicalNode): boolean => {
+ return ($isElementNode(node) || $isDecoratorNode(node)) && !node.isInline();
+ };
+
+ if (isBlockNode(node)) {
+ return node;
+ }
+
+ return $findMatchingParent(node, isBlockNode);
+}
+
export function nodeHasAlignment(node: object): node is NodeHasAlignment {
return '__alignment' in node;
}
\ No newline at end of file
import {LexicalElementNodeCreator, LexicalNodeMatcher} from "../nodes";
import {$setBlocksType} from "@lexical/selection";
-import {$getParentOfType, nodeHasAlignment} from "./nodes";
+import {$getNearestNodeBlockParent, $getParentOfType, nodeHasAlignment} from "./nodes";
import {$createCustomParagraphNode} from "../nodes/custom-paragraph";
import {CommonBlockAlignment} from "../nodes/_common";
const blockNodes: Map<string, ElementNode> = new Map();
for (const node of selection.getNodes()) {
- const blockElement = $findMatchingParent(node, (node) => {
- return $isElementNode(node) && !node.isInline();
- }) as ElementNode | null;
-
- if (blockElement) {
+ const blockElement = $getNearestNodeBlockParent(node);
+ if ($isElementNode(blockElement)) {
blockNodes.set(blockElement.getKey(), blockElement);
}
}