mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-23 23:19:40 +01:00
editor: expose link opening logic to clients (#969)
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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]
|
||||
);
|
||||
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
21
packages/editor/src/extensions/open-link/index.ts
Normal file
21
packages/editor/src/extensions/open-link/index.ts
Normal 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";
|
||||
51
packages/editor/src/extensions/open-link/open-link.ts
Normal file
51
packages/editor/src/extensions/open-link/open-link.ts
Normal 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);
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
@@ -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
|
||||
]
|
||||
);
|
||||
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user