editor: expose link opening logic to clients (#969)

This commit is contained in:
Ammar Ahmed
2022-09-16 12:10:06 +05:00
committed by GitHub
parent 99b9dda47d
commit 686b38ca87
9 changed files with 119 additions and 9 deletions

View File

@@ -59,6 +59,7 @@ import { NoteType } from "../../../utils/types";
import { useDragState } from "../../settings/editor/state";
import { EditorMessage, EditorProps, useEditorType } from "./types";
import { EditorEvents, editorState } from "./utils";
import { openLinkInBrowser } from "../../../utils/functions";
export const EventTypes = {
selection: "editor-event:selection",
@@ -75,7 +76,8 @@ export const EventTypes = {
pro: "editor-event:pro",
monograph: "editor-event:monograph",
properties: "editor-event:properties",
fullscreen: "editor-event:fullscreen"
fullscreen: "editor-event:fullscreen",
link: "editor-event:link"
};
const publishNote = async (editor: useEditorType) => {
@@ -363,6 +365,9 @@ export const useEditorEvents = (
case EventTypes.back:
onBackPress();
break;
case EventTypes.link:
openLinkInBrowser(editorMessage.value as string);
break;
default:
break;
}

View File

@@ -202,6 +202,10 @@ function TipTap(props: TipTapProps) {
onDownloadAttachment: (_editor, attachment) => {
onDownloadAttachment?.(attachment);
return true;
},
onOpenLink: (url) => {
window.open(url, "_blank");
return true;
}
},
// IMPORTANT: only put stuff here that the editor depends on.

View File

@@ -88,7 +88,10 @@ const Tiptap = ({
content: global.editorController?.content?.current,
isMobile: true,
isKeyboardOpen: settings.keyboardShown,
doubleSpacedLines: settings.doubleSpacedLines
doubleSpacedLines: settings.doubleSpacedLines,
onOpenLink: (url) => {
return global.editorController.openLink(url);
}
},
[layout, settings.readonly, tick]
);

View File

@@ -61,6 +61,7 @@ export type EditorController = {
content: MutableRefObject<string | null>;
onUpdate: () => void;
titlePlaceholder: string;
openLink: (url: string) => boolean;
setTitlePlaceholder: React.Dispatch<React.SetStateAction<string>>;
};
@@ -154,6 +155,11 @@ export function useEditorController(update: () => void): EditorController {
post(EventTypes.download, attachment);
}, []);
const openLink = useCallback((url: string) => {
post(EventTypes.link, url);
return true;
}, []);
return {
contentChange,
selectionChange,
@@ -166,6 +172,7 @@ export function useEditorController(update: () => void): EditorController {
openFilePicker,
downloadAttachment,
content: htmlContentRef,
openLink,
onUpdate: onUpdate
};
}

View File

@@ -141,7 +141,8 @@ export const EventTypes = {
pro: "editor-event:pro",
monograph: "editor-event:monograph",
properties: "editor-event:properties",
fullscreen: "editor-event:fullscreen"
fullscreen: "editor-event:fullscreen",
link: "editor-event:link"
} as const;
export function isReactNative(): boolean {

View File

@@ -0,0 +1,21 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2022 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
export * from "./open-link";
export { OpenLink as default } from "./open-link";

View File

@@ -0,0 +1,51 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2022 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { Extension } from "@tiptap/core";
declare module "@tiptap/core" {
interface Commands<ReturnType> {
openlink: {
/**
* Open a link in browser
*/
openLink: (url: string) => ReturnType;
};
}
}
export type OpenLinkOptions = {
onOpenLink: (url: string) => boolean;
};
export const OpenLink = Extension.create<OpenLinkOptions>({
name: "openlink",
addOptions() {
return {
onOpenLink: () => false
};
},
addCommands() {
return {
openLink: (url: string) => () => {
return this.options.onOpenLink(url);
}
};
}
});

View File

@@ -71,15 +71,18 @@ import { Paragraph } from "./extensions/paragraph";
import { ClipboardTextSerializer } from "./extensions/clipboard-text-serializer";
import { Code } from "@tiptap/extension-code";
import { DateTime } from "./extensions/date-time";
import { OpenLink, OpenLinkOptions } from "./extensions/open-link";
import HorizontalRule from "@tiptap/extension-horizontal-rule";
const CoreExtensions = Object.entries(TiptapCoreExtensions)
// we will implement our own customized clipboard serializer
.filter(([name]) => name !== "ClipboardTextSerializer")
.map(([, extension]) => extension);
type TiptapOptions = EditorOptions &
AttachmentOptions & {
AttachmentOptions &
OpenLinkOptions & {
theme: Theme;
isMobile?: boolean;
isKeyboardOpen?: boolean;
@@ -97,6 +100,7 @@ const useTiptap = (
isKeyboardOpen,
onDownloadAttachment,
onOpenAttachmentPicker,
onOpenLink,
onBeforeCreate,
...restOptions
} = options;
@@ -201,7 +205,9 @@ const useTiptap = (
Placeholder.configure({
placeholder: "Start writing your note..."
}),
OpenLink.configure({
onOpenLink
}),
ImageNode.configure({ allowBase64: true }),
EmbedNode,
AttachmentNode.configure({
@@ -229,7 +235,8 @@ const useTiptap = (
onDownloadAttachment,
onOpenAttachmentPicker,
PortalProviderAPI,
onBeforeCreate
onBeforeCreate,
onOpenLink
]
);

View File

@@ -22,7 +22,7 @@ import { ToolButton } from "../components/tool-button";
import { useCallback, useRef, useState } from "react";
import { ResponsivePresenter } from "../../components/responsive";
import { LinkPopup } from "../popups/link-popup";
import { useToolbarLocation } from "../stores/toolbar-store";
import { useIsMobile, useToolbarLocation } from "../stores/toolbar-store";
import { MoreTools } from "../components/more-tools";
import { useRefValue } from "../../hooks/use-ref-value";
import { findMark, selectionToOffset } from "../utils/prosemirror";
@@ -207,13 +207,24 @@ export function OpenLink(props: ToolProps) {
return (
<Flex sx={{ alignItems: "center" }}>
<Link href={href} target="_blank" variant="body" sx={{ mr: 1 }}>
<Link
href={href}
onClick={(e) => {
e.preventDefault();
editor.commands.openLink(href);
}}
target="_blank"
variant="body"
sx={{ mr: 1 }}
>
{href}
</Link>
<ToolButton
{...props}
toggled={false}
onClick={() => window.open(href, "_blank")}
onClick={() => {
editor.commands.openLink(href);
}}
/>
</Flex>
);