I’m trying to make a MatchDecorator
that will either make URLs clickable (ideally) or add a link icon after URLs that is clickable.
This will replace the URL with a link icon:
const linkDecorator = new MatchDecorator({
regexp: /https?:\/\/[a-z0-9\._/~%\-\+&\#\?!=\(\)@]*/ig,
decoration: (match, view) => {
const url = match[0];
return Decoration.widget({widget: new HyperLink({from: start, to: end, url})});
},
});
And this will make a link that isn’t clickable (due to links not being clickable in contenteditable):
const linkDecorator = new MatchDecorator({
regexp: /https?:\/\/[a-z0-9\._/~%\-\+&\#\?!=\(\)@]*/ig,
decoration: (match, view) => {
const url = match[0];
return Decoration.mark({
tagName: 'a',
attributes: {
href: url,
rel: "nofollow",
class: "cm-link",
target: "_blank",
}
});
},
});
With a MatchDecorator
is there a way to avoid replacing the match and instead add a widget just after the match?
Thanks!
marijn
2
Does this patch look like it would solve this?
1 Like
That worked great. Thanks @marijn!

For looking to add a link icon after each URL, here’s what I did:
class HyperLink extends WidgetType {
constructor(state) {
super();
this.state = state;
}
eq(other) {
return (
this.state.url === other.state.url
&& this.state.at === other.state.at
);
}
toDOM() {
const wrapper = document.createElement('a');
wrapper.href = this.state.url;
wrapper.target = "_blank";
wrapper.innerHTML = `<i class="fas fa-link mx-1"></i>`;
wrapper.className = "cm-link";
wrapper.rel = "nofollow";
return wrapper;
}
};
const linkDecorator = new MatchDecorator({
regexp: /https?:\/\/[a-z0-9\._/~%\-\+&\#\?!=\(\)@]*/ig,
decorate: (add, from, to, match, view) => {
const url = match[0];
const start = to, end = to;
const linkIcon = new HyperLink({at: start, url});
add(start, end, Decoration.widget({widget: linkIcon, side: 1}));
},
});
const urlPlugin = ViewPlugin.fromClass(
class URLView {
constructor(view) {
this.decorator = linkDecorator;
this.decorations = this.decorator.createDeco(view);
}
update(update) {
if (update.docChanged || update.viewportChanged) {
this.decorations = this.decorator.updateDeco(update, this.decorations);
}
}
}, {decorations: v => v.decorations}
);
Example here and here
1 Like