You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-12-08 23:07:32 +02:00
Compare commits
2 Commits
v3.5.9
...
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/revealResourceFile.js
|
||||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/search.js
|
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/search.js
|
||||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/setTags.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/showModalMessage.js
|
||||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/showNoteContentProperties.js
|
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/showNoteContentProperties.js
|
||||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/showNoteProperties.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/showShareNoteDialog.js
|
||||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/showSpellCheckerMenu.test.js
|
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/showSpellCheckerMenu.test.js
|
||||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/showSpellCheckerMenu.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/toggleEditors.js
|
||||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/toggleLayoutMoveMode.js
|
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/toggleLayoutMoveMode.js
|
||||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/toggleMenuBar.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/permanentlyDeleteNote.js
|
||||||
packages/lib/commands/renderMarkup.test.js
|
packages/lib/commands/renderMarkup.test.js
|
||||||
packages/lib/commands/renderMarkup.js
|
packages/lib/commands/renderMarkup.js
|
||||||
|
packages/lib/commands/showEditorPlugin.js
|
||||||
packages/lib/commands/synchronize.js
|
packages/lib/commands/synchronize.js
|
||||||
|
packages/lib/commands/toggleEditorPlugin.js
|
||||||
packages/lib/components/EncryptionConfigScreen/utils.test.js
|
packages/lib/components/EncryptionConfigScreen/utils.test.js
|
||||||
packages/lib/components/EncryptionConfigScreen/utils.js
|
packages/lib/components/EncryptionConfigScreen/utils.js
|
||||||
packages/lib/components/shared/NoteList/getEmptyFolderMessage.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/getPluginNamespacedSettingKey.js
|
||||||
packages/lib/services/plugins/utils/getPluginSettingKeyPrefix.js
|
packages/lib/services/plugins/utils/getPluginSettingKeyPrefix.js
|
||||||
packages/lib/services/plugins/utils/getPluginSettingValue.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/getDefaultPlatforms.js
|
||||||
packages/lib/services/plugins/utils/isCompatible/index.test.js
|
packages/lib/services/plugins/utils/isCompatible/index.test.js
|
||||||
packages/lib/services/plugins/utils/isCompatible/index.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/revealResourceFile.js
|
||||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/search.js
|
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/search.js
|
||||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/setTags.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/showModalMessage.js
|
||||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/showNoteContentProperties.js
|
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/showNoteContentProperties.js
|
||||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/showNoteProperties.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/showShareNoteDialog.js
|
||||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/showSpellCheckerMenu.test.js
|
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/showSpellCheckerMenu.test.js
|
||||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/showSpellCheckerMenu.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/toggleEditors.js
|
||||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/toggleLayoutMoveMode.js
|
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/toggleLayoutMoveMode.js
|
||||||
packages/app-desktop/gui/WindowCommandsAndDialogs/commands/toggleMenuBar.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/permanentlyDeleteNote.js
|
||||||
packages/lib/commands/renderMarkup.test.js
|
packages/lib/commands/renderMarkup.test.js
|
||||||
packages/lib/commands/renderMarkup.js
|
packages/lib/commands/renderMarkup.js
|
||||||
|
packages/lib/commands/showEditorPlugin.js
|
||||||
packages/lib/commands/synchronize.js
|
packages/lib/commands/synchronize.js
|
||||||
|
packages/lib/commands/toggleEditorPlugin.js
|
||||||
packages/lib/components/EncryptionConfigScreen/utils.test.js
|
packages/lib/components/EncryptionConfigScreen/utils.test.js
|
||||||
packages/lib/components/EncryptionConfigScreen/utils.js
|
packages/lib/components/EncryptionConfigScreen/utils.js
|
||||||
packages/lib/components/shared/NoteList/getEmptyFolderMessage.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/getPluginNamespacedSettingKey.js
|
||||||
packages/lib/services/plugins/utils/getPluginSettingKeyPrefix.js
|
packages/lib/services/plugins/utils/getPluginSettingKeyPrefix.js
|
||||||
packages/lib/services/plugins/utils/getPluginSettingValue.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/getDefaultPlatforms.js
|
||||||
packages/lib/services/plugins/utils/isCompatible/index.test.js
|
packages/lib/services/plugins/utils/isCompatible/index.test.js
|
||||||
packages/lib/services/plugins/utils/isCompatible/index.js
|
packages/lib/services/plugins/utils/isCompatible/index.js
|
||||||
|
|||||||
@@ -1,15 +1,11 @@
|
|||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { PluginStates } from '@joplin/lib/services/plugins/reducer';
|
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
|
// If a plugin editor should be shown for the current note, this function will return the plugin and
|
||||||
// associated view.
|
// associated view.
|
||||||
export default (plugins: PluginStates, shownEditorViewIds: string[]) => {
|
export default (plugins: PluginStates, shownEditorViewIds: string[]) => {
|
||||||
return useMemo(() => {
|
return useMemo(() => {
|
||||||
const { editorPlugin, editorView } = getActivePluginEditorView(plugins);
|
return getShownPluginEditorView(plugins, shownEditorViewIds);
|
||||||
if (editorView) {
|
|
||||||
if (!shownEditorViewIds.includes(editorView.id)) return { editorPlugin: null, editorView: null };
|
|
||||||
}
|
|
||||||
return { editorPlugin, editorView };
|
|
||||||
}, [plugins, shownEditorViewIds]);
|
}, [plugins, shownEditorViewIds]);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import * as restoreNote from './restoreNote';
|
|||||||
import * as revealResourceFile from './revealResourceFile';
|
import * as revealResourceFile from './revealResourceFile';
|
||||||
import * as search from './search';
|
import * as search from './search';
|
||||||
import * as setTags from './setTags';
|
import * as setTags from './setTags';
|
||||||
import * as showEditorPlugin from './showEditorPlugin';
|
|
||||||
import * as showModalMessage from './showModalMessage';
|
import * as showModalMessage from './showModalMessage';
|
||||||
import * as showNoteContentProperties from './showNoteContentProperties';
|
import * as showNoteContentProperties from './showNoteContentProperties';
|
||||||
import * as showNoteProperties from './showNoteProperties';
|
import * as showNoteProperties from './showNoteProperties';
|
||||||
@@ -36,7 +35,6 @@ import * as showPrompt from './showPrompt';
|
|||||||
import * as showShareFolderDialog from './showShareFolderDialog';
|
import * as showShareFolderDialog from './showShareFolderDialog';
|
||||||
import * as showShareNoteDialog from './showShareNoteDialog';
|
import * as showShareNoteDialog from './showShareNoteDialog';
|
||||||
import * as showSpellCheckerMenu from './showSpellCheckerMenu';
|
import * as showSpellCheckerMenu from './showSpellCheckerMenu';
|
||||||
import * as toggleEditorPlugin from './toggleEditorPlugin';
|
|
||||||
import * as toggleEditors from './toggleEditors';
|
import * as toggleEditors from './toggleEditors';
|
||||||
import * as toggleLayoutMoveMode from './toggleLayoutMoveMode';
|
import * as toggleLayoutMoveMode from './toggleLayoutMoveMode';
|
||||||
import * as toggleMenuBar from './toggleMenuBar';
|
import * as toggleMenuBar from './toggleMenuBar';
|
||||||
@@ -78,7 +76,6 @@ const index: any[] = [
|
|||||||
revealResourceFile,
|
revealResourceFile,
|
||||||
search,
|
search,
|
||||||
setTags,
|
setTags,
|
||||||
showEditorPlugin,
|
|
||||||
showModalMessage,
|
showModalMessage,
|
||||||
showNoteContentProperties,
|
showNoteContentProperties,
|
||||||
showNoteProperties,
|
showNoteProperties,
|
||||||
@@ -86,7 +83,6 @@ const index: any[] = [
|
|||||||
showShareFolderDialog,
|
showShareFolderDialog,
|
||||||
showShareNoteDialog,
|
showShareNoteDialog,
|
||||||
showSpellCheckerMenu,
|
showSpellCheckerMenu,
|
||||||
toggleEditorPlugin,
|
|
||||||
toggleEditors,
|
toggleEditors,
|
||||||
toggleLayoutMoveMode,
|
toggleLayoutMoveMode,
|
||||||
toggleMenuBar,
|
toggleMenuBar,
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import WebBetaButton from './WebBetaButton';
|
|||||||
|
|
||||||
import Menu, { MenuOptionType } from './Menu';
|
import Menu, { MenuOptionType } from './Menu';
|
||||||
import shim from '@joplin/lib/shim';
|
import shim from '@joplin/lib/shim';
|
||||||
|
import CommandService from '@joplin/lib/services/CommandService';
|
||||||
export { MenuOptionType };
|
export { MenuOptionType };
|
||||||
|
|
||||||
// Rather than applying a padding to the whole bar, it is applied to each
|
// Rather than applying a padding to the whole bar, it is applied to each
|
||||||
@@ -67,6 +68,7 @@ interface ScreenHeaderProps {
|
|||||||
showSideMenuButton?: boolean;
|
showSideMenuButton?: boolean;
|
||||||
showSearchButton?: boolean;
|
showSearchButton?: boolean;
|
||||||
showContextMenuButton?: boolean;
|
showContextMenuButton?: boolean;
|
||||||
|
showPluginEditorButton?: boolean;
|
||||||
showBackButton?: boolean;
|
showBackButton?: boolean;
|
||||||
|
|
||||||
saveButtonDisabled?: 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
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||||
function deleteButton(styles: any, onPress: OnPressCallback, disabled: boolean) {
|
function deleteButton(styles: any, onPress: OnPressCallback, disabled: boolean) {
|
||||||
return (
|
return (
|
||||||
@@ -631,6 +655,8 @@ class ScreenHeaderComponent extends PureComponent<ScreenHeaderProps, ScreenHeade
|
|||||||
</Menu>
|
</Menu>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const togglePluginEditorButton = renderTogglePluginEditorButton(this.styles(), () => CommandService.instance().execute('toggleEditorPlugin'), false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={this.styles().container}>
|
<View style={this.styles().container}>
|
||||||
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
||||||
@@ -653,6 +679,7 @@ class ScreenHeaderComponent extends PureComponent<ScreenHeaderProps, ScreenHeade
|
|||||||
{restoreButtonComp}
|
{restoreButtonComp}
|
||||||
{duplicateButtonComp}
|
{duplicateButtonComp}
|
||||||
{sortButtonComp}
|
{sortButtonComp}
|
||||||
|
{togglePluginEditorButton}
|
||||||
{menuComp}
|
{menuComp}
|
||||||
</View>
|
</View>
|
||||||
<WarningBanner
|
<WarningBanner
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ const PluginDialogManager: React.FC<Props> = props => {
|
|||||||
|
|
||||||
const dialogs: ReactElement[] = [];
|
const dialogs: ReactElement[] = [];
|
||||||
for (const viewInfo of viewInfos) {
|
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;
|
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 uuid from '@joplin/lib/uuid';
|
||||||
import Setting from '@joplin/lib/models/Setting';
|
import Setting from '@joplin/lib/models/Setting';
|
||||||
import shim from '@joplin/lib/shim';
|
import shim from '@joplin/lib/shim';
|
||||||
@@ -51,7 +51,7 @@ import { getNoteCallbackUrl } from '@joplin/lib/callbackUrlUtils';
|
|||||||
import { AppState } from '../../../utils/types';
|
import { AppState } from '../../../utils/types';
|
||||||
import restoreItems from '@joplin/lib/services/trash/restoreItems';
|
import restoreItems from '@joplin/lib/services/trash/restoreItems';
|
||||||
import { getDisplayParentTitle } from '@joplin/lib/services/trash';
|
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 debounce from '../../../utils/debounce';
|
||||||
import { focus } from '@joplin/lib/utils/focusHandler';
|
import { focus } from '@joplin/lib/utils/focusHandler';
|
||||||
import CommandService, { RegisteredRuntime } from '@joplin/lib/services/CommandService';
|
import CommandService, { RegisteredRuntime } from '@joplin/lib/services/CommandService';
|
||||||
@@ -63,6 +63,14 @@ import { DialogContext, DialogControl } from '../../DialogManager';
|
|||||||
import { CommandRuntimeProps, EditorMode, PickerResponse } from './types';
|
import { CommandRuntimeProps, EditorMode, PickerResponse } from './types';
|
||||||
import commands from './commands';
|
import commands from './commands';
|
||||||
import { AttachFileAction, AttachFileOptions } from './commands/attachFile';
|
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
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||||
const emptyArray: any[] = [];
|
const emptyArray: any[] = [];
|
||||||
@@ -97,6 +105,9 @@ interface Props extends BaseProps {
|
|||||||
highlightedWords: string[];
|
highlightedWords: string[];
|
||||||
noteHash: string;
|
noteHash: string;
|
||||||
toolbarEnabled: boolean;
|
toolbarEnabled: boolean;
|
||||||
|
'plugins.shownEditorViewIds': string[];
|
||||||
|
pluginHtmlContents: PluginHtmlContents;
|
||||||
|
editorNoteReloadTimeRequest: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ComponentProps extends Props {
|
interface ComponentProps extends Props {
|
||||||
@@ -122,6 +133,7 @@ interface State {
|
|||||||
imageEditorResourceFilepath: string;
|
imageEditorResourceFilepath: string;
|
||||||
noteResources: Record<string, ResourceInfo>;
|
noteResources: Record<string, ResourceInfo>;
|
||||||
newAndNoTitleChangeNoteId: boolean|null;
|
newAndNoTitleChangeNoteId: boolean|null;
|
||||||
|
noteLastLoadTime: number;
|
||||||
|
|
||||||
undoRedoButtonState: {
|
undoRedoButtonState: {
|
||||||
canUndo: boolean;
|
canUndo: boolean;
|
||||||
@@ -131,6 +143,20 @@ interface State {
|
|||||||
voiceTypingDialogShown: boolean;
|
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 {
|
class NoteScreenComponent extends BaseScreenComponent<ComponentProps, State> implements BaseNoteScreenComponent {
|
||||||
// This isn't in this.state because we don't want changing scroll to trigger
|
// This isn't in this.state because we don't want changing scroll to trigger
|
||||||
// a re-render.
|
// a re-render.
|
||||||
@@ -163,6 +189,8 @@ class NoteScreenComponent extends BaseScreenComponent<ComponentProps, State> imp
|
|||||||
public dialogbox: any;
|
public dialogbox: any;
|
||||||
private commandRegistration_: RegisteredRuntime|null = null;
|
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
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||||
public static navigationOptions(): any {
|
public static navigationOptions(): any {
|
||||||
return { header: null };
|
return { header: null };
|
||||||
@@ -189,6 +217,7 @@ class NoteScreenComponent extends BaseScreenComponent<ComponentProps, State> imp
|
|||||||
noteResources: {},
|
noteResources: {},
|
||||||
imageEditorResourceFilepath: null,
|
imageEditorResourceFilepath: null,
|
||||||
newAndNoTitleChangeNoteId: null,
|
newAndNoTitleChangeNoteId: null,
|
||||||
|
noteLastLoadTime: Date.now(),
|
||||||
|
|
||||||
undoRedoButtonState: {
|
undoRedoButtonState: {
|
||||||
canUndo: false,
|
canUndo: false,
|
||||||
@@ -551,6 +580,9 @@ class NoteScreenComponent extends BaseScreenComponent<ComponentProps, State> imp
|
|||||||
}
|
}
|
||||||
}, 100);
|
}, 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
|
// 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,
|
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() {
|
public componentWillUnmount() {
|
||||||
@@ -1420,6 +1474,8 @@ class NoteScreenComponent extends BaseScreenComponent<ComponentProps, State> imp
|
|||||||
// multiple times.
|
// multiple times.
|
||||||
this.registerCommands();
|
this.registerCommands();
|
||||||
|
|
||||||
|
const { editorPlugin, editorView } = getShownPluginEditorView(this.props.plugins, this.props['plugins.shownEditorViewIds']);
|
||||||
|
|
||||||
if (this.state.isLoading) {
|
if (this.state.isLoading) {
|
||||||
return (
|
return (
|
||||||
<View style={this.styles().screen}>
|
<View style={this.styles().screen}>
|
||||||
@@ -1448,97 +1504,113 @@ 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.
|
// Currently keyword highlighting is supported only when FTS is available.
|
||||||
const keywords = this.props.searchQuery && !!this.props.ftsEnabled ? this.props.highlightedWords : emptyArray;
|
const keywords = this.props.searchQuery && !!this.props.ftsEnabled ? this.props.highlightedWords : emptyArray;
|
||||||
|
|
||||||
let bodyComponent = null;
|
let bodyComponent = null;
|
||||||
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,
|
if (editorView) {
|
||||||
// to avoid the HACK_webviewLoadingState related bug.
|
bodyComponent = renderPluginEditor();
|
||||||
bodyComponent =
|
|
||||||
!note || !note.body.trim() ? null : (
|
|
||||||
<NoteBodyViewer
|
|
||||||
onJoplinLinkClick={this.onJoplinLinkClick_}
|
|
||||||
style={this.styles().noteBodyViewer}
|
|
||||||
// Extra bottom padding to make it possible to scroll past the
|
|
||||||
// action button (so that it doesn't overlap the text)
|
|
||||||
paddingBottom={150}
|
|
||||||
noteBody={note.body}
|
|
||||||
noteMarkupLanguage={note.markup_language}
|
|
||||||
noteResources={this.state.noteResources}
|
|
||||||
highlightedKeywords={keywords}
|
|
||||||
themeId={this.props.themeId}
|
|
||||||
fontSize={this.props.viewerFontSize}
|
|
||||||
noteHash={this.props.noteHash}
|
|
||||||
onCheckboxChange={this.onBodyViewerCheckboxChange}
|
|
||||||
onMarkForDownload={this.onMarkForDownload}
|
|
||||||
onRequestEditResource={this.onEditResource}
|
|
||||||
onScroll={this.onBodyViewerScroll}
|
|
||||||
initialScroll={this.lastBodyScroll}
|
|
||||||
pluginStates={this.props.plugins}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
// Note: In theory ScrollView can be used to provide smoother scrolling of the TextInput.
|
if (this.state.mode === 'view') {
|
||||||
// However it causes memory or rendering issues on older Android devices, probably because
|
// Note: as of 2018-12-29 it's important not to display the viewer if the note body is empty,
|
||||||
// the whole text input has to be in memory for the scrollview to work. So we keep it as
|
// to avoid the HACK_webviewLoadingState related bug.
|
||||||
// a plain TextInput for now.
|
bodyComponent =
|
||||||
// See https://github.com/laurent22/joplin/issues/3041
|
!note || !note.body.trim() ? null : (
|
||||||
|
<NoteBodyViewer
|
||||||
// IMPORTANT: The TextInput selection is unreliable and cannot be used in a controlled component
|
onJoplinLinkClick={this.onJoplinLinkClick_}
|
||||||
// context. In other words, the selection should be considered read-only. For example, if the selection
|
style={this.styles().noteBodyViewer}
|
||||||
// is saved to the state in onSelectionChange and the current text in onChangeText, then set
|
// Extra bottom padding to make it possible to scroll past the
|
||||||
// back in `selection` and `value` props, it will mostly work. But when typing fast, sooner or
|
// action button (so that it doesn't overlap the text)
|
||||||
// later the real selection will be different from what is stored in the state, thus making
|
paddingBottom={150}
|
||||||
// the cursor jump around. Eg, when typing "abcdef", it will do this:
|
noteBody={note.body}
|
||||||
// abcd|
|
noteMarkupLanguage={note.markup_language}
|
||||||
// abcde|
|
noteResources={this.state.noteResources}
|
||||||
// abcde|f
|
highlightedKeywords={keywords}
|
||||||
|
themeId={this.props.themeId}
|
||||||
if (!this.useEditorBeta()) {
|
fontSize={this.props.viewerFontSize}
|
||||||
bodyComponent = (
|
noteHash={this.props.noteHash}
|
||||||
<TextInput
|
onCheckboxChange={this.onBodyViewerCheckboxChange}
|
||||||
autoCapitalize="sentences"
|
onMarkForDownload={this.onMarkForDownload}
|
||||||
style={this.styles().bodyTextInput}
|
onRequestEditResource={this.onEditResource}
|
||||||
ref="noteBodyTextField"
|
onScroll={this.onBodyViewerScroll}
|
||||||
multiline={true}
|
initialScroll={this.lastBodyScroll}
|
||||||
value={note.body}
|
pluginStates={this.props.plugins}
|
||||||
onChangeText={this.onPlainEditorTextChange}
|
/>
|
||||||
onSelectionChange={this.onPlainEditorSelectionChange}
|
);
|
||||||
blurOnSubmit={false}
|
|
||||||
selectionColor={theme.textSelectionColor}
|
|
||||||
keyboardAppearance={theme.keyboardAppearance}
|
|
||||||
placeholder={_('Add body')}
|
|
||||||
placeholderTextColor={theme.colorFaded}
|
|
||||||
// need some extra padding for iOS so that the keyboard won't cover last line of the note
|
|
||||||
// see https://github.com/laurent22/joplin/issues/3607
|
|
||||||
// Property is gone as of RN 0.72?
|
|
||||||
// paddingBottom={ (Platform.OS === 'ios' ? 40 : 0) as any}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
const editorStyle = this.styles().bodyTextInput;
|
// Note: In theory ScrollView can be used to provide smoother scrolling of the TextInput.
|
||||||
|
// However it causes memory or rendering issues on older Android devices, probably because
|
||||||
|
// the whole text input has to be in memory for the scrollview to work. So we keep it as
|
||||||
|
// a plain TextInput for now.
|
||||||
|
// See https://github.com/laurent22/joplin/issues/3041
|
||||||
|
|
||||||
bodyComponent = <NoteEditor
|
// IMPORTANT: The TextInput selection is unreliable and cannot be used in a controlled component
|
||||||
ref={this.editorRef}
|
// context. In other words, the selection should be considered read-only. For example, if the selection
|
||||||
toolbarEnabled={this.props.toolbarEnabled}
|
// is saved to the state in onSelectionChange and the current text in onChangeText, then set
|
||||||
themeId={this.props.themeId}
|
// back in `selection` and `value` props, it will mostly work. But when typing fast, sooner or
|
||||||
initialText={note.body}
|
// later the real selection will be different from what is stored in the state, thus making
|
||||||
initialSelection={this.selection}
|
// the cursor jump around. Eg, when typing "abcdef", it will do this:
|
||||||
onChange={this.onMarkdownEditorTextChange}
|
// abcd|
|
||||||
onSelectionChange={this.onMarkdownEditorSelectionChange}
|
// abcde|
|
||||||
onUndoRedoDepthChange={this.onUndoRedoDepthChange}
|
// abcde|f
|
||||||
onAttach={this.onAttach}
|
|
||||||
readOnly={this.state.readOnly}
|
|
||||||
plugins={this.props.plugins}
|
|
||||||
style={{
|
|
||||||
...editorStyle,
|
|
||||||
|
|
||||||
// Allow the editor to set its own padding
|
if (!this.useEditorBeta()) {
|
||||||
paddingLeft: 0,
|
bodyComponent = (
|
||||||
paddingRight: 0,
|
<TextInput
|
||||||
}}
|
autoCapitalize="sentences"
|
||||||
/>;
|
style={this.styles().bodyTextInput}
|
||||||
|
ref="noteBodyTextField"
|
||||||
|
multiline={true}
|
||||||
|
value={note.body}
|
||||||
|
onChangeText={this.onPlainEditorTextChange}
|
||||||
|
onSelectionChange={this.onPlainEditorSelectionChange}
|
||||||
|
blurOnSubmit={false}
|
||||||
|
selectionColor={theme.textSelectionColor}
|
||||||
|
keyboardAppearance={theme.keyboardAppearance}
|
||||||
|
placeholder={_('Add body')}
|
||||||
|
placeholderTextColor={theme.colorFaded}
|
||||||
|
// need some extra padding for iOS so that the keyboard won't cover last line of the note
|
||||||
|
// see https://github.com/laurent22/joplin/issues/3607
|
||||||
|
// Property is gone as of RN 0.72?
|
||||||
|
// paddingBottom={ (Platform.OS === 'ios' ? 40 : 0) as any}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
const editorStyle = this.styles().bodyTextInput;
|
||||||
|
|
||||||
|
bodyComponent = <NoteEditor
|
||||||
|
ref={this.editorRef}
|
||||||
|
toolbarEnabled={this.props.toolbarEnabled}
|
||||||
|
themeId={this.props.themeId}
|
||||||
|
initialText={note.body}
|
||||||
|
initialSelection={this.selection}
|
||||||
|
onChange={this.onMarkdownEditorTextChange}
|
||||||
|
onSelectionChange={this.onMarkdownEditorSelectionChange}
|
||||||
|
onUndoRedoDepthChange={this.onUndoRedoDepthChange}
|
||||||
|
onAttach={this.onAttach}
|
||||||
|
readOnly={this.state.readOnly}
|
||||||
|
plugins={this.props.plugins}
|
||||||
|
style={{
|
||||||
|
...editorStyle,
|
||||||
|
|
||||||
|
// Allow the editor to set its own padding
|
||||||
|
paddingLeft: 0,
|
||||||
|
paddingRight: 0,
|
||||||
|
}}
|
||||||
|
/>;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1595,6 +1667,8 @@ class NoteScreenComponent extends BaseScreenComponent<ComponentProps, State> imp
|
|||||||
return <VoiceTypingDialog locale={currentLocale()} onText={this.voiceTypingDialog_onText} onDismiss={this.voiceTypingDialog_onDismiss}/>;
|
return <VoiceTypingDialog locale={currentLocale()} onText={this.voiceTypingDialog_onText} onDismiss={this.voiceTypingDialog_onDismiss}/>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const { editorPlugin: activeEditorPlugin } = getActivePluginEditorView(this.props.plugins);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={this.rootStyle(this.props.themeId).root}>
|
<View style={this.rootStyle(this.props.themeId).root}>
|
||||||
<ScreenHeader
|
<ScreenHeader
|
||||||
@@ -1607,6 +1681,7 @@ class NoteScreenComponent extends BaseScreenComponent<ComponentProps, State> imp
|
|||||||
showSearchButton={false}
|
showSearchButton={false}
|
||||||
showUndoButton={(this.state.undoRedoButtonState.canUndo || this.state.undoRedoButtonState.canRedo) && this.state.mode === 'edit'}
|
showUndoButton={(this.state.undoRedoButtonState.canUndo || this.state.undoRedoButtonState.canRedo) && this.state.mode === 'edit'}
|
||||||
showRedoButton={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}
|
undoButtonDisabled={!this.state.undoRedoButtonState.canUndo && this.state.undoRedoButtonState.canRedo}
|
||||||
onUndoButtonPress={this.screenHeader_undoButtonPress}
|
onUndoButtonPress={this.screenHeader_undoButtonPress}
|
||||||
onRedoButtonPress={this.screenHeader_redoButtonPress}
|
onRedoButtonPress={this.screenHeader_redoButtonPress}
|
||||||
@@ -1654,6 +1729,9 @@ const NoteScreen = connect((state: AppState) => {
|
|||||||
provisionalNoteIds: state.provisionalNoteIds,
|
provisionalNoteIds: state.provisionalNoteIds,
|
||||||
highlightedWords: state.highlightedWords,
|
highlightedWords: state.highlightedWords,
|
||||||
plugins: state.pluginService.plugins,
|
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
|
// What we call "beta editor" in this component is actually the (now
|
||||||
// default) CodeMirror editor. That should be refactored to make it less
|
// default) CodeMirror editor. That should be refactored to make it less
|
||||||
|
|||||||
@@ -288,7 +288,14 @@ class NotesScreenComponent extends BaseScreenComponent<ComponentProps, State> {
|
|||||||
|
|
||||||
inert={accessibilityHidden}
|
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 />
|
<NoteList />
|
||||||
{actionButtonComp}
|
{actionButtonComp}
|
||||||
</AccessibleView>
|
</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 md5 = require('md5');
|
||||||
|
|
||||||
const rootDir = `${__dirname}/..`;
|
const rootDir = `${__dirname}/..`;
|
||||||
const outputDir = `${rootDir}/pluginAssets`;
|
const defaultOutputDir = `${rootDir}/pluginAssets`;
|
||||||
|
|
||||||
const walk = function(dir) {
|
const walk = function(dir) {
|
||||||
let results = [];
|
let results = [];
|
||||||
@@ -37,7 +37,7 @@ const readAsBase64 = async (path, mime) => {
|
|||||||
return buffer.toString('base64');
|
return buffer.toString('base64');
|
||||||
};
|
};
|
||||||
|
|
||||||
async function encodeFile(sourcePath, destPath) {
|
async function encodeFile(sourcePath, destPath, outputDir) {
|
||||||
const ext = utils.fileExtension(sourcePath).toLowerCase();
|
const ext = utils.fileExtension(sourcePath).toLowerCase();
|
||||||
let mime = 'application/octet-stream';
|
let mime = 'application/octet-stream';
|
||||||
if (ext === 'js') mime = 'application/javascript';
|
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++) {
|
for (let i = 0; i < 3; i++) {
|
||||||
try {
|
try {
|
||||||
|
const outputDir = sourceAssetDir.destination ? sourceAssetDir.destination : defaultOutputDir;
|
||||||
|
|
||||||
await fs.remove(outputDir);
|
await fs.remove(outputDir);
|
||||||
await utils.mkdirp(outputDir);
|
await utils.mkdirp(outputDir);
|
||||||
|
|
||||||
const encodedFiles = [];
|
const encodedFiles = [];
|
||||||
const sourceAssetDir = `${rootDir}/../renderer/assets`;
|
const files = walk(sourceAssetDir.source);
|
||||||
const files = walk(sourceAssetDir);
|
|
||||||
|
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
const destFile = file.substr(sourceAssetDir.length + 1);
|
if (file.endsWith('.DS_Store')) continue;
|
||||||
encodedFiles.push(await encodeFile(file, destFile));
|
const destFile = file.substr(sourceAssetDir.source.length + 1);
|
||||||
|
encodedFiles.push(await encodeFile(file, destFile, outputDir));
|
||||||
}
|
}
|
||||||
|
|
||||||
const hashes = [];
|
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.js`, `module.exports = {\nhash:"${hash}", files: {\n${indexJs.join('\n')}\n}\n};`);
|
||||||
await fs.writeFile(`${outputDir}/index.web.js`, `module.exports = ${JSON.stringify({
|
await fs.writeFile(`${outputDir}/index.web.js`, `module.exports = ${JSON.stringify({
|
||||||
hash,
|
hash,
|
||||||
files: files.map(file => toForwardSlashes(path.relative(sourceAssetDir, file))),
|
files: files.map(file => toForwardSlashes(path.relative(sourceAssetDir.source, file))),
|
||||||
})}`);
|
})}`);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -115,6 +131,28 @@ async function main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
throw new Error('Could not encode file after multiple attempts. See above for errors.');
|
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;
|
module.exports = main;
|
||||||
|
|||||||
@@ -5,7 +5,9 @@ import * as historyForward from './historyForward';
|
|||||||
import * as openMasterPasswordDialog from './openMasterPasswordDialog';
|
import * as openMasterPasswordDialog from './openMasterPasswordDialog';
|
||||||
import * as permanentlyDeleteNote from './permanentlyDeleteNote';
|
import * as permanentlyDeleteNote from './permanentlyDeleteNote';
|
||||||
import * as renderMarkup from './renderMarkup';
|
import * as renderMarkup from './renderMarkup';
|
||||||
|
import * as showEditorPlugin from './showEditorPlugin';
|
||||||
import * as synchronize from './synchronize';
|
import * as synchronize from './synchronize';
|
||||||
|
import * as toggleEditorPlugin from './toggleEditorPlugin';
|
||||||
|
|
||||||
const index: any[] = [
|
const index: any[] = [
|
||||||
deleteNote,
|
deleteNote,
|
||||||
@@ -14,7 +16,9 @@ const index: any[] = [
|
|||||||
openMasterPasswordDialog,
|
openMasterPasswordDialog,
|
||||||
permanentlyDeleteNote,
|
permanentlyDeleteNote,
|
||||||
renderMarkup,
|
renderMarkup,
|
||||||
|
showEditorPlugin,
|
||||||
synchronize,
|
synchronize,
|
||||||
|
toggleEditorPlugin,
|
||||||
];
|
];
|
||||||
|
|
||||||
export default index;
|
export default index;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { CommandContext, CommandDeclaration, CommandRuntime } from '@joplin/lib/services/CommandService';
|
import { CommandContext, CommandDeclaration, CommandRuntime } from '../services/CommandService';
|
||||||
import Setting from '@joplin/lib/models/Setting';
|
import Setting from '../models/Setting';
|
||||||
import getActivePluginEditorView from '@joplin/lib/services/plugins/utils/getActivePluginEditorView';
|
import getActivePluginEditorView from '../services/plugins/utils/getActivePluginEditorView';
|
||||||
import Logger from '@joplin/utils/Logger';
|
import Logger from '@joplin/utils/Logger';
|
||||||
|
|
||||||
const logger = Logger.create('showEditorPlugin');
|
const logger = Logger.create('showEditorPlugin');
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { CommandContext, CommandDeclaration, CommandRuntime } from '@joplin/lib/services/CommandService';
|
import { CommandContext, CommandDeclaration, CommandRuntime } from '../services/CommandService';
|
||||||
import { _ } from '@joplin/lib/locale';
|
import { _ } from '../locale';
|
||||||
import Setting from '@joplin/lib/models/Setting';
|
import Setting from '../models/Setting';
|
||||||
import getActivePluginEditorView from '@joplin/lib/services/plugins/utils/getActivePluginEditorView';
|
import getActivePluginEditorView from '../services/plugins/utils/getActivePluginEditorView';
|
||||||
import Logger from '@joplin/utils/Logger';
|
import Logger from '@joplin/utils/Logger';
|
||||||
|
|
||||||
const logger = Logger.create('toggleEditorPlugin');
|
const logger = Logger.create('toggleEditorPlugin');
|
||||||
@@ -24,14 +24,26 @@ export const runtime = (): CommandRuntime => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const idx = shownEditorViewIds.indexOf(editorView.id);
|
const idx = shownEditorViewIds.indexOf(editorView.id);
|
||||||
|
let hasBeenHidden = false;
|
||||||
|
|
||||||
if (idx < 0) {
|
if (idx < 0) {
|
||||||
shownEditorViewIds.push(editorView.id);
|
shownEditorViewIds.push(editorView.id);
|
||||||
} else {
|
} else {
|
||||||
shownEditorViewIds.splice(idx, 1);
|
shownEditorViewIds.splice(idx, 1);
|
||||||
|
hasBeenHidden = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.info('New shown editor views: ', shownEditorViewIds);
|
||||||
|
|
||||||
Setting.setValue('plugins.shownEditorViewIds', 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;
|
installResourceHandling?: (refreshResourceHandler: any)=> void;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||||
uninstallResourceHandling?: (refreshResourceHandler: any)=> void;
|
uninstallResourceHandling?: (refreshResourceHandler: any)=> void;
|
||||||
|
|
||||||
|
reloadNote?: (comp: BaseNoteScreenComponent)=> Promise<NoteEntity>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const shared: Shared = {};
|
const shared: Shared = {};
|
||||||
@@ -268,7 +270,7 @@ shared.isModified = function(comp: BaseNoteScreenComponent) {
|
|||||||
return !!Object.getOwnPropertyNames(diff).length;
|
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 isProvisionalNote = comp.props.provisionalNoteIds.includes(comp.props.noteId);
|
||||||
|
|
||||||
const note = await Note.load(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,
|
fromShare: !!comp.props.sharedData,
|
||||||
noteResources: await shared.attachedResources(note ? note.body : ''),
|
noteResources: await shared.attachedResources(note ? note.body : ''),
|
||||||
readOnly: itemIsReadOnlySync(ModelType.Note, ItemChange.SOURCE_UNSPECIFIED, note as ItemSlice, Setting.value('sync.userId'), BaseItem.syncShareCache),
|
readOnly: itemIsReadOnlySync(ModelType.Note, ItemChange.SOURCE_UNSPECIFIED, note as ItemSlice, Setting.value('sync.userId'), BaseItem.syncShareCache),
|
||||||
|
noteLastLoadTime: Date.now(),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Handle the case where a non-existent note is loaded. This can happen briefly after deleting a note.
|
// 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,
|
fromShare,
|
||||||
noteResources: [],
|
noteResources: [],
|
||||||
readOnly: true,
|
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) {
|
||||||
if (comp.props.sharedData.title) {
|
if (comp.props.sharedData.title) {
|
||||||
this.noteComponent_change(comp, 'title', comp.props.sharedData.title);
|
this.noteComponent_change(comp, 'title', comp.props.sharedData.title);
|
||||||
|
|||||||
@@ -170,6 +170,7 @@ export interface State extends WindowState {
|
|||||||
mustUpgradeAppMessage: string;
|
mustUpgradeAppMessage: string;
|
||||||
mustAuthenticate: boolean;
|
mustAuthenticate: boolean;
|
||||||
toast: Toast | null;
|
toast: Toast | null;
|
||||||
|
editorNoteReloadTimeRequest: number;
|
||||||
|
|
||||||
allowSelectionInOtherFolders: boolean;
|
allowSelectionInOtherFolders: boolean;
|
||||||
|
|
||||||
@@ -241,6 +242,7 @@ export const defaultState: State = {
|
|||||||
mustUpgradeAppMessage: '',
|
mustUpgradeAppMessage: '',
|
||||||
mustAuthenticate: false,
|
mustAuthenticate: false,
|
||||||
allowSelectionInOtherFolders: false,
|
allowSelectionInOtherFolders: false,
|
||||||
|
editorNoteReloadTimeRequest: 0,
|
||||||
|
|
||||||
pluginService: pluginServiceDefaultState,
|
pluginService: pluginServiceDefaultState,
|
||||||
shareService: shareServiceDefaultState,
|
shareService: shareServiceDefaultState,
|
||||||
@@ -1512,6 +1514,12 @@ const reducer = produce((draft: Draft<State> = defaultState, action: any) => {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'EDITOR_NOTE_NEEDS_RELOAD':
|
||||||
|
{
|
||||||
|
draft.editorNoteReloadTimeRequest = Date.now();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case 'TOAST_SHOW':
|
case 'TOAST_SHOW':
|
||||||
draft.toast = {
|
draft.toast = {
|
||||||
duration: 6000,
|
duration: 6000,
|
||||||
|
|||||||
@@ -157,10 +157,13 @@ export default class WebviewController extends ViewController {
|
|||||||
public emitUpdate() {
|
public emitUpdate() {
|
||||||
if (!this.updateListener_) return;
|
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());
|
// TODO:
|
||||||
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;
|
||||||
|
// }
|
||||||
|
|
||||||
this.updateListener_();
|
this.updateListener_();
|
||||||
}
|
}
|
||||||
@@ -279,7 +282,7 @@ export default class WebviewController extends ViewController {
|
|||||||
return this.storeView.opened;
|
return this.storeView.opened;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async isVisible(): Promise<boolean> {
|
public isVisible(): boolean {
|
||||||
if (!this.storeView.opened) return false;
|
if (!this.storeView.opened) return false;
|
||||||
const shownEditorViewIds: string[] = this.store.getState().settings['plugins.shownEditorViewIds'];
|
const shownEditorViewIds: string[] = this.store.getState().settings['plugins.shownEditorViewIds'];
|
||||||
return shownEditorViewIds.includes(this.handle);
|
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
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"@fortawesome/fontawesome-svg-core@npm:6.1.2":
|
||||||
version: 6.1.2
|
version: 6.1.2
|
||||||
resolution: "@fortawesome/fontawesome-svg-core@npm:6.1.2"
|
resolution: "@fortawesome/fontawesome-svg-core@npm:6.1.2"
|
||||||
@@ -8355,6 +8362,7 @@ __metadata:
|
|||||||
"@babel/preset-env": 7.24.7
|
"@babel/preset-env": 7.24.7
|
||||||
"@babel/runtime": 7.24.7
|
"@babel/runtime": 7.24.7
|
||||||
"@bam.tech/react-native-image-resizer": 3.0.10
|
"@bam.tech/react-native-image-resizer": 3.0.10
|
||||||
|
"@fortawesome/fontawesome-free": ^6.7.2
|
||||||
"@joplin/editor": ~3.3
|
"@joplin/editor": ~3.3
|
||||||
"@joplin/lib": ~3.3
|
"@joplin/lib": ~3.3
|
||||||
"@joplin/react-native-alarm-notification": ~3.3
|
"@joplin/react-native-alarm-notification": ~3.3
|
||||||
|
|||||||
Reference in New Issue
Block a user