mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-10-01 01:36:00 -04:00
Lexical: Got media node core work & form done
This commit is contained in:
parent
f284d31861
commit
c8f6b7e0d6
@ -30,7 +30,7 @@ const attributeAllowList = [
|
||||
|
||||
function filterAttributes(attributes: Record<string, string>): Record<string, string> {
|
||||
const filtered: Record<string, string> = {};
|
||||
for (const key in Object.keys(attributes)) {
|
||||
for (const key of Object.keys(attributes)) {
|
||||
if (attributeAllowList.includes(key)) {
|
||||
filtered[key] = attributes[key];
|
||||
}
|
||||
@ -170,7 +170,7 @@ export class MediaNode extends ElementNode {
|
||||
exportJSON(): SerializedMediaNode {
|
||||
return {
|
||||
...super.exportJSON(),
|
||||
type: 'callout',
|
||||
type: 'media',
|
||||
version: 1,
|
||||
tag: this.__tag,
|
||||
attributes: this.__attributes,
|
||||
@ -206,6 +206,25 @@ export function $createMediaNodeFromHtml(html: string): MediaNode | null {
|
||||
return domElementToNode(tag as MediaNodeTag, el);
|
||||
}
|
||||
|
||||
const videoExtensions = ['mp4', 'mpeg', 'm4v', 'm4p', 'mov'];
|
||||
const audioExtensions = ['3gp', 'aac', 'flac', 'mp3', 'm4a', 'ogg', 'wav', 'webm'];
|
||||
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();
|
||||
if (videoExtensions.includes(extension)) {
|
||||
nodeTag = 'video';
|
||||
} else if (audioExtensions.includes(extension)) {
|
||||
nodeTag = 'audio';
|
||||
} else if (extension && !iframeExtensions.includes(extension)) {
|
||||
nodeTag = 'embed';
|
||||
}
|
||||
|
||||
return new MediaNode(nodeTag);
|
||||
}
|
||||
|
||||
export function $isMediaNode(node: LexicalNode | null | undefined) {
|
||||
return node instanceof MediaNode;
|
||||
}
|
||||
|
@ -2,7 +2,8 @@
|
||||
|
||||
## In progress
|
||||
|
||||
- Finish initial media node & form integration
|
||||
- Update forms to allow panels (Media)
|
||||
- Will be used for table forms also.
|
||||
|
||||
## Main Todo
|
||||
|
||||
|
@ -1,15 +1,17 @@
|
||||
import {EditorFormDefinition, EditorSelectFormFieldDefinition} from "../framework/forms";
|
||||
import {EditorUiContext} from "../framework/core";
|
||||
import {$createLinkNode} from "@lexical/link";
|
||||
import {$createTextNode, $getSelection} from "lexical";
|
||||
import {$createTextNode, $getSelection, LexicalNode} from "lexical";
|
||||
import {$createImageNode} from "../../nodes/image";
|
||||
import {setEditorContentFromHtml} from "../../actions";
|
||||
import {$createMediaNodeFromHtml} from "../../nodes/media";
|
||||
import {$createMediaNodeFromHtml, $createMediaNodeFromSrc, $isMediaNode, MediaNode} from "../../nodes/media";
|
||||
import {$getNodeFromSelection} from "../../helpers";
|
||||
import {$insertNodeToNearestRoot} from "@lexical/utils";
|
||||
|
||||
|
||||
export const link: EditorFormDefinition = {
|
||||
submitText: 'Apply',
|
||||
action(formData, context: EditorUiContext) {
|
||||
async action(formData, context: EditorUiContext) {
|
||||
context.editor.update(() => {
|
||||
|
||||
const selection = $getSelection();
|
||||
@ -54,7 +56,7 @@ export const link: EditorFormDefinition = {
|
||||
|
||||
export const image: EditorFormDefinition = {
|
||||
submitText: 'Apply',
|
||||
action(formData, context: EditorUiContext) {
|
||||
async action(formData, context: EditorUiContext) {
|
||||
context.editor.update(() => {
|
||||
const selection = $getSelection();
|
||||
const imageNode = $createImageNode(formData.get('src')?.toString() || '', {
|
||||
@ -92,25 +94,40 @@ export const image: EditorFormDefinition = {
|
||||
|
||||
export const media: EditorFormDefinition = {
|
||||
submitText: 'Save',
|
||||
action(formData, context: EditorUiContext) {
|
||||
|
||||
// TODO - Get media from selection
|
||||
async action(formData, context: EditorUiContext) {
|
||||
const selectedNode: MediaNode|null = await (new Promise((res, rej) => {
|
||||
context.editor.getEditorState().read(() => {
|
||||
const node = $getNodeFromSelection($getSelection(), $isMediaNode);
|
||||
res(node as MediaNode|null);
|
||||
});
|
||||
}));
|
||||
|
||||
const embedCode = (formData.get('embed') || '').toString().trim();
|
||||
if (embedCode) {
|
||||
context.editor.update(() => {
|
||||
const node = $createMediaNodeFromHtml(embedCode);
|
||||
// TODO - Replace existing or insert new
|
||||
if (selectedNode && node) {
|
||||
selectedNode.replace(node)
|
||||
} else if (node) {
|
||||
$insertNodeToNearestRoot(node);
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const src = (formData.get('src') || '').toString().trim();
|
||||
const height = (formData.get('height') || '').toString().trim();
|
||||
const width = (formData.get('width') || '').toString().trim();
|
||||
context.editor.update(() => {
|
||||
const src = (formData.get('src') || '').toString().trim();
|
||||
const height = (formData.get('height') || '').toString().trim();
|
||||
const width = (formData.get('width') || '').toString().trim();
|
||||
|
||||
// TODO - Update existing or insert new
|
||||
const updateNode = selectedNode || $createMediaNodeFromSrc(src);
|
||||
updateNode.setSrc(src);
|
||||
updateNode.setWidthAndHeight(width, height);
|
||||
if (!selectedNode) {
|
||||
$insertNodeToNearestRoot(updateNode);
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
},
|
||||
@ -141,7 +158,7 @@ export const media: EditorFormDefinition = {
|
||||
|
||||
export const source: EditorFormDefinition = {
|
||||
submitText: 'Save',
|
||||
action(formData, context: EditorUiContext) {
|
||||
async action(formData, context: EditorUiContext) {
|
||||
setEditorContentFromHtml(context.editor, formData.get('source')?.toString() || '');
|
||||
return true;
|
||||
},
|
||||
|
@ -14,7 +14,7 @@ export interface EditorSelectFormFieldDefinition extends EditorFormFieldDefiniti
|
||||
|
||||
export interface EditorFormDefinition {
|
||||
submitText: string;
|
||||
action: (formData: FormData, context: EditorUiContext) => boolean;
|
||||
action: (formData: FormData, context: EditorUiContext) => Promise<boolean>;
|
||||
fields: EditorFormFieldDefinition[];
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user