feat: Handle pasting iframe for supported embed

This commit is contained in:
Tom Moor
2023-08-12 11:44:16 +02:00
parent f4e4992508
commit 9749a53558
2 changed files with 44 additions and 6 deletions

View File

@@ -9,9 +9,13 @@ import isInCode from "../queries/isInCode";
import isInList from "../queries/isInList";
import { LANGUAGES } from "./Prism";
/**
* Checks if the HTML string is likely coming from Dropbox Paper.
*
* @param html The HTML string to check.
* @returns True if the HTML string is likely coming from Dropbox Paper.
*/
function isDropboxPaper(html: string): boolean {
// The best we have to detect if a paste is likely coming from Paper
// In this case it's actually better to use the text version
return html?.includes("usually-unique-id");
}
@@ -23,6 +27,34 @@ function sliceSingleNode(slice: Slice) {
: null;
}
/**
* Parses the text contents of an HTML string and returns the src of the first
* iframe if it exists.
*
* @param text The HTML string to parse.
* @returns The src of the first iframe if it exists, or undefined.
*/
function parseSingleIframeSrc(html: string) {
try {
const parser = new DOMParser();
const doc = parser.parseFromString(html, "text/html");
if (
doc.body.children.length === 1 &&
doc.body.firstElementChild?.tagName === "IFRAME"
) {
const iframe = doc.body.firstElementChild;
const src = iframe.getAttribute("src");
if (src) {
return src;
}
}
} catch (e) {
// Ignore the million ways parsing could fail.
}
return undefined;
}
export default class PasteHandler extends Extension {
get name() {
return "paste-handler";
@@ -65,10 +97,16 @@ export default class PasteHandler extends Extension {
return false;
}
const text = event.clipboardData.getData("text/plain");
const { state, dispatch } = view;
const iframeSrc = parseSingleIframeSrc(
event.clipboardData.getData("text/plain")
);
const text =
iframeSrc && !isInCode(state)
? iframeSrc
: event.clipboardData.getData("text/plain");
const html = event.clipboardData.getData("text/html");
const vscode = event.clipboardData.getData("vscode-editor-data");
const { state, dispatch } = view;
// first check if the clipboard contents can be parsed as a single
// url, this is mainly for allowing pasted urls to become embeds

View File

@@ -27,7 +27,7 @@ export default class Embed extends Node {
},
parseDOM: [
{
tag: "iframe.embed",
tag: "iframe",
getAttrs: (dom: HTMLIFrameElement) => {
const { embeds } = this.editor.props;
const href = dom.getAttribute("src") || "";
@@ -43,7 +43,7 @@ export default class Embed extends Node {
}
}
return {};
return false;
},
},
],