You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-08-24 20:19:10 +02:00
Compare commits
2 Commits
android-v3
...
mobile_plu
Author | SHA1 | Date | |
---|---|---|---|
|
812666957c | ||
|
dabb7e08b4 |
@@ -456,7 +456,6 @@ packages/app-desktop/gui/WindowCommandsAndDialogs/commands/restoreNote.js
|
||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/revealResourceFile.js
|
||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/search.js
|
||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/setTags.js
|
||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/showEditorPlugin.js
|
||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/showModalMessage.js
|
||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/showNoteContentProperties.js
|
||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/showNoteProperties.js
|
||||
@@ -465,7 +464,6 @@ packages/app-desktop/gui/WindowCommandsAndDialogs/commands/showShareFolderDialog
|
||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/showShareNoteDialog.js
|
||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/showSpellCheckerMenu.test.js
|
||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/showSpellCheckerMenu.js
|
||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/toggleEditorPlugin.js
|
||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/toggleEditors.js
|
||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/toggleLayoutMoveMode.js
|
||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/toggleMenuBar.js
|
||||
@@ -1021,7 +1019,9 @@ packages/lib/commands/openMasterPasswordDialog.js
|
||||
packages/lib/commands/permanentlyDeleteNote.js
|
||||
packages/lib/commands/renderMarkup.test.js
|
||||
packages/lib/commands/renderMarkup.js
|
||||
packages/lib/commands/showEditorPlugin.js
|
||||
packages/lib/commands/synchronize.js
|
||||
packages/lib/commands/toggleEditorPlugin.js
|
||||
packages/lib/components/EncryptionConfigScreen/utils.test.js
|
||||
packages/lib/components/EncryptionConfigScreen/utils.js
|
||||
packages/lib/components/shared/NoteList/getEmptyFolderMessage.js
|
||||
@@ -1303,6 +1303,7 @@ packages/lib/services/plugins/utils/getPluginIssueReportUrl.js
|
||||
packages/lib/services/plugins/utils/getPluginNamespacedSettingKey.js
|
||||
packages/lib/services/plugins/utils/getPluginSettingKeyPrefix.js
|
||||
packages/lib/services/plugins/utils/getPluginSettingValue.js
|
||||
packages/lib/services/plugins/utils/getShownPluginEditorView.js
|
||||
packages/lib/services/plugins/utils/isCompatible/getDefaultPlatforms.js
|
||||
packages/lib/services/plugins/utils/isCompatible/index.test.js
|
||||
packages/lib/services/plugins/utils/isCompatible/index.js
|
||||
|
5
.gitignore
vendored
5
.gitignore
vendored
@@ -431,7 +431,6 @@ packages/app-desktop/gui/WindowCommandsAndDialogs/commands/restoreNote.js
|
||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/revealResourceFile.js
|
||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/search.js
|
||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/setTags.js
|
||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/showEditorPlugin.js
|
||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/showModalMessage.js
|
||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/showNoteContentProperties.js
|
||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/showNoteProperties.js
|
||||
@@ -440,7 +439,6 @@ packages/app-desktop/gui/WindowCommandsAndDialogs/commands/showShareFolderDialog
|
||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/showShareNoteDialog.js
|
||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/showSpellCheckerMenu.test.js
|
||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/showSpellCheckerMenu.js
|
||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/toggleEditorPlugin.js
|
||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/toggleEditors.js
|
||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/toggleLayoutMoveMode.js
|
||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/toggleMenuBar.js
|
||||
@@ -996,7 +994,9 @@ packages/lib/commands/openMasterPasswordDialog.js
|
||||
packages/lib/commands/permanentlyDeleteNote.js
|
||||
packages/lib/commands/renderMarkup.test.js
|
||||
packages/lib/commands/renderMarkup.js
|
||||
packages/lib/commands/showEditorPlugin.js
|
||||
packages/lib/commands/synchronize.js
|
||||
packages/lib/commands/toggleEditorPlugin.js
|
||||
packages/lib/components/EncryptionConfigScreen/utils.test.js
|
||||
packages/lib/components/EncryptionConfigScreen/utils.js
|
||||
packages/lib/components/shared/NoteList/getEmptyFolderMessage.js
|
||||
@@ -1278,6 +1278,7 @@ packages/lib/services/plugins/utils/getPluginIssueReportUrl.js
|
||||
packages/lib/services/plugins/utils/getPluginNamespacedSettingKey.js
|
||||
packages/lib/services/plugins/utils/getPluginSettingKeyPrefix.js
|
||||
packages/lib/services/plugins/utils/getPluginSettingValue.js
|
||||
packages/lib/services/plugins/utils/getShownPluginEditorView.js
|
||||
packages/lib/services/plugins/utils/isCompatible/getDefaultPlatforms.js
|
||||
packages/lib/services/plugins/utils/isCompatible/index.test.js
|
||||
packages/lib/services/plugins/utils/isCompatible/index.js
|
||||
|
@@ -1,15 +1,11 @@
|
||||
import { useMemo } from 'react';
|
||||
import { PluginStates } from '@joplin/lib/services/plugins/reducer';
|
||||
import getActivePluginEditorView from '@joplin/lib/services/plugins/utils/getActivePluginEditorView';
|
||||
import getShownPluginEditorView from '@joplin/lib/services/plugins/utils/getShownPluginEditorView';
|
||||
|
||||
// If a plugin editor should be shown for the current note, this function will return the plugin and
|
||||
// associated view.
|
||||
export default (plugins: PluginStates, shownEditorViewIds: string[]) => {
|
||||
return useMemo(() => {
|
||||
const { editorPlugin, editorView } = getActivePluginEditorView(plugins);
|
||||
if (editorView) {
|
||||
if (!shownEditorViewIds.includes(editorView.id)) return { editorPlugin: null, editorView: null };
|
||||
}
|
||||
return { editorPlugin, editorView };
|
||||
return getShownPluginEditorView(plugins, shownEditorViewIds);
|
||||
}, [plugins, shownEditorViewIds]);
|
||||
};
|
||||
|
@@ -28,7 +28,6 @@ import * as restoreNote from './restoreNote';
|
||||
import * as revealResourceFile from './revealResourceFile';
|
||||
import * as search from './search';
|
||||
import * as setTags from './setTags';
|
||||
import * as showEditorPlugin from './showEditorPlugin';
|
||||
import * as showModalMessage from './showModalMessage';
|
||||
import * as showNoteContentProperties from './showNoteContentProperties';
|
||||
import * as showNoteProperties from './showNoteProperties';
|
||||
@@ -36,7 +35,6 @@ import * as showPrompt from './showPrompt';
|
||||
import * as showShareFolderDialog from './showShareFolderDialog';
|
||||
import * as showShareNoteDialog from './showShareNoteDialog';
|
||||
import * as showSpellCheckerMenu from './showSpellCheckerMenu';
|
||||
import * as toggleEditorPlugin from './toggleEditorPlugin';
|
||||
import * as toggleEditors from './toggleEditors';
|
||||
import * as toggleLayoutMoveMode from './toggleLayoutMoveMode';
|
||||
import * as toggleMenuBar from './toggleMenuBar';
|
||||
@@ -78,7 +76,6 @@ const index: any[] = [
|
||||
revealResourceFile,
|
||||
search,
|
||||
setTags,
|
||||
showEditorPlugin,
|
||||
showModalMessage,
|
||||
showNoteContentProperties,
|
||||
showNoteProperties,
|
||||
@@ -86,7 +83,6 @@ const index: any[] = [
|
||||
showShareFolderDialog,
|
||||
showShareNoteDialog,
|
||||
showSpellCheckerMenu,
|
||||
toggleEditorPlugin,
|
||||
toggleEditors,
|
||||
toggleLayoutMoveMode,
|
||||
toggleMenuBar,
|
||||
|
@@ -25,6 +25,7 @@ import WebBetaButton from './WebBetaButton';
|
||||
|
||||
import Menu, { MenuOptionType } from './Menu';
|
||||
import shim from '@joplin/lib/shim';
|
||||
import CommandService from '@joplin/lib/services/CommandService';
|
||||
export { MenuOptionType };
|
||||
|
||||
// Rather than applying a padding to the whole bar, it is applied to each
|
||||
@@ -67,6 +68,7 @@ interface ScreenHeaderProps {
|
||||
showSideMenuButton?: boolean;
|
||||
showSearchButton?: boolean;
|
||||
showContextMenuButton?: boolean;
|
||||
showPluginEditorButton?: boolean;
|
||||
showBackButton?: boolean;
|
||||
|
||||
saveButtonDisabled?: boolean;
|
||||
@@ -419,6 +421,28 @@ class ScreenHeaderComponent extends PureComponent<ScreenHeaderProps, ScreenHeade
|
||||
);
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
const renderTogglePluginEditorButton = (styles: any, onPress: OnPressCallback, disabled: boolean) => {
|
||||
if (!this.props.showPluginEditorButton) return null;
|
||||
|
||||
return (
|
||||
<IconButton
|
||||
onPress={onPress}
|
||||
disabled={disabled}
|
||||
|
||||
themeId={themeId}
|
||||
description={_('Toggle plugin editor')}
|
||||
accessibilityHint={
|
||||
disabled ? null : _('Toggle plugin editor')
|
||||
}
|
||||
contentWrapperStyle={disabled ? styles.iconButtonDisabled : styles.iconButton}
|
||||
|
||||
iconName='ionicon eye'
|
||||
iconStyle={styles.topIcon}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
function deleteButton(styles: any, onPress: OnPressCallback, disabled: boolean) {
|
||||
return (
|
||||
@@ -631,6 +655,8 @@ class ScreenHeaderComponent extends PureComponent<ScreenHeaderProps, ScreenHeade
|
||||
</Menu>
|
||||
);
|
||||
|
||||
const togglePluginEditorButton = renderTogglePluginEditorButton(this.styles(), () => CommandService.instance().execute('toggleEditorPlugin'), false);
|
||||
|
||||
return (
|
||||
<View style={this.styles().container}>
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
||||
@@ -653,6 +679,7 @@ class ScreenHeaderComponent extends PureComponent<ScreenHeaderProps, ScreenHeade
|
||||
{restoreButtonComp}
|
||||
{duplicateButtonComp}
|
||||
{sortButtonComp}
|
||||
{togglePluginEditorButton}
|
||||
{menuComp}
|
||||
</View>
|
||||
<WarningBanner
|
||||
|
@@ -28,7 +28,7 @@ const PluginDialogManager: React.FC<Props> = props => {
|
||||
|
||||
const dialogs: ReactElement[] = [];
|
||||
for (const viewInfo of viewInfos) {
|
||||
if (viewInfo.view.containerType === ContainerType.Panel || !viewInfo.view.opened) {
|
||||
if (viewInfo.view.containerType === ContainerType.Panel || viewInfo.view.containerType === ContainerType.Editor || !viewInfo.view.opened) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import AsyncActionQueue from '@joplin/lib/AsyncActionQueue';
|
||||
import AsyncActionQueue, { IntervalType } from '@joplin/lib/AsyncActionQueue';
|
||||
import uuid from '@joplin/lib/uuid';
|
||||
import Setting from '@joplin/lib/models/Setting';
|
||||
import shim from '@joplin/lib/shim';
|
||||
@@ -51,7 +51,7 @@ import { getNoteCallbackUrl } from '@joplin/lib/callbackUrlUtils';
|
||||
import { AppState } from '../../../utils/types';
|
||||
import restoreItems from '@joplin/lib/services/trash/restoreItems';
|
||||
import { getDisplayParentTitle } from '@joplin/lib/services/trash';
|
||||
import { PluginStates, utils as pluginUtils } from '@joplin/lib/services/plugins/reducer';
|
||||
import { PluginHtmlContents, PluginStates, utils as pluginUtils } from '@joplin/lib/services/plugins/reducer';
|
||||
import debounce from '../../../utils/debounce';
|
||||
import { focus } from '@joplin/lib/utils/focusHandler';
|
||||
import CommandService, { RegisteredRuntime } from '@joplin/lib/services/CommandService';
|
||||
@@ -63,6 +63,14 @@ import { DialogContext, DialogControl } from '../../DialogManager';
|
||||
import { CommandRuntimeProps, EditorMode, PickerResponse } from './types';
|
||||
import commands from './commands';
|
||||
import { AttachFileAction, AttachFileOptions } from './commands/attachFile';
|
||||
import { EditorActivationCheckFilterObject } from '@joplin/lib/services/plugins/api/types';
|
||||
import eventManager from '@joplin/lib/eventManager';
|
||||
import PluginService from '@joplin/lib/services/plugins/PluginService';
|
||||
import WebviewController from '@joplin/lib/services/plugins/WebviewController';
|
||||
import PluginUserWebView from '../../plugins/dialogs/PluginUserWebView';
|
||||
import getShownPluginEditorView from '@joplin/lib/services/plugins/utils/getShownPluginEditorView';
|
||||
import getActivePluginEditorView from '@joplin/lib/services/plugins/utils/getActivePluginEditorView';
|
||||
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
const emptyArray: any[] = [];
|
||||
@@ -97,6 +105,9 @@ interface Props extends BaseProps {
|
||||
highlightedWords: string[];
|
||||
noteHash: string;
|
||||
toolbarEnabled: boolean;
|
||||
'plugins.shownEditorViewIds': string[];
|
||||
pluginHtmlContents: PluginHtmlContents;
|
||||
editorNoteReloadTimeRequest: number;
|
||||
}
|
||||
|
||||
interface ComponentProps extends Props {
|
||||
@@ -122,6 +133,7 @@ interface State {
|
||||
imageEditorResourceFilepath: string;
|
||||
noteResources: Record<string, ResourceInfo>;
|
||||
newAndNoTitleChangeNoteId: boolean|null;
|
||||
noteLastLoadTime: number;
|
||||
|
||||
undoRedoButtonState: {
|
||||
canUndo: boolean;
|
||||
@@ -131,6 +143,20 @@ interface State {
|
||||
voiceTypingDialogShown: boolean;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// TODO: COPIED FROM DESKTOP
|
||||
const makeNoteUpdateAction = (shownEditorViewIds: string[]) => {
|
||||
return async () => {
|
||||
for (const viewId of shownEditorViewIds) {
|
||||
const controller = PluginService.instance().viewControllerByViewId(viewId) as WebviewController;
|
||||
if (controller) controller.emitUpdate();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
class NoteScreenComponent extends BaseScreenComponent<ComponentProps, State> implements BaseNoteScreenComponent {
|
||||
// This isn't in this.state because we don't want changing scroll to trigger
|
||||
// a re-render.
|
||||
@@ -163,6 +189,8 @@ class NoteScreenComponent extends BaseScreenComponent<ComponentProps, State> imp
|
||||
public dialogbox: any;
|
||||
private commandRegistration_: RegisteredRuntime|null = null;
|
||||
|
||||
private viewUpdateAsyncQueue_ = new AsyncActionQueue(100, IntervalType.Fixed);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
public static navigationOptions(): any {
|
||||
return { header: null };
|
||||
@@ -189,6 +217,7 @@ class NoteScreenComponent extends BaseScreenComponent<ComponentProps, State> imp
|
||||
noteResources: {},
|
||||
imageEditorResourceFilepath: null,
|
||||
newAndNoTitleChangeNoteId: null,
|
||||
noteLastLoadTime: Date.now(),
|
||||
|
||||
undoRedoButtonState: {
|
||||
canUndo: false,
|
||||
@@ -551,6 +580,9 @@ class NoteScreenComponent extends BaseScreenComponent<ComponentProps, State> imp
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
|
||||
// TODO: set shownEditorViewIds
|
||||
this.viewUpdateAsyncQueue_.push(makeNoteUpdateAction(['plugin-view-org.joplinapp.plugins.YesYouKan-kanbanBoard']));
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
@@ -610,6 +642,28 @@ class NoteScreenComponent extends BaseScreenComponent<ComponentProps, State> imp
|
||||
noteHash: noteHash,
|
||||
});
|
||||
}
|
||||
|
||||
if (this.props['plugins.shownEditorViewIds'] !== prevProps['plugins.shownEditorViewIds']) {
|
||||
const { editorPlugin } = getShownPluginEditorView(this.props.plugins, this.props['plugins.shownEditorViewIds']);
|
||||
if (!editorPlugin && this.props.editorNoteReloadTimeRequest > this.state.noteLastLoadTime) {
|
||||
void shared.reloadNote(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// **************** TODO: REUSED FROM DESKTOP APP
|
||||
setTimeout(async () => {
|
||||
let filterObject: EditorActivationCheckFilterObject = {
|
||||
activatedEditors: [],
|
||||
};
|
||||
filterObject = await eventManager.filterEmit('editorActivationCheck', filterObject);
|
||||
|
||||
for (const editor of filterObject.activatedEditors) {
|
||||
const controller = PluginService.instance().pluginById(editor.pluginId).viewController(editor.viewId) as WebviewController;
|
||||
controller.setActive(editor.isActive);
|
||||
}
|
||||
}, 50);
|
||||
// **************** REUSED FROM DESKTOP APP
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
@@ -1420,6 +1474,8 @@ class NoteScreenComponent extends BaseScreenComponent<ComponentProps, State> imp
|
||||
// multiple times.
|
||||
this.registerCommands();
|
||||
|
||||
const { editorPlugin, editorView } = getShownPluginEditorView(this.props.plugins, this.props['plugins.shownEditorViewIds']);
|
||||
|
||||
if (this.state.isLoading) {
|
||||
return (
|
||||
<View style={this.styles().screen}>
|
||||
@@ -1448,10 +1504,25 @@ class NoteScreenComponent extends BaseScreenComponent<ComponentProps, State> imp
|
||||
/>;
|
||||
}
|
||||
|
||||
const renderPluginEditor = () => {
|
||||
return <PluginUserWebView
|
||||
viewInfo={{ plugin: editorPlugin, view: editorView }}
|
||||
themeId={this.props.themeId}
|
||||
onLoadEnd={() => {}}
|
||||
pluginHtmlContents={this.props.pluginHtmlContents}
|
||||
setDialogControl={() => {}}
|
||||
style={{}}
|
||||
/>;
|
||||
};
|
||||
|
||||
// Currently keyword highlighting is supported only when FTS is available.
|
||||
const keywords = this.props.searchQuery && !!this.props.ftsEnabled ? this.props.highlightedWords : emptyArray;
|
||||
|
||||
let bodyComponent = null;
|
||||
|
||||
if (editorView) {
|
||||
bodyComponent = renderPluginEditor();
|
||||
} else {
|
||||
if (this.state.mode === 'view') {
|
||||
// Note: as of 2018-12-29 it's important not to display the viewer if the note body is empty,
|
||||
// to avoid the HACK_webviewLoadingState related bug.
|
||||
@@ -1541,6 +1612,7 @@ class NoteScreenComponent extends BaseScreenComponent<ComponentProps, State> imp
|
||||
/>;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const renderActionButton = () => {
|
||||
if (this.state.voiceTypingDialogShown) return null;
|
||||
@@ -1595,6 +1667,8 @@ class NoteScreenComponent extends BaseScreenComponent<ComponentProps, State> imp
|
||||
return <VoiceTypingDialog locale={currentLocale()} onText={this.voiceTypingDialog_onText} onDismiss={this.voiceTypingDialog_onDismiss}/>;
|
||||
};
|
||||
|
||||
const { editorPlugin: activeEditorPlugin } = getActivePluginEditorView(this.props.plugins);
|
||||
|
||||
return (
|
||||
<View style={this.rootStyle(this.props.themeId).root}>
|
||||
<ScreenHeader
|
||||
@@ -1607,6 +1681,7 @@ class NoteScreenComponent extends BaseScreenComponent<ComponentProps, State> imp
|
||||
showSearchButton={false}
|
||||
showUndoButton={(this.state.undoRedoButtonState.canUndo || this.state.undoRedoButtonState.canRedo) && this.state.mode === 'edit'}
|
||||
showRedoButton={this.state.undoRedoButtonState.canRedo && this.state.mode === 'edit'}
|
||||
showPluginEditorButton={!!activeEditorPlugin}
|
||||
undoButtonDisabled={!this.state.undoRedoButtonState.canUndo && this.state.undoRedoButtonState.canRedo}
|
||||
onUndoButtonPress={this.screenHeader_undoButtonPress}
|
||||
onRedoButtonPress={this.screenHeader_redoButtonPress}
|
||||
@@ -1654,6 +1729,9 @@ const NoteScreen = connect((state: AppState) => {
|
||||
provisionalNoteIds: state.provisionalNoteIds,
|
||||
highlightedWords: state.highlightedWords,
|
||||
plugins: state.pluginService.plugins,
|
||||
'plugins.shownEditorViewIds': state.settings['plugins.shownEditorViewIds'] || [],
|
||||
pluginHtmlContents: state.pluginService.pluginHtmlContents,
|
||||
editorNoteReloadTimeRequest: state.editorNoteReloadTimeRequest,
|
||||
|
||||
// What we call "beta editor" in this component is actually the (now
|
||||
// default) CodeMirror editor. That should be refactored to make it less
|
||||
|
@@ -288,7 +288,14 @@ class NotesScreenComponent extends BaseScreenComponent<ComponentProps, State> {
|
||||
|
||||
inert={accessibilityHidden}
|
||||
>
|
||||
<ScreenHeader title={iconString + title} showBackButton={false} sortButton_press={this.sortButton_press} folderPickerOptions={this.folderPickerOptions()} showSearchButton={true} showSideMenuButton={true} />
|
||||
<ScreenHeader
|
||||
title={iconString + title}
|
||||
showBackButton={false}
|
||||
sortButton_press={this.sortButton_press}
|
||||
folderPickerOptions={this.folderPickerOptions()}
|
||||
showSearchButton={true}
|
||||
showSideMenuButton={true}
|
||||
/>
|
||||
<NoteList />
|
||||
{actionButtonComp}
|
||||
</AccessibleView>
|
||||
|
@@ -1 +1 @@
|
||||
module.exports = {"hash":"cfa07333af79f4db4bc9ca008fb257f8","files":["highlight.js/atom-one-dark-reasonable.css","highlight.js/atom-one-light.css","katex/fonts/KaTeX_AMS-Regular.woff2","katex/fonts/KaTeX_Caligraphic-Bold.woff2","katex/fonts/KaTeX_Caligraphic-Regular.woff2","katex/fonts/KaTeX_Fraktur-Bold.woff2","katex/fonts/KaTeX_Fraktur-Regular.woff2","katex/fonts/KaTeX_Main-Bold.woff2","katex/fonts/KaTeX_Main-BoldItalic.woff2","katex/fonts/KaTeX_Main-Italic.woff2","katex/fonts/KaTeX_Main-Regular.woff2","katex/fonts/KaTeX_Math-BoldItalic.woff2","katex/fonts/KaTeX_Math-Italic.woff2","katex/fonts/KaTeX_SansSerif-Bold.woff2","katex/fonts/KaTeX_SansSerif-Italic.woff2","katex/fonts/KaTeX_SansSerif-Regular.woff2","katex/fonts/KaTeX_Script-Regular.woff2","katex/fonts/KaTeX_Size1-Regular.woff2","katex/fonts/KaTeX_Size2-Regular.woff2","katex/fonts/KaTeX_Size3-Regular.woff2","katex/fonts/KaTeX_Size4-Regular.woff2","katex/fonts/KaTeX_Typewriter-Regular.woff2","katex/katex.css","mermaid/mermaid.min.js","mermaid/mermaid_render.js"]}
|
||||
module.exports = {"hash":"cfa07333af79f4db4bc9ca008fb257f8","files":[".DS_Store","highlight.js/atom-one-dark-reasonable.css","highlight.js/atom-one-light.css","katex/fonts/KaTeX_AMS-Regular.woff2","katex/fonts/KaTeX_Caligraphic-Bold.woff2","katex/fonts/KaTeX_Caligraphic-Regular.woff2","katex/fonts/KaTeX_Fraktur-Bold.woff2","katex/fonts/KaTeX_Fraktur-Regular.woff2","katex/fonts/KaTeX_Main-Bold.woff2","katex/fonts/KaTeX_Main-BoldItalic.woff2","katex/fonts/KaTeX_Main-Italic.woff2","katex/fonts/KaTeX_Main-Regular.woff2","katex/fonts/KaTeX_Math-BoldItalic.woff2","katex/fonts/KaTeX_Math-Italic.woff2","katex/fonts/KaTeX_SansSerif-Bold.woff2","katex/fonts/KaTeX_SansSerif-Italic.woff2","katex/fonts/KaTeX_SansSerif-Regular.woff2","katex/fonts/KaTeX_Script-Regular.woff2","katex/fonts/KaTeX_Size1-Regular.woff2","katex/fonts/KaTeX_Size2-Regular.woff2","katex/fonts/KaTeX_Size3-Regular.woff2","katex/fonts/KaTeX_Size4-Regular.woff2","katex/fonts/KaTeX_Typewriter-Regular.woff2","katex/katex.css","mermaid/mermaid.min.js","mermaid/mermaid_render.js"]}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,13 @@
|
||||
module.exports = {
|
||||
hash: '55cc4fcf19c129e3824873d98ad417c9', files: {
|
||||
'fontawesome/css/all.min.css': { data: require('./fontawesome/css/all.min.css.base64.js'), mime: 'text/css', encoding: 'base64' },
|
||||
'fontawesome/webfonts/fa-brands-400.ttf': { data: require('./fontawesome/webfonts/fa-brands-400.ttf.base64.js'), mime: 'application/octet-stream', encoding: 'base64' },
|
||||
'fontawesome/webfonts/fa-brands-400.woff2': { data: require('./fontawesome/webfonts/fa-brands-400.woff2.base64.js'), mime: 'application/octet-stream', encoding: 'base64' },
|
||||
'fontawesome/webfonts/fa-regular-400.ttf': { data: require('./fontawesome/webfonts/fa-regular-400.ttf.base64.js'), mime: 'application/octet-stream', encoding: 'base64' },
|
||||
'fontawesome/webfonts/fa-regular-400.woff2': { data: require('./fontawesome/webfonts/fa-regular-400.woff2.base64.js'), mime: 'application/octet-stream', encoding: 'base64' },
|
||||
'fontawesome/webfonts/fa-solid-900.ttf': { data: require('./fontawesome/webfonts/fa-solid-900.ttf.base64.js'), mime: 'application/octet-stream', encoding: 'base64' },
|
||||
'fontawesome/webfonts/fa-solid-900.woff2': { data: require('./fontawesome/webfonts/fa-solid-900.woff2.base64.js'), mime: 'application/octet-stream', encoding: 'base64' },
|
||||
'fontawesome/webfonts/fa-v4compatibility.ttf': { data: require('./fontawesome/webfonts/fa-v4compatibility.ttf.base64.js'), mime: 'application/octet-stream', encoding: 'base64' },
|
||||
'fontawesome/webfonts/fa-v4compatibility.woff2': { data: require('./fontawesome/webfonts/fa-v4compatibility.woff2.base64.js'), mime: 'application/octet-stream', encoding: 'base64' },
|
||||
},
|
||||
};
|
@@ -0,0 +1 @@
|
||||
module.exports = { 'hash': '55cc4fcf19c129e3824873d98ad417c9', 'files': ['fontawesome/css/all.min.css', 'fontawesome/webfonts/fa-brands-400.ttf', 'fontawesome/webfonts/fa-brands-400.woff2', 'fontawesome/webfonts/fa-regular-400.ttf', 'fontawesome/webfonts/fa-regular-400.woff2', 'fontawesome/webfonts/fa-solid-900.ttf', 'fontawesome/webfonts/fa-solid-900.woff2', 'fontawesome/webfonts/fa-v4compatibility.ttf', 'fontawesome/webfonts/fa-v4compatibility.woff2'] };
|
@@ -5,7 +5,7 @@ const path = require('path');
|
||||
const md5 = require('md5');
|
||||
|
||||
const rootDir = `${__dirname}/..`;
|
||||
const outputDir = `${rootDir}/pluginAssets`;
|
||||
const defaultOutputDir = `${rootDir}/pluginAssets`;
|
||||
|
||||
const walk = function(dir) {
|
||||
let results = [];
|
||||
@@ -37,7 +37,7 @@ const readAsBase64 = async (path, mime) => {
|
||||
return buffer.toString('base64');
|
||||
};
|
||||
|
||||
async function encodeFile(sourcePath, destPath) {
|
||||
async function encodeFile(sourcePath, destPath, outputDir) {
|
||||
const ext = utils.fileExtension(sourcePath).toLowerCase();
|
||||
let mime = 'application/octet-stream';
|
||||
if (ext === 'js') mime = 'application/javascript';
|
||||
@@ -60,19 +60,35 @@ async function encodeFile(sourcePath, destPath) {
|
||||
};
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const copyFontAwesomeAssets = async () => {
|
||||
const sourceDir = `${rootDir}/node_modules/@fortawesome/fontawesome-free`;
|
||||
const targetDir = `${rootDir}/fontawesome-temp`;
|
||||
await fs.remove(targetDir);
|
||||
|
||||
await fs.mkdirp(`${targetDir}/fontawesome/css`);
|
||||
await fs.mkdirp(`${targetDir}/fontawesome/webfonts`);
|
||||
|
||||
await fs.copyFile(`${sourceDir}/css/all.min.css`, `${targetDir}/fontawesome/css/all.min.css`);
|
||||
await fs.copy(`${sourceDir}/webfonts`, `${targetDir}/fontawesome/webfonts`);
|
||||
|
||||
return targetDir;
|
||||
};
|
||||
|
||||
const encodeDirectory = async (sourceAssetDir) => {
|
||||
for (let i = 0; i < 3; i++) {
|
||||
try {
|
||||
const outputDir = sourceAssetDir.destination ? sourceAssetDir.destination : defaultOutputDir;
|
||||
|
||||
await fs.remove(outputDir);
|
||||
await utils.mkdirp(outputDir);
|
||||
|
||||
const encodedFiles = [];
|
||||
const sourceAssetDir = `${rootDir}/../renderer/assets`;
|
||||
const files = walk(sourceAssetDir);
|
||||
const files = walk(sourceAssetDir.source);
|
||||
|
||||
for (const file of files) {
|
||||
const destFile = file.substr(sourceAssetDir.length + 1);
|
||||
encodedFiles.push(await encodeFile(file, destFile));
|
||||
if (file.endsWith('.DS_Store')) continue;
|
||||
const destFile = file.substr(sourceAssetDir.source.length + 1);
|
||||
encodedFiles.push(await encodeFile(file, destFile, outputDir));
|
||||
}
|
||||
|
||||
const hashes = [];
|
||||
@@ -87,7 +103,7 @@ async function main() {
|
||||
await fs.writeFile(`${outputDir}/index.js`, `module.exports = {\nhash:"${hash}", files: {\n${indexJs.join('\n')}\n}\n};`);
|
||||
await fs.writeFile(`${outputDir}/index.web.js`, `module.exports = ${JSON.stringify({
|
||||
hash,
|
||||
files: files.map(file => toForwardSlashes(path.relative(sourceAssetDir, file))),
|
||||
files: files.map(file => toForwardSlashes(path.relative(sourceAssetDir.source, file))),
|
||||
})}`);
|
||||
|
||||
return;
|
||||
@@ -115,6 +131,28 @@ async function main() {
|
||||
}
|
||||
|
||||
throw new Error('Could not encode file after multiple attempts. See above for errors.');
|
||||
};
|
||||
|
||||
async function main() {
|
||||
const fontAwesomeAssetDir = await copyFontAwesomeAssets();
|
||||
|
||||
const sourceAssetDirs = [
|
||||
{
|
||||
source: `${rootDir}/../renderer/assets`,
|
||||
},
|
||||
{
|
||||
source: fontAwesomeAssetDir,
|
||||
destination: `${rootDir}/plugins/pluginUserWebViewAssets/fontawesome`,
|
||||
},
|
||||
];
|
||||
|
||||
try {
|
||||
for (const sourceAssetDir of sourceAssetDirs) {
|
||||
await encodeDirectory(sourceAssetDir);
|
||||
}
|
||||
} finally {
|
||||
await fs.remove(fontAwesomeAssetDir);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = main;
|
||||
|
@@ -5,7 +5,9 @@ import * as historyForward from './historyForward';
|
||||
import * as openMasterPasswordDialog from './openMasterPasswordDialog';
|
||||
import * as permanentlyDeleteNote from './permanentlyDeleteNote';
|
||||
import * as renderMarkup from './renderMarkup';
|
||||
import * as showEditorPlugin from './showEditorPlugin';
|
||||
import * as synchronize from './synchronize';
|
||||
import * as toggleEditorPlugin from './toggleEditorPlugin';
|
||||
|
||||
const index: any[] = [
|
||||
deleteNote,
|
||||
@@ -14,7 +16,9 @@ const index: any[] = [
|
||||
openMasterPasswordDialog,
|
||||
permanentlyDeleteNote,
|
||||
renderMarkup,
|
||||
showEditorPlugin,
|
||||
synchronize,
|
||||
toggleEditorPlugin,
|
||||
];
|
||||
|
||||
export default index;
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { CommandContext, CommandDeclaration, CommandRuntime } from '@joplin/lib/services/CommandService';
|
||||
import Setting from '@joplin/lib/models/Setting';
|
||||
import getActivePluginEditorView from '@joplin/lib/services/plugins/utils/getActivePluginEditorView';
|
||||
import { CommandContext, CommandDeclaration, CommandRuntime } from '../services/CommandService';
|
||||
import Setting from '../models/Setting';
|
||||
import getActivePluginEditorView from '../services/plugins/utils/getActivePluginEditorView';
|
||||
import Logger from '@joplin/utils/Logger';
|
||||
|
||||
const logger = Logger.create('showEditorPlugin');
|
@@ -1,7 +1,7 @@
|
||||
import { CommandContext, CommandDeclaration, CommandRuntime } from '@joplin/lib/services/CommandService';
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import Setting from '@joplin/lib/models/Setting';
|
||||
import getActivePluginEditorView from '@joplin/lib/services/plugins/utils/getActivePluginEditorView';
|
||||
import { CommandContext, CommandDeclaration, CommandRuntime } from '../services/CommandService';
|
||||
import { _ } from '../locale';
|
||||
import Setting from '../models/Setting';
|
||||
import getActivePluginEditorView from '../services/plugins/utils/getActivePluginEditorView';
|
||||
import Logger from '@joplin/utils/Logger';
|
||||
|
||||
const logger = Logger.create('toggleEditorPlugin');
|
||||
@@ -24,14 +24,26 @@ export const runtime = (): CommandRuntime => {
|
||||
}
|
||||
|
||||
const idx = shownEditorViewIds.indexOf(editorView.id);
|
||||
let hasBeenHidden = false;
|
||||
|
||||
if (idx < 0) {
|
||||
shownEditorViewIds.push(editorView.id);
|
||||
} else {
|
||||
shownEditorViewIds.splice(idx, 1);
|
||||
hasBeenHidden = true;
|
||||
}
|
||||
|
||||
logger.info('New shown editor views: ', shownEditorViewIds);
|
||||
|
||||
Setting.setValue('plugins.shownEditorViewIds', shownEditorViewIds);
|
||||
|
||||
if (hasBeenHidden) {
|
||||
// When the plugin editor goes from visible to hidden, we need to reload the note
|
||||
// because it may have been changed via the data API.
|
||||
context.dispatch({
|
||||
type: 'EDITOR_NOTE_NEEDS_RELOAD',
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
@@ -67,6 +67,8 @@ interface Shared {
|
||||
installResourceHandling?: (refreshResourceHandler: any)=> void;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
uninstallResourceHandling?: (refreshResourceHandler: any)=> void;
|
||||
|
||||
reloadNote?: (comp: BaseNoteScreenComponent)=> Promise<NoteEntity>;
|
||||
}
|
||||
|
||||
const shared: Shared = {};
|
||||
@@ -268,7 +270,7 @@ shared.isModified = function(comp: BaseNoteScreenComponent) {
|
||||
return !!Object.getOwnPropertyNames(diff).length;
|
||||
};
|
||||
|
||||
shared.initState = async function(comp: BaseNoteScreenComponent) {
|
||||
shared.reloadNote = async (comp: BaseNoteScreenComponent) => {
|
||||
const isProvisionalNote = comp.props.provisionalNoteIds.includes(comp.props.noteId);
|
||||
|
||||
const note = await Note.load(comp.props.noteId);
|
||||
@@ -292,6 +294,7 @@ shared.initState = async function(comp: BaseNoteScreenComponent) {
|
||||
fromShare: !!comp.props.sharedData,
|
||||
noteResources: await shared.attachedResources(note ? note.body : ''),
|
||||
readOnly: itemIsReadOnlySync(ModelType.Note, ItemChange.SOURCE_UNSPECIFIED, note as ItemSlice, Setting.value('sync.userId'), BaseItem.syncShareCache),
|
||||
noteLastLoadTime: Date.now(),
|
||||
});
|
||||
} else {
|
||||
// Handle the case where a non-existent note is loaded. This can happen briefly after deleting a note.
|
||||
@@ -304,9 +307,16 @@ shared.initState = async function(comp: BaseNoteScreenComponent) {
|
||||
fromShare,
|
||||
noteResources: [],
|
||||
readOnly: true,
|
||||
noteLastLoadTime: Date.now(),
|
||||
});
|
||||
}
|
||||
|
||||
return note;
|
||||
};
|
||||
|
||||
shared.initState = async function(comp: BaseNoteScreenComponent) {
|
||||
const note = await shared.reloadNote(comp);
|
||||
|
||||
if (comp.props.sharedData) {
|
||||
if (comp.props.sharedData.title) {
|
||||
this.noteComponent_change(comp, 'title', comp.props.sharedData.title);
|
||||
|
@@ -170,6 +170,7 @@ export interface State extends WindowState {
|
||||
mustUpgradeAppMessage: string;
|
||||
mustAuthenticate: boolean;
|
||||
toast: Toast | null;
|
||||
editorNoteReloadTimeRequest: number;
|
||||
|
||||
allowSelectionInOtherFolders: boolean;
|
||||
|
||||
@@ -241,6 +242,7 @@ export const defaultState: State = {
|
||||
mustUpgradeAppMessage: '',
|
||||
mustAuthenticate: false,
|
||||
allowSelectionInOtherFolders: false,
|
||||
editorNoteReloadTimeRequest: 0,
|
||||
|
||||
pluginService: pluginServiceDefaultState,
|
||||
shareService: shareServiceDefaultState,
|
||||
@@ -1512,6 +1514,12 @@ const reducer = produce((draft: Draft<State> = defaultState, action: any) => {
|
||||
}
|
||||
break;
|
||||
|
||||
case 'EDITOR_NOTE_NEEDS_RELOAD':
|
||||
{
|
||||
draft.editorNoteReloadTimeRequest = Date.now();
|
||||
}
|
||||
break;
|
||||
|
||||
case 'TOAST_SHOW':
|
||||
draft.toast = {
|
||||
duration: 6000,
|
||||
|
@@ -157,10 +157,13 @@ export default class WebviewController extends ViewController {
|
||||
public emitUpdate() {
|
||||
if (!this.updateListener_) return;
|
||||
|
||||
if (this.containerType_ === ContainerType.Editor && (!this.isActive() || !this.isVisible())) {
|
||||
logger.info('emitMessage: Not emitting update because editor is disabled or hidden:', this.pluginId, this.handle, this.isActive(), this.isVisible());
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO:
|
||||
|
||||
// if (this.containerType_ === ContainerType.Editor && (!this.isActive() || !this.isVisible())) {
|
||||
// logger.info('emitMessage: Not emitting update because editor is disabled or hidden:', this.pluginId, this.handle, this.isActive(), this.isVisible());
|
||||
// return;
|
||||
// }
|
||||
|
||||
this.updateListener_();
|
||||
}
|
||||
@@ -279,7 +282,7 @@ export default class WebviewController extends ViewController {
|
||||
return this.storeView.opened;
|
||||
}
|
||||
|
||||
public async isVisible(): Promise<boolean> {
|
||||
public isVisible(): boolean {
|
||||
if (!this.storeView.opened) return false;
|
||||
const shownEditorViewIds: string[] = this.store.getState().settings['plugins.shownEditorViewIds'];
|
||||
return shownEditorViewIds.includes(this.handle);
|
||||
|
@@ -0,0 +1,10 @@
|
||||
import { PluginStates } from '../reducer';
|
||||
import getActivePluginEditorView from './getActivePluginEditorView';
|
||||
|
||||
export default (plugins: PluginStates, shownEditorViewIds: string[]) => {
|
||||
const { editorPlugin, editorView } = getActivePluginEditorView(plugins);
|
||||
if (editorView) {
|
||||
if (!shownEditorViewIds.includes(editorView.id)) return { editorPlugin: null, editorView: null };
|
||||
}
|
||||
return { editorPlugin, editorView };
|
||||
};
|
@@ -7468,6 +7468,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@fortawesome/fontawesome-free@npm:^6.7.2":
|
||||
version: 6.7.2
|
||||
resolution: "@fortawesome/fontawesome-free@npm:6.7.2"
|
||||
checksum: 2ceb384ada8e4a1e8a8e24384a35e3afa01589ddec67c8c52e3ad5d7db1662d0fc92560bd9a23baa4e0676e721e423aef99fb79fe6899bf13900fd1e611b6760
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@fortawesome/fontawesome-svg-core@npm:6.1.2":
|
||||
version: 6.1.2
|
||||
resolution: "@fortawesome/fontawesome-svg-core@npm:6.1.2"
|
||||
@@ -8355,6 +8362,7 @@ __metadata:
|
||||
"@babel/preset-env": 7.24.7
|
||||
"@babel/runtime": 7.24.7
|
||||
"@bam.tech/react-native-image-resizer": 3.0.10
|
||||
"@fortawesome/fontawesome-free": ^6.7.2
|
||||
"@joplin/editor": ~3.3
|
||||
"@joplin/lib": ~3.3
|
||||
"@joplin/react-native-alarm-notification": ~3.3
|
||||
|
Reference in New Issue
Block a user