diff --git a/apps/mobile/app/components/sheets/editor-tabs/index.tsx b/apps/mobile/app/components/sheets/editor-tabs/index.tsx
index cfd740b04..e52f56ea0 100644
--- a/apps/mobile/app/components/sheets/editor-tabs/index.tsx
+++ b/apps/mobile/app/components/sheets/editor-tabs/index.tsx
@@ -16,8 +16,8 @@ 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 .
*/
-import { Note } from "@notesnook/core";
-import { EVENTS } from "@notesnook/core";
+import { EVENTS, Note } from "@notesnook/core";
+import { strings } from "@notesnook/intl";
import { useThemeColors } from "@notesnook/theme";
import React, { useEffect } from "react";
import { View } from "react-native";
@@ -33,12 +33,10 @@ import { editorController } from "../../../screens/editor/tiptap/utils";
import { eSendEvent, presentSheet } from "../../../services/event-manager";
import { eUnlockNote } from "../../../utils/events";
import { SIZE } from "../../../utils/size";
-import { Button } from "../../ui/button";
import { IconButton } from "../../ui/icon-button";
import { Pressable } from "../../ui/pressable";
import Heading from "../../ui/typography/heading";
import Paragraph from "../../ui/typography/paragraph";
-import { strings } from "@notesnook/intl";
const TabItemComponent = (props: {
tab: TabItem;
diff --git a/apps/mobile/app/screens/editor/tiptap/commands.ts b/apps/mobile/app/screens/editor/tiptap/commands.ts
index 061c11bdb..50ab1429b 100644
--- a/apps/mobile/app/screens/editor/tiptap/commands.ts
+++ b/apps/mobile/app/screens/editor/tiptap/commands.ts
@@ -18,9 +18,11 @@ along with this program. If not, see .
*/
import { Note } from "@notesnook/core";
-import type { Attachment } from "@notesnook/editor";
-import type { ImageAttributes } from "@notesnook/editor";
-import type { LinkAttributes } from "@notesnook/editor";
+import type {
+ Attachment,
+ ImageAttributes,
+ LinkAttributes
+} from "@notesnook/editor";
import { createRef, RefObject } from "react";
import { Platform } from "react-native";
import { EdgeInsets } from "react-native-safe-area-context";
@@ -37,9 +39,6 @@ async function call(webview: RefObject, action?: Action) {
if (!webview.current || !action) return;
setImmediate(() => webview.current?.injectJavaScript(action.job));
const response = await getResponse(action.id);
- // if (!response) {
- // console.warn("webview job failed", action.id);
- // }
return response ? response.value : response;
}
@@ -75,6 +74,17 @@ class Commands {
return call(this.ref, fn(job, name)) as Promise;
}
+ async sendCommand(command: string, ...args: any[]) {
+ return this.doAsync(
+ `response = globalThis.commands.${command}(${args
+ .map((arg) =>
+ typeof arg === "string" ? `"${arg}"` : JSON.stringify(arg)
+ )
+ .join(",")})`,
+ command
+ );
+ }
+
focus = async (tabId: string) => {
if (!this.ref.current) return;
@@ -84,107 +94,45 @@ class Commands {
setTimeout(async () => {
if (!this.ref) return;
textInput.current?.focus();
- await this.doAsync(
- locked
- ? `editorControllers["${tabId}"]?.focusPassInput();`
- : `editors["${tabId}"]?.commands.focus()`,
- "focus"
- );
-
+ await this.sendCommand("focus", tabId, locked);
this.ref?.current?.requestFocus();
}, 1);
} else {
await sleep(400);
- await this.doAsync(
- locked
- ? `editorControllers["${tabId}"]?.focusPassInput();`
- : `editors["${tabId}"]?.commands.focus()`,
- "focus"
- );
+ await this.sendCommand("focus", tabId, locked);
}
};
- blur = async (tabId: string) =>
- await this.doAsync(
- `
- const editor = editors["${tabId}"];
- const editorTitle = editorTitles["${tabId}"];
- typeof editor !== "undefined" && editor.commands.blur();
- typeof editorTitle !== "undefined" && editorTitle.current && editorTitle.current.blur();
-
- editorControllers["${tabId}"]?.blurPassInput();
-
- `,
- "blur"
- );
+ blur = async (tabId: string) => this.sendCommand("blur", tabId);
clearContent = async (tabId: string) => {
this.previousSettings = null;
- await this.doAsync(
- `
-const editor = editors["${tabId}"];
-const editorController = editorControllers["${tabId}"];
-const editorTitle = editorTitles["${tabId}"];
-const statusBar = statusBars["${tabId}"];
-
-if (typeof editor !== "undefined") {
- editor.commands.blur();
- editor.commands.clearContent(false);
-}
-
-typeof editorTitle !== "undefined" && editorTitle.current && editorTitle.current?.blur();
-if (typeof editorController.content !== undefined) editorController.content.current = '';
-editorController.onUpdate();
-editorController.setTitle('');
-if (typeof statusBar !== "undefined") {
- statusBar.current.resetWords();
- statusBar.current.set({date:"",saved:""});
-}`,
- "clearContent"
- );
+ await this.sendCommand("clearContent", tabId);
};
setSessionId = async (id: string | null) =>
- await this.doAsync(`globalThis.sessionId = "${id}";`);
+ await this.sendCommand("setSessionId", id);
setStatus = async (
date: string | undefined,
saved: string,
tabId: string
) => {
- await this.doAsync(
- `
- const statusBar = statusBars["${tabId}"];
- typeof statusBar !== "undefined" && statusBar.current.set({date:"${date}",saved:"${saved}"})`,
- "setStatus"
+ this.sendCommand("setStatus", date, saved, tabId);
+ };
+
+ setPlaceholder = async (placeholder: string) => {};
+
+ setLoading = async (loading?: boolean, tabId?: string) => {
+ this.sendCommand(
+ "setLoading",
+ loading,
+ tabId === undefined ? useTabStore.getState().currentTab : tabId
);
};
- setPlaceholder = async (placeholder: string) => {
- // await this.doAsync(`
- // const element = document.querySelector(".is-editor-empty");
- // if (element) {
- // element.setAttribute("data-placeholder","${placeholder}");
- // }
- // `);
- };
-
- setLoading = async (loading?: boolean, tabId?: string) => {
- await this.doAsync(`
- const editorController = editorControllers["${
- tabId === undefined ? useTabStore.getState().currentTab : tabId
- }"];
- editorController.setLoading(${loading})
- logger("info", editorController.setLoading);
- `);
- };
-
setInsets = async (insets: EdgeInsets) => {
- await this.doAsync(`
- if (typeof safeAreaController !== "undefined") {
- safeAreaController.update(${JSON.stringify(insets)})
- }
- `);
+ this.sendCommand("setInsets", insets);
};
updateSettings = async (settings?: Partial) => {
@@ -193,13 +141,7 @@ if (typeof statusBar !== "undefined") {
...this.previousSettings,
...settings
};
- await this.doAsync(`
- if (typeof globalThis.settingsController !== "undefined") {
- globalThis.settingsController.update(${JSON.stringify(
- this.previousSettings
- )})
- }
- `);
+ this.sendCommand("updateSettings", settings);
};
setSettings = async (settings?: Partial) => {
@@ -212,11 +154,7 @@ if (typeof statusBar !== "undefined") {
return;
}
}
- await this.doAsync(`
- if (typeof globalThis.settingsController !== "undefined") {
- globalThis.settingsController.update(${JSON.stringify(settings)})
- }
- `);
+ this.sendCommand("setSettings", settings);
};
setTags = async (note: Note | null | undefined) => {
@@ -224,60 +162,23 @@ if (typeof statusBar !== "undefined") {
useTabStore.getState().forEachNoteTab(note.id, async (tab) => {
const tabId = tab.id;
const tags = await db.relations.to(note, "tag").resolve();
- await this.doAsync(
- `
- const tags = editorTags["${tabId}"];
- if (tags && tags.current) {
- tags.current.setTags(${JSON.stringify(
- tags.map((tag) => ({
- title: tag.title,
- alias: tag.title,
- id: tag.id,
- type: tag.type
- }))
- )});
- }
- `,
- "setTags"
- );
+ await this.sendCommand("setTags", tabId, tags);
});
};
clearTags = async (tabId: string) => {
- await this.doAsync(
- `
- const tags = editorTags["${tabId}"];
- logger("info", Object.keys(editorTags), typeof editorTags[0]);
- if (tags && tags.current) {
- tags.current.setTags([]);
- }
- `,
- "clearTags"
- );
+ await this.sendCommand("clearTags", tabId);
};
insertAttachment = async (attachment: Attachment, tabId: number) => {
- await this.doAsync(
- `const editor = editors["${tabId}"];
-editor && editor.commands.insertAttachment(${JSON.stringify(attachment)})`
- );
+ await this.sendCommand("insertAttachment", attachment, tabId);
};
setAttachmentProgress = async (
attachmentProgress: Partial,
tabId: number
) => {
- await this.doAsync(
- `const editor = editors["${tabId}"];
-editor && editor.commands.updateAttachment(${JSON.stringify(
- attachmentProgress
- )}, {
- preventUpdate: true,
- query: (attachment) => {
- return attachment.hash === "${attachmentProgress.hash}";
- }
- })`
- );
+ await this.sendCommand("setAttachmentProgress", attachmentProgress, tabId);
};
insertImage = async (
@@ -286,50 +187,30 @@ editor && editor.commands.updateAttachment(${JSON.stringify(
},
tabId: number
) => {
- await this.doAsync(
- `const editor = editors["${tabId}"];
-
-const image = toBlobURL("${image.dataurl}", "${image.hash}");
-
-editor && editor.commands.insertImage({
- ...${JSON.stringify({
- ...image,
- dataurl: undefined
- })},
- bloburl: image
- })`
- );
+ await this.sendCommand("insertImage", image, tabId);
};
handleBack = async () => {
- return this.doAsync(
- 'response = window.dispatchEvent(new Event("handleBackPress",{cancelable:true}));'
- );
+ return this.sendCommand("handleBack");
};
keyboardShown = async (keyboardShown: boolean) => {
- return this.doAsync(`globalThis['keyboardShown']=${keyboardShown};`);
+ return this.sendCommand("keyboardShown", keyboardShown);
};
getTableOfContents = async () => {
const tabId = useTabStore.getState().currentTab;
- return this.doAsync(`
- response = editorControllers["${tabId}"]?.getTableOfContents() || [];
- `);
+ return this.sendCommand("getTableOfContents", tabId);
};
focusPassInput = async () => {
const tabId = useTabStore.getState().currentTab;
- return this.doAsync(`
- response = editorControllers["${tabId}"]?.focusPassInput() || [];
- `);
+ return this.sendCommand("focusPassInput", tabId);
};
blurPassInput = async () => {
const tabId = useTabStore.getState().currentTab;
- return this.doAsync(`
- response = editorControllers["${tabId}"]?.blurPassInput() || [];
- `);
+ return this.sendCommand("blurPassInput", tabId);
};
createInternalLink = async (
@@ -337,28 +218,17 @@ editor && editor.commands.insertImage({
resolverId: string
) => {
if (!resolverId) return;
- return this.doAsync(`
- if (globalThis.pendingResolvers["${resolverId}"]) {
- globalThis.pendingResolvers["${resolverId}"](${JSON.stringify(
- attributes
- )});
- }`);
+ return this.sendCommand("createInternalLink", attributes, resolverId);
};
dismissCreateInternalLinkRequest = async (resolverId: string) => {
if (!resolverId) return;
- return this.doAsync(`
- if (globalThis.pendingResolvers["${resolverId}"]) {
- globalThis.pendingResolvers["${resolverId}"](undefined);
- }
- `);
+ return this.sendCommand("dismissCreateInternalLinkRequest", resolverId);
};
scrollIntoViewById = async (id: string) => {
const tabId = useTabStore.getState().currentTab;
- return this.doAsync(`
- response = editorControllers["${tabId}"]?.scrollIntoView("${id}") || [];
- `);
+ return this.sendCommand("scrollIntoViewById", id, tabId);
};
}
diff --git a/packages/editor-mobile/src/index.tsx b/packages/editor-mobile/src/index.tsx
index f327f3a85..1d706116d 100644
--- a/packages/editor-mobile/src/index.tsx
+++ b/packages/editor-mobile/src/index.tsx
@@ -17,6 +17,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
import "./utils/index";
+import "./utils/commands";
global.Buffer = require("buffer").Buffer;
import { i18n } from "@lingui/core";
import "@notesnook/editor/styles/fonts.mobile.css";
diff --git a/packages/editor-mobile/src/utils/commands.ts b/packages/editor-mobile/src/utils/commands.ts
new file mode 100644
index 000000000..7f20313bc
--- /dev/null
+++ b/packages/editor-mobile/src/utils/commands.ts
@@ -0,0 +1,200 @@
+/*
+This file is part of the Notesnook project (https://notesnook.com/)
+
+Copyright (C) 2023 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 .
+*/
+
+import { Attachment, ImageAttributes, LinkAttributes } from "@notesnook/editor";
+import { Settings } from ".";
+
+globalThis.commands = {
+ clearContent: (tabId: string) => {
+ try {
+ const editor = editors[tabId];
+ const editorController = editorControllers[tabId];
+ const editorTitle = editorTitles[tabId];
+ const statusBar = statusBars[tabId];
+
+ if (editor) {
+ editor?.commands.blur();
+ editor?.commands.clearContent(false);
+ }
+
+ if (editorController) {
+ editorController.content.current = "";
+ editorController.onUpdate();
+ editorController.setTitle("");
+ }
+
+ if (editorTitle?.current) {
+ editorTitle.current?.blur();
+ editorTitle.current.value = "";
+ }
+
+ if (statusBar) {
+ statusBar.current.resetWords();
+ statusBar.current.set({ date: "", saved: "" });
+ }
+ } catch (error) {
+ logger("error", "clearContent", error, (error as Error).stack);
+ }
+ },
+
+ focus: (tabId: string, locked: boolean) => {
+ const editorController = editorControllers[tabId];
+ if (locked) {
+ editorController?.focusPassInput();
+ } else {
+ editors[tabId]?.commands.focus();
+ }
+ },
+
+ blur: (tabId: string) => {
+ const editor = editors[tabId];
+ const editorTitle = editorTitles[tabId];
+ if (editor) editor.commands.blur();
+ if (editorTitle?.current) editorTitle.current.blur();
+ editorControllers[tabId]?.blurPassInput();
+ },
+
+ setSessionId: (id: string | undefined) => {
+ globalThis.sessionId = id;
+ },
+
+ setStatus: (date: string | undefined, saved: string, tabId: string) => {
+ const statusBar = statusBars[tabId];
+ if (statusBar?.current) {
+ statusBar.current.set({ date: date || "", saved });
+ }
+ },
+
+ setLoading: (loading?: boolean, tabId?: string) => {
+ if (tabId) {
+ const editorController = editorControllers[tabId];
+ editorController?.setLoading(loading || false);
+ logger("info", editorController?.setLoading);
+ }
+ },
+
+ setInsets: (insets: any) => {
+ if (typeof safeAreaController !== "undefined") {
+ safeAreaController.update(insets);
+ }
+ },
+
+ updateSettings: (settings?: Partial) => {
+ if (typeof globalThis.settingsController !== "undefined") {
+ globalThis.settingsController.update(settings as Settings);
+ }
+ },
+
+ setSettings: (settings?: Partial) => {
+ if (typeof globalThis.settingsController !== "undefined") {
+ globalThis.settingsController.update(settings as Settings);
+ }
+ },
+
+ setTags: async (tabId: string, tags: any) => {
+ const current = globalThis.editorTags[tabId];
+ if (current?.current) {
+ current.current.setTags(
+ tags.map((tag: any) => ({
+ title: tag.title,
+ alias: tag.title,
+ id: tag.id,
+ type: tag.type
+ }))
+ );
+ }
+ },
+
+ clearTags: (tabId: string) => {
+ const tags = editorTags[tabId];
+ if (tags?.current) {
+ tags.current.setTags([]);
+ }
+ },
+
+ insertAttachment: (attachment: Attachment, tabId: number) => {
+ const editor = editors[tabId];
+ if (editor) {
+ editor.commands.insertAttachment(attachment);
+ }
+ },
+
+ setAttachmentProgress: (
+ attachmentProgress: Partial,
+ tabId: number
+ ) => {
+ const editor = editors[tabId];
+ if (editor) {
+ editor.commands.updateAttachment(attachmentProgress, {
+ preventUpdate: true,
+ query: (attachment) => attachment.hash === attachmentProgress.hash
+ });
+ }
+ },
+
+ insertImage: (
+ image: Omit & { dataurl: string },
+ tabId: number
+ ) => {
+ const editor = editors[tabId];
+ if (editor) {
+ editor.commands.insertImage({
+ ...image
+ });
+ }
+ },
+
+ handleBack: () => {
+ return window.dispatchEvent(
+ new Event("handleBackPress", { cancelable: true })
+ );
+ },
+
+ keyboardShown: (keyboardShown: boolean) => {
+ globalThis["keyboardShown"] = keyboardShown;
+ },
+
+ getTableOfContents: (tabId: string) => {
+ return editorControllers[tabId]?.getTableOfContents() || [];
+ },
+
+ focusPassInput: (tabId: string) => {
+ return editorControllers[tabId]?.focusPassInput() || [];
+ },
+
+ blurPassInput: (tabId: string) => {
+ return editorControllers[tabId]?.blurPassInput() || [];
+ },
+
+ createInternalLink: (attributes: LinkAttributes, resolverId: string) => {
+ if (globalThis.pendingResolvers[resolverId]) {
+ globalThis.pendingResolvers[resolverId](attributes);
+ }
+ },
+
+ dismissCreateInternalLinkRequest: (resolverId: string) => {
+ if (globalThis.pendingResolvers[resolverId]) {
+ globalThis.pendingResolvers[resolverId](undefined);
+ }
+ },
+
+ scrollIntoViewById: (id: string, tabId: string) => {
+ return editorControllers[tabId]?.scrollIntoView(id) || [];
+ }
+};
diff --git a/packages/editor-mobile/src/utils/index.ts b/packages/editor-mobile/src/utils/index.ts
index 0e1fb4d0d..c7f20d599 100644
--- a/packages/editor-mobile/src/utils/index.ts
+++ b/packages/editor-mobile/src/utils/index.ts
@@ -83,10 +83,12 @@ declare global {
var noHeader: boolean;
function toBlobURL(dataurl: string, id?: string): string | undefined;
var pendingResolvers: { [name: string]: (value: any) => void };
+
+ var commands: any;
/**
* Id of current session
*/
- var sessionId: string;
+ var sessionId: string | undefined;
var tabStore: any;
/**