@atlaskit/editor-plugin-hyperlink
Version:
Hyperlink plugin for @atlaskit/editor-core
122 lines (114 loc) • 5.66 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.createInputRulePlugin = createInputRulePlugin;
exports.createLinkInputRule = createLinkInputRule;
exports.default = void 0;
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _analytics = require("@atlaskit/editor-common/analytics");
var _card = require("@atlaskit/editor-common/card");
var _safePlugin = require("@atlaskit/editor-common/safe-plugin");
var _utils = require("@atlaskit/editor-common/utils");
var _prosemirrorInputRules = require("@atlaskit/prosemirror-input-rules");
var _toolbarButtons = require("./toolbar-buttons");
/**
* Called when space after link, but not on enter
*/
function createLinkInputRule(regexp, editorAnalyticsApi) {
// Plain typed text (eg, typing 'www.google.com') should convert to a hyperlink
return (0, _utils.createRule)(regexp, function (state, match, start, end) {
var _toolbarKey$getState$, _toolbarKey$getState;
var schema = state.schema;
if (state.doc.rangeHasMark(start, end, schema.marks.link)) {
return null;
}
var link = match;
// Property 'url' does not exist on type 'RegExpExecArray', the type of `match`.
// This check is in case the match is not a Linkify match, which has a url property.
if (link.url === undefined) {
return null;
}
if (!(0, _utils.shouldAutoLinkifyMatch)(link)) {
return null;
}
var url = (0, _utils.normalizeUrl)(link.url);
// Not previously handled; don't create a link if the URL is empty.
// This will only happen if the `regexp` matches more links than the normalizeUrl validation;
// if they both use the same linkify instance this shouldn't happen.
if (url === '') {
return null;
}
var markType = schema.mark('link', {
href: url
});
// Need access to complete text to check if last URL is part of a filepath before linkifying
var nodeBefore = state.selection.$from.nodeBefore;
if (!nodeBefore || !nodeBefore.isText || !nodeBefore.text) {
return null;
}
var filepaths = (0, _utils.findFilepaths)(nodeBefore.text,
// The position referenced by 'start' is relative to the start of the document, findFilepaths deals with index in a node only.
start - (nodeBefore.text.length - link.text.length) // (start of link match) - (whole node text length - link length) gets start of text node, which is used as offset
);
if ((0, _utils.isLinkInMatches)(start, filepaths)) {
var _tr = state.tr;
return _tr;
}
var from = start;
var to = Math.min(start + link.text.length, state.doc.content.size);
var tr = state.tr.addMark(from, to, markType);
// Keep old behavior that will delete the space after the link
if (to === end) {
tr.insertText(' ');
}
(0, _card.addLinkMetadata)(state.selection, tr, {
inputMethod: _analytics.INPUT_METHOD.AUTO_DETECT
});
var skipAnalytics = (_toolbarKey$getState$ = (_toolbarKey$getState = _toolbarButtons.toolbarKey.getState(state)) === null || _toolbarKey$getState === void 0 ? void 0 : _toolbarKey$getState.skipAnalytics) !== null && _toolbarKey$getState$ !== void 0 ? _toolbarKey$getState$ : false;
if (skipAnalytics) {
return tr;
}
editorAnalyticsApi === null || editorAnalyticsApi === void 0 || editorAnalyticsApi.attachAnalyticsEvent((0, _utils.getLinkCreationAnalyticsEvent)(_analytics.INPUT_METHOD.AUTO_DETECT, url))(tr);
return tr;
});
}
function createInputRulePlugin(schema, editorAnalyticsApi) {
var autoLinkOnBlur = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
if (!schema.marks.link) {
return;
}
var urlWithASpaceRule = createLinkInputRule(_utils.LinkMatcher.create(), editorAnalyticsApi);
// [something](link) should convert to a hyperlink
// eslint-disable-next-line require-unicode-regexp
var markdownLinkRule = (0, _utils.createRule)(/(^|[^!])\[(.*?)\]\((\S+)\)$/, function (state, match, start, end) {
var _toolbarKey$getState$2, _toolbarKey$getState2;
var schema = state.schema;
var _match = (0, _slicedToArray2.default)(match, 4),
prefix = _match[1],
linkText = _match[2],
linkUrl = _match[3];
// We don't filter this match here by shouldAutoLinkifyMatch
// because the intent of creating a link is clear
var url = (0, _utils.normalizeUrl)(linkUrl).trim();
var markType = schema.mark('link', {
href: url
});
var tr = state.tr.replaceWith(start + prefix.length, end, schema.text((linkText || '').trim(), [markType]));
(0, _card.addLinkMetadata)(state.selection, tr, {
inputMethod: _analytics.INPUT_METHOD.FORMATTING
});
var skipAnalytics = (_toolbarKey$getState$2 = (_toolbarKey$getState2 = _toolbarButtons.toolbarKey.getState(state)) === null || _toolbarKey$getState2 === void 0 ? void 0 : _toolbarKey$getState2.skipAnalytics) !== null && _toolbarKey$getState$2 !== void 0 ? _toolbarKey$getState$2 : false;
if (skipAnalytics) {
return tr;
}
editorAnalyticsApi === null || editorAnalyticsApi === void 0 || editorAnalyticsApi.attachAnalyticsEvent((0, _utils.getLinkCreationAnalyticsEvent)(_analytics.INPUT_METHOD.FORMATTING, url))(tr);
return tr;
});
return new _safePlugin.SafePlugin((0, _prosemirrorInputRules.createPlugin)('hyperlink', [urlWithASpaceRule, markdownLinkRule], autoLinkOnBlur ? {
checkOnBlur: true,
appendTextOnBlur: ' '
} : undefined));
}
var _default = exports.default = createInputRulePlugin;