Skip to content

Commit 097ad2e

Browse files
committed
feat(hyper-link): add anchor options. (#525)
1 parent 194e2ee commit 097ad2e

File tree

1 file changed

+18
-9
lines changed

1 file changed

+18
-9
lines changed

extensions/hyper-link/src/index.ts

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const pathStr = `<svg viewBox="0 0 1024 1024" width="16" height="16" fill="curre
1515
export interface HyperLinkState {
1616
at: number;
1717
url: string;
18+
anchor: HyperLinkExtensionOptions['anchor'];
1819
}
1920

2021
class HyperLinkIcon extends WidgetType {
@@ -33,11 +34,12 @@ class HyperLinkIcon extends WidgetType {
3334
wrapper.innerHTML = pathStr;
3435
wrapper.className = 'cm-hyper-link-icon';
3536
wrapper.rel = 'nofollow';
36-
return wrapper;
37+
const anchor = this.state.anchor && this.state.anchor(wrapper);
38+
return anchor || wrapper;
3739
}
3840
}
3941

40-
function hyperLinkDecorations(view: EditorView) {
42+
function hyperLinkDecorations(view: EditorView, anchor?: HyperLinkExtensionOptions['anchor']) {
4143
const widgets: Array<Range<Decoration>> = [];
4244
for (const range of view.visibleRanges) {
4345
syntaxTree(view.state).iterate({
@@ -50,6 +52,7 @@ function hyperLinkDecorations(view: EditorView) {
5052
widget: new HyperLinkIcon({
5153
at: to,
5254
url: callExp,
55+
anchor,
5356
}),
5457
side: 1,
5558
});
@@ -61,7 +64,12 @@ function hyperLinkDecorations(view: EditorView) {
6164
return Decoration.set(widgets);
6265
}
6366

64-
const linkDecorator = (regexp?: RegExp, matchData?: Record<string, string>, matchFn?: (str: string) => string) =>
67+
const linkDecorator = (
68+
regexp?: RegExp,
69+
matchData?: Record<string, string>,
70+
matchFn?: (str: string) => string,
71+
anchor?: HyperLinkExtensionOptions['anchor'],
72+
) =>
6573
new MatchDecorator({
6674
regexp: regexp || /\b((?:https?|ftp):\/\/[^\s/$.?#].[^\s]*)\b/gi,
6775
decorate: (add, from, to, match, view) => {
@@ -72,36 +80,37 @@ const linkDecorator = (regexp?: RegExp, matchData?: Record<string, string>, matc
7280
}
7381
const start = to,
7482
end = to;
75-
const linkIcon = new HyperLinkIcon({ at: start, url: urlStr });
83+
const linkIcon = new HyperLinkIcon({ at: start, url: urlStr, anchor });
7684
add(start, end, Decoration.widget({ widget: linkIcon, side: 1 }));
7785
},
7886
});
7987

80-
export type hyperLinkExtensionOptions = {
88+
export type HyperLinkExtensionOptions = {
8189
regexp?: RegExp;
8290
match?: Record<string, string>;
8391
handle?: (value: string) => string;
92+
anchor?: (dom: HTMLAnchorElement) => HTMLAnchorElement;
8493
};
8594

86-
export function hyperLinkExtension({ regexp, match, handle }: hyperLinkExtensionOptions = {}) {
95+
export function hyperLinkExtension({ regexp, match, handle, anchor }: HyperLinkExtensionOptions = {}) {
8796
return ViewPlugin.fromClass(
8897
class HyperLinkView {
8998
decorator?: MatchDecorator;
9099
decorations: DecorationSet;
91100
constructor(view: EditorView) {
92101
if (regexp) {
93-
this.decorator = linkDecorator(regexp, match, handle);
102+
this.decorator = linkDecorator(regexp, match, handle, anchor);
94103
this.decorations = this.decorator.createDeco(view);
95104
} else {
96-
this.decorations = hyperLinkDecorations(view);
105+
this.decorations = hyperLinkDecorations(view, anchor);
97106
}
98107
}
99108
update(update: ViewUpdate) {
100109
if (update.docChanged || update.viewportChanged) {
101110
if (regexp && this.decorator) {
102111
this.decorations = this.decorator.updateDeco(update, this.decorations);
103112
} else {
104-
this.decorations = hyperLinkDecorations(update.view);
113+
this.decorations = hyperLinkDecorations(update.view, anchor);
105114
}
106115
}
107116
}

0 commit comments

Comments
 (0)