mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-08 04:36:13 +08:00
fix(editor): should add HTTP protocol into link automatically (#11934)
Closes: [BS-3291](https://linear.app/affine-design/issue/BS-3291/工具栏展开时报错,链接无法点击打开) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - URLs entered without a protocol (e.g., "github.com/...") are now automatically normalized to use "https://", ensuring links are secure and consistently formatted. - **Bug Fixes** - Improved handling and validation of links to prevent issues with missing or invalid protocols in bookmarks and inline links. - Simplified URL validation logic by leveraging native URL parsing, removing complex regex and email-specific checks. - Streamlined toolbar link actions to operate only on valid normalized URLs. - Refined URL detection in markdown preprocessing to exclude lines containing spaces from being treated as URLs. - **Tests** - Added tests to verify that links without a protocol are correctly normalized and displayed across different views. - Updated URL validation tests to better reflect valid and invalid URL formats, including IP addresses and domain variants. - **Style** - Updated snapshots to reflect the use of "https://" in links. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -7,6 +7,7 @@ import {
|
||||
} from '@blocksuite/affine-shared/services';
|
||||
import { affineTextStyles } from '@blocksuite/affine-shared/styles';
|
||||
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
|
||||
import { normalizeUrl } from '@blocksuite/affine-shared/utils';
|
||||
import { WithDisposable } from '@blocksuite/global/lit';
|
||||
import type { BlockComponent, BlockStdScope } from '@blocksuite/std';
|
||||
import { BLOCK_ID_ATTR, ShadowlessElement } from '@blocksuite/std';
|
||||
@@ -120,7 +121,7 @@ export class AffineLink extends WithDisposable(ShadowlessElement) {
|
||||
}
|
||||
|
||||
get link() {
|
||||
return this.delta.attributes?.link ?? '';
|
||||
return normalizeUrl(this.delta.attributes?.link ?? '');
|
||||
}
|
||||
|
||||
get selfInlineRange() {
|
||||
|
||||
@@ -38,6 +38,7 @@ export const builtinInlineLinkToolbarConfig = {
|
||||
if (!(target instanceof AffineLink)) return null;
|
||||
|
||||
const { link } = target;
|
||||
if (!link) return null;
|
||||
|
||||
return html`<affine-link-preview .url=${link}></affine-link-preview>`;
|
||||
},
|
||||
@@ -115,6 +116,9 @@ export const builtinInlineLinkToolbarConfig = {
|
||||
if (!(target instanceof AffineLink)) return;
|
||||
if (!target.block) return;
|
||||
|
||||
const url = target.link;
|
||||
if (!url) return;
|
||||
|
||||
const {
|
||||
block: { model },
|
||||
inlineEditor,
|
||||
@@ -124,9 +128,6 @@ export const builtinInlineLinkToolbarConfig = {
|
||||
|
||||
if (!inlineEditor || !selfInlineRange || !parent) return;
|
||||
|
||||
const url = inlineEditor.getFormat(selfInlineRange).link;
|
||||
if (!url) return;
|
||||
|
||||
// Clears
|
||||
ctx.reset();
|
||||
|
||||
@@ -182,6 +183,9 @@ export const builtinInlineLinkToolbarConfig = {
|
||||
if (!(target instanceof AffineLink)) return false;
|
||||
if (!target.block) return false;
|
||||
|
||||
const url = target.link;
|
||||
if (!url) return false;
|
||||
|
||||
const {
|
||||
block: { model },
|
||||
inlineEditor,
|
||||
@@ -191,9 +195,6 @@ export const builtinInlineLinkToolbarConfig = {
|
||||
|
||||
if (!inlineEditor || !selfInlineRange || !parent) return false;
|
||||
|
||||
const url = inlineEditor.getFormat(selfInlineRange).link;
|
||||
if (!url) return false;
|
||||
|
||||
// check if the url can be embedded as iframe block
|
||||
const embedIframeService = ctx.std.get(EmbedIframeService);
|
||||
const canEmbedAsIframe = embedIframeService.canEmbed(url);
|
||||
@@ -208,6 +209,9 @@ export const builtinInlineLinkToolbarConfig = {
|
||||
if (!(target instanceof AffineLink)) return;
|
||||
if (!target.block) return;
|
||||
|
||||
const url = target.link;
|
||||
if (!url) return;
|
||||
|
||||
const {
|
||||
block: { model },
|
||||
inlineEditor,
|
||||
@@ -217,9 +221,6 @@ export const builtinInlineLinkToolbarConfig = {
|
||||
|
||||
if (!inlineEditor || !selfInlineRange || !parent) return;
|
||||
|
||||
const url = inlineEditor.getFormat(selfInlineRange).link;
|
||||
if (!url) return;
|
||||
|
||||
// Clears
|
||||
ctx.reset();
|
||||
|
||||
@@ -306,16 +307,7 @@ export const builtinInlineLinkToolbarConfig = {
|
||||
)
|
||||
return false;
|
||||
|
||||
const { link } = target;
|
||||
try {
|
||||
const url = new URL(link);
|
||||
if (!url.protocol.startsWith('http')) {
|
||||
return false;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return false;
|
||||
}
|
||||
if (!target.link.startsWith('http')) return false;
|
||||
|
||||
const { model } = target.block;
|
||||
const parent = model.parent;
|
||||
|
||||
Reference in New Issue
Block a user