mirror of
https://github.com/streetwriters/notesnook.git
synced 2026-02-24 04:00:59 +01:00
mobile: fix commands
This commit is contained in:
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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;
|
||||
|
||||
@@ -18,9 +18,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<WebView | undefined>, 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<T>;
|
||||
}
|
||||
|
||||
async sendCommand<T>(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<Settings>) => {
|
||||
@@ -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<Settings>) => {
|
||||
@@ -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<Attachment>,
|
||||
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<boolean>(
|
||||
'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);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ 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 "./utils/index";
|
||||
import "./utils/commands";
|
||||
global.Buffer = require("buffer").Buffer;
|
||||
import { i18n } from "@lingui/core";
|
||||
import "@notesnook/editor/styles/fonts.mobile.css";
|
||||
|
||||
200
packages/editor-mobile/src/utils/commands.ts
Normal file
200
packages/editor-mobile/src/utils/commands.ts
Normal file
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<Settings>) => {
|
||||
if (typeof globalThis.settingsController !== "undefined") {
|
||||
globalThis.settingsController.update(settings as Settings);
|
||||
}
|
||||
},
|
||||
|
||||
setSettings: (settings?: Partial<Settings>) => {
|
||||
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<Attachment>,
|
||||
tabId: number
|
||||
) => {
|
||||
const editor = editors[tabId];
|
||||
if (editor) {
|
||||
editor.commands.updateAttachment(attachmentProgress, {
|
||||
preventUpdate: true,
|
||||
query: (attachment) => attachment.hash === attachmentProgress.hash
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
insertImage: (
|
||||
image: Omit<ImageAttributes, "bloburl"> & { 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) || [];
|
||||
}
|
||||
};
|
||||
@@ -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;
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user