mirror of
https://github.com/BookStackApp/BookStack.git
synced 2025-04-21 11:40:38 +00:00
Lexical: Got media node core work & form done
This commit is contained in:
parent
f284d31861
commit
c8f6b7e0d6
4 changed files with 54 additions and 17 deletions
resources/js/wysiwyg
|
@ -30,7 +30,7 @@ const attributeAllowList = [
|
||||||
|
|
||||||
function filterAttributes(attributes: Record<string, string>): Record<string, string> {
|
function filterAttributes(attributes: Record<string, string>): Record<string, string> {
|
||||||
const filtered: 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)) {
|
if (attributeAllowList.includes(key)) {
|
||||||
filtered[key] = attributes[key];
|
filtered[key] = attributes[key];
|
||||||
}
|
}
|
||||||
|
@ -170,7 +170,7 @@ export class MediaNode extends ElementNode {
|
||||||
exportJSON(): SerializedMediaNode {
|
exportJSON(): SerializedMediaNode {
|
||||||
return {
|
return {
|
||||||
...super.exportJSON(),
|
...super.exportJSON(),
|
||||||
type: 'callout',
|
type: 'media',
|
||||||
version: 1,
|
version: 1,
|
||||||
tag: this.__tag,
|
tag: this.__tag,
|
||||||
attributes: this.__attributes,
|
attributes: this.__attributes,
|
||||||
|
@ -206,6 +206,25 @@ export function $createMediaNodeFromHtml(html: string): MediaNode | null {
|
||||||
return domElementToNode(tag as MediaNodeTag, el);
|
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) {
|
export function $isMediaNode(node: LexicalNode | null | undefined) {
|
||||||
return node instanceof MediaNode;
|
return node instanceof MediaNode;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
## In progress
|
## In progress
|
||||||
|
|
||||||
- Finish initial media node & form integration
|
- Update forms to allow panels (Media)
|
||||||
|
- Will be used for table forms also.
|
||||||
|
|
||||||
## Main Todo
|
## Main Todo
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,17 @@
|
||||||
import {EditorFormDefinition, EditorSelectFormFieldDefinition} from "../framework/forms";
|
import {EditorFormDefinition, EditorSelectFormFieldDefinition} from "../framework/forms";
|
||||||
import {EditorUiContext} from "../framework/core";
|
import {EditorUiContext} from "../framework/core";
|
||||||
import {$createLinkNode} from "@lexical/link";
|
import {$createLinkNode} from "@lexical/link";
|
||||||
import {$createTextNode, $getSelection} from "lexical";
|
import {$createTextNode, $getSelection, LexicalNode} from "lexical";
|
||||||
import {$createImageNode} from "../../nodes/image";
|
import {$createImageNode} from "../../nodes/image";
|
||||||
import {setEditorContentFromHtml} from "../../actions";
|
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 = {
|
export const link: EditorFormDefinition = {
|
||||||
submitText: 'Apply',
|
submitText: 'Apply',
|
||||||
action(formData, context: EditorUiContext) {
|
async action(formData, context: EditorUiContext) {
|
||||||
context.editor.update(() => {
|
context.editor.update(() => {
|
||||||
|
|
||||||
const selection = $getSelection();
|
const selection = $getSelection();
|
||||||
|
@ -54,7 +56,7 @@ export const link: EditorFormDefinition = {
|
||||||
|
|
||||||
export const image: EditorFormDefinition = {
|
export const image: EditorFormDefinition = {
|
||||||
submitText: 'Apply',
|
submitText: 'Apply',
|
||||||
action(formData, context: EditorUiContext) {
|
async action(formData, context: EditorUiContext) {
|
||||||
context.editor.update(() => {
|
context.editor.update(() => {
|
||||||
const selection = $getSelection();
|
const selection = $getSelection();
|
||||||
const imageNode = $createImageNode(formData.get('src')?.toString() || '', {
|
const imageNode = $createImageNode(formData.get('src')?.toString() || '', {
|
||||||
|
@ -92,25 +94,40 @@ export const image: EditorFormDefinition = {
|
||||||
|
|
||||||
export const media: EditorFormDefinition = {
|
export const media: EditorFormDefinition = {
|
||||||
submitText: 'Save',
|
submitText: 'Save',
|
||||||
action(formData, context: EditorUiContext) {
|
async action(formData, context: EditorUiContext) {
|
||||||
|
const selectedNode: MediaNode|null = await (new Promise((res, rej) => {
|
||||||
// TODO - Get media from selection
|
context.editor.getEditorState().read(() => {
|
||||||
|
const node = $getNodeFromSelection($getSelection(), $isMediaNode);
|
||||||
|
res(node as MediaNode|null);
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
const embedCode = (formData.get('embed') || '').toString().trim();
|
const embedCode = (formData.get('embed') || '').toString().trim();
|
||||||
if (embedCode) {
|
if (embedCode) {
|
||||||
context.editor.update(() => {
|
context.editor.update(() => {
|
||||||
const node = $createMediaNodeFromHtml(embedCode);
|
const node = $createMediaNodeFromHtml(embedCode);
|
||||||
// TODO - Replace existing or insert new
|
if (selectedNode && node) {
|
||||||
|
selectedNode.replace(node)
|
||||||
|
} else if (node) {
|
||||||
|
$insertNodeToNearestRoot(node);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const src = (formData.get('src') || '').toString().trim();
|
context.editor.update(() => {
|
||||||
const height = (formData.get('height') || '').toString().trim();
|
const src = (formData.get('src') || '').toString().trim();
|
||||||
const width = (formData.get('width') || '').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;
|
return true;
|
||||||
},
|
},
|
||||||
|
@ -141,7 +158,7 @@ export const media: EditorFormDefinition = {
|
||||||
|
|
||||||
export const source: EditorFormDefinition = {
|
export const source: EditorFormDefinition = {
|
||||||
submitText: 'Save',
|
submitText: 'Save',
|
||||||
action(formData, context: EditorUiContext) {
|
async action(formData, context: EditorUiContext) {
|
||||||
setEditorContentFromHtml(context.editor, formData.get('source')?.toString() || '');
|
setEditorContentFromHtml(context.editor, formData.get('source')?.toString() || '');
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
|
@ -14,7 +14,7 @@ export interface EditorSelectFormFieldDefinition extends EditorFormFieldDefiniti
|
||||||
|
|
||||||
export interface EditorFormDefinition {
|
export interface EditorFormDefinition {
|
||||||
submitText: string;
|
submitText: string;
|
||||||
action: (formData: FormData, context: EditorUiContext) => boolean;
|
action: (formData: FormData, context: EditorUiContext) => Promise<boolean>;
|
||||||
fields: EditorFormFieldDefinition[];
|
fields: EditorFormFieldDefinition[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue