Lexical: Media form improvements
Some checks failed
test-js / build (push) Has been cancelled

- Allowed re-editing of existing embed HTML code.
- Handled "src" form field when video is using child source tags.
This commit is contained in:
Dan Brown
2025-06-15 20:00:28 +01:00
parent 1611b0399f
commit b913ae703d
4 changed files with 46 additions and 6 deletions

View File

@ -14,7 +14,6 @@ import {
setCommonBlockPropsFromElement,
updateElementWithCommonBlockProps
} from "lexical/nodes/common";
import {$selectSingleNode} from "../../utils/selection";
import {SerializedCommonBlockNode} from "lexical/nodes/CommonBlockNode";
export type MediaNodeTag = 'iframe' | 'embed' | 'object' | 'video' | 'audio';
@ -141,16 +140,26 @@ export class MediaNode extends ElementNode {
getSources(): MediaNodeSource[] {
const self = this.getLatest();
return self.__sources;
return self.__sources.map(s => Object.assign({}, s))
}
setSrc(src: string): void {
const attrs = this.getAttributes();
const sources = this.getSources();
if (this.__tag ==='object') {
attrs.data = src;
} if (this.__tag === 'video' && sources.length > 0) {
sources[0].src = src;
delete attrs.src;
if (sources.length > 1) {
sources.splice(1, sources.length - 1);
}
this.setSources(sources);
} else {
attrs.src = src;
}
this.setAttributes(attrs);
}

View File

@ -28,4 +28,19 @@ describe('LexicalMediaNode', () => {
});
});
test('setSrc on video uses sources if existing', () => {
const {editor} = createTestContext();
editor.updateAndCommit(() => {
const mediaMode = $createMediaNode('video');
mediaMode.setAttributes({src: 'z'});
mediaMode.setSources([{src: 'a', type: 'video'}, {src: 'b', type: 'video'}]);
mediaMode.setSrc('c');
expect(mediaMode.getAttributes().src).toBeUndefined();
expect(mediaMode.getSources()).toHaveLength(1);
expect(mediaMode.getSources()[0].src).toBe('c');
});
});
});

View File

@ -192,11 +192,17 @@ export function $showMediaForm(media: MediaNode|null, context: EditorUiContext):
let formDefaults = {};
if (media) {
const nodeAttrs = media.getAttributes();
const nodeDOM = media.exportDOM(context.editor).element;
const nodeHtml = (nodeDOM instanceof HTMLElement) ? nodeDOM.outerHTML : '';
formDefaults = {
src: nodeAttrs.src || nodeAttrs.data || '',
src: nodeAttrs.src || nodeAttrs.data || media.getSources()[0]?.src || '',
width: nodeAttrs.width,
height: nodeAttrs.height,
embed: '',
embed: nodeHtml,
// This is used so we can check for edits against the embed field on submit
embed_check: nodeHtml,
}
}
@ -214,7 +220,8 @@ export const media: EditorFormDefinition = {
}));
const embedCode = (formData.get('embed') || '').toString().trim();
if (embedCode) {
const embedCheck = (formData.get('embed_check') || '').toString().trim();
if (embedCode && embedCode !== embedCheck) {
context.editor.update(() => {
const node = $createMediaNodeFromHtml(embedCode);
if (selectedNode && node) {
@ -236,6 +243,7 @@ export const media: EditorFormDefinition = {
if (selectedNode) {
selectedNode.setSrc(src);
selectedNode.setWidthAndHeight(width, height);
context.manager.triggerFutureStateRefresh();
return;
}
@ -281,6 +289,11 @@ export const media: EditorFormDefinition = {
name: 'embed',
type: 'textarea',
},
{
label: '',
name: 'embed_check',
type: 'hidden',
},
],
}
])

View File

@ -11,7 +11,7 @@ import {el} from "../../utils/dom";
export interface EditorFormFieldDefinition {
label: string;
name: string;
type: 'text' | 'select' | 'textarea' | 'checkbox';
type: 'text' | 'select' | 'textarea' | 'checkbox' | 'hidden';
}
export interface EditorSelectFormFieldDefinition extends EditorFormFieldDefinition {
@ -67,6 +67,9 @@ export class EditorFormField extends EditorUiElement {
input = el('textarea', {id, name: this.definition.name, class: 'editor-form-field-input'});
} else if (this.definition.type === 'checkbox') {
input = el('input', {id, name: this.definition.name, type: 'checkbox', class: 'editor-form-field-input-checkbox', value: 'true'});
} else if (this.definition.type === 'hidden') {
input = el('input', {id, name: this.definition.name, type: 'hidden'});
return el('div', {hidden: 'true'}, [input]);
} else {
input = el('input', {id, name: this.definition.name, class: 'editor-form-field-input'});
}