Path: blob/master/src/packages/frontend/editors/slate/elements/link/editable.tsx
1698 views
/*1* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.2* License: MS-RSL – see LICENSE.md for details3*/45import { Text } from "slate";6import { register } from "../register";7import { useProcessLinks } from "../hooks";8import { open_new_tab } from "@cocalc/frontend/misc";9const linkify = require("linkify-it")();10import { Link, LINK_STYLE } from "./index";11import { Tooltip } from "antd";1213register({14slateType: "link",1516Element: ({ attributes, children, element }) => {17const node = element as Link;18const { url, title } = node;19const ref = useProcessLinks([url], { doubleClick: true });20return (21<span {...attributes}>22<span ref={ref}>23<Tooltip title={url ? `Double click to open ${url}...` : undefined}>24<a25href={url}26title={title}27onDoubleClick={() => {28if (url) {29open_new_tab(url);30}31}}32style={LINK_STYLE}33>34{children}35{element.children.length == 1 &&36Text.isText(element.children[0]) &&37!element.children[0].text.trim() && (38<span contentEditable={false}>(blank link)</span>39)}40</a>41</Tooltip>42</span>43</span>44);45},4647fromSlate: ({ node, children, info }) => {48let url = node.url ?? "";49if (info.references != null) {50// might be able to use a reference link; if so, we will.51for (const name in info.references) {52if (info.references[name].href == url) {53// get to use this.54const c = `${children}`;55if (c.toLowerCase() == name.toLowerCase()) {56return `[${c}]`;57}58return `[${children}][${name}]`;59}60}61}6263// [my website](wstein.org "here")64let title = node.title ?? "";65if (title.length > 0) {66title = ` \"${title}\"`;67}68if (title == "" && children == url && linkify.test(url)) {69// special case where the url is easily parsed by the linkify plugin,70// and there is no title.71return url;72} else {73if (/\s/.test(url)) {74// See https://superuser.com/questions/1170654/how-do-i-add-a-hyperlink-with-spaces-in-it-using-markdown75url = `<${url}>`;76}77return `[${children}](${url}${title})`;78}79},80});8182// This is a workaround for https://github.com/ianstormtaylor/slate/issues/377283import { Editor, Element, Path, Range, Transforms } from "slate";8485export const withInsertBreakHack = (editor) => {86const { insertBreak } = editor;8788editor.insertBreak = () => {89let selectedElement, path;90try {91[selectedElement, path] = Editor.parent(editor, editor.selection);92} catch (_err) {93// document is empty so no need to do this workaround.94insertBreak();95return;96}9798if (Element.isElement(selectedElement) && selectedElement.type === "link") {99const endPoint = Range.end(editor.selection);100const [selectedLeaf] = Editor.node(editor, endPoint);101if (102Text.isText(selectedLeaf) &&103selectedLeaf.text.length === endPoint.offset104) {105if (Range.isExpanded(editor.selection)) {106Transforms.delete(editor);107}108Transforms.select(editor, Path.next(path));109}110}111insertBreak();112};113114return editor;115};116117118