@atlaskit/editor-plugin-hyperlink
Version:
Hyperlink plugin for @atlaskit/editor-core
93 lines (90 loc) • 4.09 kB
JavaScript
import { getLinkMatch } from '@atlaskit/adf-schema';
import { INPUT_METHOD } from '@atlaskit/editor-common/analytics';
import { addLinkMetadata } from '@atlaskit/editor-common/card';
import { addLink, bindKeymapWithCommand, bindKeymapWithEditorCommand, enter, escape, insertNewLine } from '@atlaskit/editor-common/keymaps';
import { findFilepaths, getLinkCreationAnalyticsEvent, isLinkInMatches, shouldAutoLinkifyMatch } from '@atlaskit/editor-common/utils';
import { keymap } from '@atlaskit/editor-prosemirror/keymap';
import { hideLinkToolbar, showLinkToolbar } from '../editor-commands/commands';
import { stateKey } from '../pm-plugins/main';
import { toolbarKey } from './toolbar-buttons';
export function createKeymapPlugin(editorAnalyticsApi) {
const list = {};
bindKeymapWithEditorCommand(
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
addLink.common, showLinkToolbar(INPUT_METHOD.SHORTCUT, editorAnalyticsApi), list);
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
bindKeymapWithCommand(enter.common, mayConvertLastWordToHyperlink(editorAnalyticsApi), list);
bindKeymapWithCommand(
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
insertNewLine.common, mayConvertLastWordToHyperlink(editorAnalyticsApi), list);
bindKeymapWithCommand(
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
escape.common, (state, dispatch, view) => {
const hyperlinkPlugin = stateKey.getState(state);
if (hyperlinkPlugin.activeLinkMark) {
hideLinkToolbar()(state, dispatch);
if (view) {
view.focus();
}
return false;
}
return false;
}, list);
return keymap(list);
}
/**
* Convert the last word before the selection to a hyperlink if it's a valid URL with a tld we want to linkify
*/
const mayConvertLastWordToHyperlink = editorAnalyticsApi => {
return function (state, dispatch) {
var _toolbarKey$getState$, _toolbarKey$getState;
const skipAnalytics = (_toolbarKey$getState$ = (_toolbarKey$getState = toolbarKey.getState(state)) === null || _toolbarKey$getState === void 0 ? void 0 : _toolbarKey$getState.skipAnalytics) !== null && _toolbarKey$getState$ !== void 0 ? _toolbarKey$getState$ : false;
const nodeBefore = state.selection.$from.nodeBefore;
if (!nodeBefore || !nodeBefore.isText || !nodeBefore.text) {
return false;
}
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const words = nodeBefore.text.split(' ');
const lastWord = words[words.length - 1];
const match = getLinkMatch(lastWord);
if (match) {
if (!shouldAutoLinkifyMatch(match)) {
return false;
}
const hyperlinkedText = match.raw;
const start = state.selection.$from.pos - hyperlinkedText.length;
const end = state.selection.$from.pos;
if (state.doc.rangeHasMark(start, end, state.schema.marks.link)) {
return false;
}
const url = match.url;
const markType = state.schema.mark('link', {
href: url
});
const filepaths = findFilepaths(nodeBefore.text, start - (nodeBefore.text.length - hyperlinkedText.length) // The position referenced by 'start' is relative to the start of the document, findFilepaths deals with index in a node only.
);
if (isLinkInMatches(start, filepaths)) {
return false;
}
const tr = state.tr.addMark(start, end, markType);
if (dispatch) {
addLinkMetadata(state.selection, tr, {
inputMethod: INPUT_METHOD.AUTO_DETECT
});
if (skipAnalytics) {
dispatch(tr);
} else {
editorAnalyticsApi === null || editorAnalyticsApi === void 0 ? void 0 : editorAnalyticsApi.attachAnalyticsEvent(getLinkCreationAnalyticsEvent(INPUT_METHOD.AUTO_DETECT, url))(tr);
dispatch(tr);
}
}
}
return false;
};
};
export default createKeymapPlugin;