mirror of
https://github.com/BookStackApp/BookStack.git
synced 2025-02-24 05:14:34 +08:00
Lexical: Added media src conversions
Only actuall added YT in the end. Google had changed URL scheme, and Vimeo seems to just be something else now, can't really browse video pages like before.
This commit is contained in:
parent
958b537a49
commit
d89a2fdb15
@ -16,6 +16,7 @@ import {
|
||||
} from "lexical/nodes/common";
|
||||
import {$selectSingleNode} from "../../utils/selection";
|
||||
import {SerializedCommonBlockNode} from "lexical/nodes/CommonBlockNode";
|
||||
import * as url from "node:url";
|
||||
|
||||
export type MediaNodeTag = 'iframe' | 'embed' | 'object' | 'video' | 'audio';
|
||||
export type MediaNodeSource = {
|
||||
@ -343,11 +344,55 @@ export function $createMediaNodeFromHtml(html: string): MediaNode | null {
|
||||
return domElementToNode(tag as MediaNodeTag, el);
|
||||
}
|
||||
|
||||
interface UrlPattern {
|
||||
readonly regex: RegExp;
|
||||
readonly w: number;
|
||||
readonly h: number;
|
||||
readonly url: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* These patterns originate from the tinymce/tinymce project.
|
||||
* https://github.com/tinymce/tinymce/blob/release/6.6/modules/tinymce/src/plugins/media/main/ts/core/UrlPatterns.ts
|
||||
* License: MIT Copyright (c) 2022 Ephox Corporation DBA Tiny Technologies, Inc.
|
||||
* License Link: https://github.com/tinymce/tinymce/blob/584a150679669859a528828e5d2910a083b1d911/LICENSE.TXT
|
||||
*/
|
||||
const urlPatterns: UrlPattern[] = [
|
||||
{
|
||||
regex: /.*?youtu\.be\/([\w\-_\?&=.]+)/i,
|
||||
w: 560, h: 314,
|
||||
url: 'https://www.youtube.com/embed/$1',
|
||||
},
|
||||
{
|
||||
regex: /.*youtube\.com(.+)v=([^&]+)(&([a-z0-9&=\-_]+))?.*/i,
|
||||
w: 560, h: 314,
|
||||
url: 'https://www.youtube.com/embed/$2?$4',
|
||||
},
|
||||
{
|
||||
regex: /.*youtube.com\/embed\/([a-z0-9\?&=\-_]+).*/i,
|
||||
w: 560, h: 314,
|
||||
url: 'https://www.youtube.com/embed/$1',
|
||||
},
|
||||
];
|
||||
|
||||
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 {
|
||||
|
||||
for (const pattern of urlPatterns) {
|
||||
const match = src.match(pattern.regex);
|
||||
if (match) {
|
||||
const newSrc = src.replace(pattern.regex, pattern.url);
|
||||
const node = new MediaNode('iframe');
|
||||
node.setSrc(newSrc);
|
||||
node.setHeight(pattern.h);
|
||||
node.setWidth(pattern.w);
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
let nodeTag: MediaNodeTag = 'iframe';
|
||||
const srcEnd = src.split('?')[0].split('/').pop() || '';
|
||||
const srcEndSplit = srcEnd.split('.');
|
||||
@ -360,7 +405,9 @@ export function $createMediaNodeFromSrc(src: string): MediaNode {
|
||||
nodeTag = 'embed';
|
||||
}
|
||||
|
||||
return new MediaNode(nodeTag);
|
||||
const node = new MediaNode(nodeTag);
|
||||
node.setSrc(src);
|
||||
return node;
|
||||
}
|
||||
|
||||
export function $isMediaNode(node: LexicalNode | null | undefined): node is MediaNode {
|
||||
|
@ -10,7 +10,6 @@
|
||||
|
||||
## Secondary Todo
|
||||
|
||||
- Support media src conversions (https://github.com/tinymce/tinymce/blob/release/6.6/modules/tinymce/src/plugins/media/main/ts/core/UrlPatterns.ts)
|
||||
- Deep check of translation coverage
|
||||
|
||||
## Bugs
|
||||
|
@ -32,7 +32,7 @@ import {
|
||||
} from "../../../utils/selection";
|
||||
import {$isDiagramNode, $openDrawingEditorForNode, showDiagramManagerForInsert} from "../../../utils/diagrams";
|
||||
import {$createLinkedImageNodeFromImageData, showImageManager} from "../../../utils/images";
|
||||
import {$showDetailsForm, $showImageForm, $showLinkForm} from "../forms/objects";
|
||||
import {$showDetailsForm, $showImageForm, $showLinkForm, $showMediaForm} from "../forms/objects";
|
||||
import {formatCodeBlock} from "../../../utils/formats";
|
||||
|
||||
export const link: EditorButtonDefinition = {
|
||||
@ -168,24 +168,11 @@ export const media: EditorButtonDefinition = {
|
||||
label: 'Insert/edit Media',
|
||||
icon: mediaIcon,
|
||||
action(context: EditorUiContext) {
|
||||
const mediaModal = context.manager.createModal('media');
|
||||
|
||||
context.editor.getEditorState().read(() => {
|
||||
const selection = $getSelection();
|
||||
const selectedNode = $getNodeFromSelection(selection, $isMediaNode) as MediaNode | null;
|
||||
|
||||
let formDefaults = {};
|
||||
if (selectedNode) {
|
||||
const nodeAttrs = selectedNode.getAttributes();
|
||||
formDefaults = {
|
||||
src: nodeAttrs.src || nodeAttrs.data || '',
|
||||
width: nodeAttrs.width,
|
||||
height: nodeAttrs.height,
|
||||
embed: '',
|
||||
}
|
||||
}
|
||||
|
||||
mediaModal.show(formDefaults);
|
||||
$showMediaForm(selectedNode, context);
|
||||
});
|
||||
},
|
||||
isActive(selection: BaseSelection | null): boolean {
|
||||
|
@ -186,6 +186,23 @@ export const link: EditorFormDefinition = {
|
||||
],
|
||||
};
|
||||
|
||||
export function $showMediaForm(media: MediaNode|null, context: EditorUiContext): void {
|
||||
const mediaModal = context.manager.createModal('media');
|
||||
|
||||
let formDefaults = {};
|
||||
if (media) {
|
||||
const nodeAttrs = media.getAttributes();
|
||||
formDefaults = {
|
||||
src: nodeAttrs.src || nodeAttrs.data || '',
|
||||
width: nodeAttrs.width,
|
||||
height: nodeAttrs.height,
|
||||
embed: '',
|
||||
}
|
||||
}
|
||||
|
||||
mediaModal.show(formDefaults);
|
||||
}
|
||||
|
||||
export const media: EditorFormDefinition = {
|
||||
submitText: 'Save',
|
||||
async action(formData, context: EditorUiContext) {
|
||||
@ -215,12 +232,19 @@ export const media: EditorFormDefinition = {
|
||||
const height = (formData.get('height') || '').toString().trim();
|
||||
const width = (formData.get('width') || '').toString().trim();
|
||||
|
||||
const updateNode = selectedNode || $createMediaNodeFromSrc(src);
|
||||
updateNode.setSrc(src);
|
||||
updateNode.setWidthAndHeight(width, height);
|
||||
if (!selectedNode) {
|
||||
$insertNodes([updateNode]);
|
||||
// Update existing
|
||||
if (selectedNode) {
|
||||
selectedNode.setSrc(src);
|
||||
selectedNode.setWidthAndHeight(width, height);
|
||||
return;
|
||||
}
|
||||
|
||||
// Insert new
|
||||
const node = $createMediaNodeFromSrc(src);
|
||||
if (width || height) {
|
||||
node.setWidthAndHeight(width, height);
|
||||
}
|
||||
$insertNodes([node]);
|
||||
});
|
||||
|
||||
return true;
|
||||
|
Loading…
x
Reference in New Issue
Block a user