mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-09-06 08:50:50 +08:00
feat(editor): allow embedding any iframes (#12895)
fix BS-3606 #### PR Dependency Tree * **PR #12892** * **PR #12895** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Introduced support for embedding generic iframes with customizable dimensions and permissions, while ensuring only secure, non-AFFiNE URLs are allowed. * Enhanced embedding options by prioritizing custom embed blocks over iframe blocks for a richer embedding experience across toolbars and link actions. * Added URL validation to support secure and flexible embedding configurations. * **Bug Fixes** * Improved iframe embedding reliability by removing restrictive HTTP headers and certain Content Security Policy directives that could block iframe usage in the Electron app. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
canEmbedAsEmbedBlock,
|
||||
canEmbedAsIframe,
|
||||
EMBED_IFRAME_DEFAULT_HEIGHT_IN_SURFACE,
|
||||
EMBED_IFRAME_DEFAULT_WIDTH_IN_SURFACE,
|
||||
@@ -149,13 +150,10 @@ const builtinToolbarConfig = {
|
||||
if (!model) return true;
|
||||
|
||||
const url = model.props.url;
|
||||
// check if the url can be embedded as iframe block or other embed blocks
|
||||
const options = ctx.std
|
||||
.get(EmbedOptionProvider)
|
||||
.getEmbedBlockOptions(url);
|
||||
|
||||
return (
|
||||
!canEmbedAsIframe(ctx.std, url) && options?.viewType !== 'embed'
|
||||
!canEmbedAsIframe(ctx.std, url) &&
|
||||
!canEmbedAsEmbedBlock(ctx.std, url)
|
||||
);
|
||||
},
|
||||
run(ctx) {
|
||||
@@ -169,15 +167,8 @@ const builtinToolbarConfig = {
|
||||
|
||||
let blockId: string | undefined;
|
||||
|
||||
// first try to embed as iframe block
|
||||
if (canEmbedAsIframe(ctx.std, url)) {
|
||||
const embedIframeService = ctx.std.get(EmbedIframeService);
|
||||
blockId = embedIframeService.addEmbedIframeBlock(
|
||||
{ url, caption, title, description },
|
||||
parent.id,
|
||||
index
|
||||
);
|
||||
} else {
|
||||
// first try to embed as a custom embed block
|
||||
if (canEmbedAsEmbedBlock(ctx.std, url)) {
|
||||
const options = ctx.std
|
||||
.get(EmbedOptionProvider)
|
||||
.getEmbedBlockOptions(url);
|
||||
@@ -202,6 +193,13 @@ const builtinToolbarConfig = {
|
||||
parent,
|
||||
index
|
||||
);
|
||||
} else if (canEmbedAsIframe(ctx.std, url)) {
|
||||
const embedIframeService = ctx.std.get(EmbedIframeService);
|
||||
blockId = embedIframeService.addEmbedIframeBlock(
|
||||
{ url, caption, title, description },
|
||||
parent.id,
|
||||
index
|
||||
);
|
||||
}
|
||||
|
||||
if (!blockId) return;
|
||||
@@ -379,27 +377,8 @@ const builtinSurfaceToolbarConfig = {
|
||||
|
||||
let newId: string | undefined;
|
||||
|
||||
// first try to embed as iframe block
|
||||
if (canEmbedAsIframe(ctx.std, url)) {
|
||||
const embedIframeService = ctx.std.get(EmbedIframeService);
|
||||
const config = embedIframeService.getConfig(url);
|
||||
if (!config) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bound = Bound.deserialize(xywh);
|
||||
const options = config.options;
|
||||
const { widthInSurface, heightInSurface } = options ?? {};
|
||||
bound.w = widthInSurface ?? EMBED_IFRAME_DEFAULT_WIDTH_IN_SURFACE;
|
||||
bound.h =
|
||||
heightInSurface ?? EMBED_IFRAME_DEFAULT_HEIGHT_IN_SURFACE;
|
||||
|
||||
newId = ctx.store.addBlock(
|
||||
'affine:embed-iframe',
|
||||
{ url, caption, title, description, xywh: bound.serialize() },
|
||||
parent
|
||||
);
|
||||
} else {
|
||||
// first try to embed as a custom embed block
|
||||
if (canEmbedAsEmbedBlock(ctx.std, url)) {
|
||||
const options = ctx.std
|
||||
.get(EmbedOptionProvider)
|
||||
.getEmbedBlockOptions(url);
|
||||
@@ -429,8 +408,29 @@ const builtinSurfaceToolbarConfig = {
|
||||
},
|
||||
parent
|
||||
);
|
||||
} else if (canEmbedAsIframe(ctx.std, url)) {
|
||||
const embedIframeService = ctx.std.get(EmbedIframeService);
|
||||
const config = embedIframeService.getConfig(url);
|
||||
if (!config) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bound = Bound.deserialize(xywh);
|
||||
const options = config.options;
|
||||
const { widthInSurface, heightInSurface } = options ?? {};
|
||||
bound.w = widthInSurface ?? EMBED_IFRAME_DEFAULT_WIDTH_IN_SURFACE;
|
||||
bound.h =
|
||||
heightInSurface ?? EMBED_IFRAME_DEFAULT_HEIGHT_IN_SURFACE;
|
||||
|
||||
newId = ctx.store.addBlock(
|
||||
'affine:embed-iframe',
|
||||
{ url, caption, title, description, xywh: bound.serialize() },
|
||||
parent
|
||||
);
|
||||
}
|
||||
|
||||
if (!newId) return;
|
||||
|
||||
ctx.command.exec(reassociateConnectorsCommand, { oldId, newId });
|
||||
|
||||
ctx.store.deleteBlock(model);
|
||||
@@ -449,13 +449,10 @@ const builtinSurfaceToolbarConfig = {
|
||||
when(ctx) {
|
||||
const model = ctx.getCurrentModelByType(BookmarkBlockModel);
|
||||
if (!model) return false;
|
||||
|
||||
const { url } = model.props;
|
||||
const options = ctx.std
|
||||
.get(EmbedOptionProvider)
|
||||
.getEmbedBlockOptions(url);
|
||||
|
||||
return canEmbedAsIframe(ctx.std, url) || options?.viewType === 'embed';
|
||||
return (
|
||||
canEmbedAsIframe(ctx.std, url) || canEmbedAsEmbedBlock(ctx.std, url)
|
||||
);
|
||||
},
|
||||
content(ctx) {
|
||||
const model = ctx.getCurrentModelByType(BookmarkBlockModel);
|
||||
|
||||
Reference in New Issue
Block a user