You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-11-23 22:36:32 +02:00
This commit is contained in:
@@ -11,6 +11,7 @@ export const initializeEditor = ({
|
||||
initialText,
|
||||
initialNoteId,
|
||||
settings,
|
||||
onLocalize,
|
||||
}: EditorProps) => {
|
||||
const messenger = new WebViewToRNMessenger<EditorProcessApi, MainProcessApi>('markdownEditor', null);
|
||||
|
||||
@@ -23,6 +24,7 @@ export const initializeEditor = ({
|
||||
initialText,
|
||||
initialNoteId,
|
||||
settings,
|
||||
onLocalize,
|
||||
|
||||
onPasteFile: async (data) => {
|
||||
const base64 = await readFileToBase64(data);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { EditorEvent } from '@joplin/editor/events';
|
||||
import { EditorControl, EditorSettings } from '@joplin/editor/types';
|
||||
import { EditorControl, EditorSettings, OnLocalize } from '@joplin/editor/types';
|
||||
|
||||
export interface EditorProcessApi {
|
||||
editor: EditorControl;
|
||||
@@ -14,6 +14,7 @@ export interface EditorProps {
|
||||
parentElementClassName: string;
|
||||
initialText: string;
|
||||
initialNoteId: string;
|
||||
onLocalize: OnLocalize;
|
||||
settings: EditorSettings;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ const defaultRendererSettings: RenderSettings = {
|
||||
noteHash: '',
|
||||
initialScroll: 0,
|
||||
readAssetBlob: async (_path: string) => new Blob(),
|
||||
removeUnusedPluginAssets: true,
|
||||
|
||||
createEditPopupSyntax: '',
|
||||
destroyEditPopupSyntax: '',
|
||||
|
||||
@@ -23,6 +23,7 @@ export interface RenderSettings {
|
||||
initialScroll: number;
|
||||
// If [null], plugin assets are not added to the document
|
||||
pluginAssetContainerSelector: string|null;
|
||||
removeUnusedPluginAssets: boolean;
|
||||
|
||||
splitted?: boolean; // Move CSS into a separate output
|
||||
mapsToLine?: boolean; // Sourcemaps
|
||||
@@ -156,6 +157,7 @@ export default class Renderer {
|
||||
inlineAssets: this.setupOptions_.useTransferredFiles,
|
||||
readAssetBlob: settings.readAssetBlob,
|
||||
container: document.querySelector(settings.pluginAssetContainerSelector),
|
||||
removeUnusedPluginAssets: settings.removeUnusedPluginAssets,
|
||||
});
|
||||
|
||||
// Some plugins require this event to be dispatched just after being added.
|
||||
|
||||
@@ -39,6 +39,7 @@ const rewriteInternalAssetLinks = async (asset: RenderResultPluginAsset, content
|
||||
|
||||
interface Options {
|
||||
inlineAssets: boolean;
|
||||
removeUnusedPluginAssets: boolean;
|
||||
container: HTMLElement;
|
||||
readAssetBlob?(path: string): Promise<Blob>;
|
||||
}
|
||||
@@ -137,16 +138,22 @@ const addPluginAssets = async (assets: RenderResultPluginAsset[], options: Optio
|
||||
// light to dark theme, and then back to light theme - in that case
|
||||
// the viewer would remain dark because it would use the dark
|
||||
// stylesheet that would still be in the DOM.
|
||||
for (const [assetId, asset] of Object.entries(pluginAssetsAdded_)) {
|
||||
if (!processedAssetIds.includes(assetId)) {
|
||||
try {
|
||||
asset.element.remove();
|
||||
} catch (error) {
|
||||
// We don't throw an exception but we log it since
|
||||
// it shouldn't happen
|
||||
console.warn('Tried to remove an asset but got an error', error);
|
||||
//
|
||||
// In some cases, however, we only want to rerender part of the document.
|
||||
// In this case, old plugin assets may have been from the last full-page
|
||||
// render and should not be removed.
|
||||
if (options.removeUnusedPluginAssets) {
|
||||
for (const [assetId, asset] of Object.entries(pluginAssetsAdded_)) {
|
||||
if (!processedAssetIds.includes(assetId)) {
|
||||
try {
|
||||
asset.element.remove();
|
||||
} catch (error) {
|
||||
// We don't throw an exception but we log it since
|
||||
// it shouldn't happen
|
||||
console.warn('Tried to remove an asset but got an error', error);
|
||||
}
|
||||
pluginAssetsAdded_[assetId] = null;
|
||||
}
|
||||
pluginAssetsAdded_[assetId] = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -54,8 +54,13 @@ export interface RenderOptions {
|
||||
highlightedKeywords: string[];
|
||||
resources: ResourceInfos;
|
||||
themeOverrides: Record<string, string|number>;
|
||||
|
||||
// If null, plugin assets will not be added to the document.
|
||||
pluginAssetContainerSelector: string|null;
|
||||
// When true, plugin assets are removed from the container when not used by the render result.
|
||||
// This should be true for full-page renders.
|
||||
removeUnusedPluginAssets: boolean;
|
||||
|
||||
noteHash: string;
|
||||
initialScroll: number;
|
||||
|
||||
|
||||
@@ -219,6 +219,7 @@ const useWebViewSetup = (props: Props): SetUpResult<RendererControl> => {
|
||||
}
|
||||
return shim.fsDriver().fileAtPath(resolvedPath);
|
||||
},
|
||||
removeUnusedPluginAssets: options.removeUnusedPluginAssets,
|
||||
};
|
||||
|
||||
await transferResources(options.resources);
|
||||
|
||||
@@ -16,22 +16,6 @@ const postprocessHtml = (html: HTMLElement) => {
|
||||
resource.src = `:/${resourceId}`;
|
||||
}
|
||||
|
||||
// Re-add newlines to data-joplin-source-* that were removed
|
||||
// by ProseMirror.
|
||||
// TODO: Try to find a better solution
|
||||
const sourceBlocks = html.querySelectorAll<HTMLPreElement>(
|
||||
'pre[data-joplin-source-open][data-joplin-source-close].joplin-source',
|
||||
);
|
||||
for (const sourceBlock of sourceBlocks) {
|
||||
const isBlock = sourceBlock.parentElement.tagName !== 'SPAN';
|
||||
if (isBlock) {
|
||||
const originalOpen = sourceBlock.getAttribute('data-joplin-source-open');
|
||||
const originalClose = sourceBlock.getAttribute('data-joplin-source-close');
|
||||
sourceBlock.setAttribute('data-joplin-source-open', `${originalOpen}\n`);
|
||||
sourceBlock.setAttribute('data-joplin-source-close', `\n${originalClose}`);
|
||||
}
|
||||
}
|
||||
|
||||
return html;
|
||||
};
|
||||
|
||||
@@ -73,6 +57,7 @@ export const initialize = async ({
|
||||
settings,
|
||||
initialText,
|
||||
initialNoteId,
|
||||
onLocalize: messenger.remoteApi.onLocalize,
|
||||
|
||||
onPasteFile: async (data) => {
|
||||
const base64 = await readFileToBase64(data);
|
||||
@@ -85,14 +70,20 @@ export const initialize = async ({
|
||||
void messenger.remoteApi.onEditorEvent(event);
|
||||
},
|
||||
}, {
|
||||
renderMarkupToHtml: async (markup) => {
|
||||
renderMarkupToHtml: async (markup, options) => {
|
||||
let language = MarkupLanguage.Markdown;
|
||||
if (settings.language === EditorLanguageType.Html && !options.forceMarkdown) {
|
||||
language = MarkupLanguage.Html;
|
||||
}
|
||||
|
||||
return await messenger.remoteApi.onRender({
|
||||
markup,
|
||||
language: settings.language === EditorLanguageType.Html ? MarkupLanguage.Html : MarkupLanguage.Markdown,
|
||||
language,
|
||||
}, {
|
||||
pluginAssetContainerSelector: `#${assetContainer.id}`,
|
||||
splitted: true,
|
||||
mapsToLine: true,
|
||||
removeUnusedPluginAssets: options.isFullPageRender,
|
||||
});
|
||||
},
|
||||
renderHtmlToMarkup: (node) => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { EditorEvent } from '@joplin/editor/events';
|
||||
import { EditorControl, EditorSettings, SearchState } from '@joplin/editor/types';
|
||||
import { EditorControl, EditorSettings, OnLocalize, SearchState } from '@joplin/editor/types';
|
||||
import { MarkupRecord, RendererControl } from '../rendererBundle/types';
|
||||
import { RenderResult } from '@joplin/renderer/types';
|
||||
|
||||
@@ -19,6 +19,7 @@ type RenderOptionsSlice = {
|
||||
pluginAssetContainerSelector: string;
|
||||
splitted: boolean;
|
||||
mapsToLine: true;
|
||||
removeUnusedPluginAssets: boolean;
|
||||
};
|
||||
|
||||
export interface MainProcessApi {
|
||||
@@ -26,6 +27,7 @@ export interface MainProcessApi {
|
||||
logMessage(message: string): Promise<void>;
|
||||
onRender(markup: MarkupRecord, options: RenderOptionsSlice): Promise<RenderResult>;
|
||||
onPasteFile(type: string, base64: string): Promise<void>;
|
||||
onLocalize: OnLocalize;
|
||||
}
|
||||
|
||||
export interface RichTextEditorControl {
|
||||
|
||||
@@ -11,6 +11,7 @@ import shim from '@joplin/lib/shim';
|
||||
import { PluginStates } from '@joplin/lib/services/plugins/reducer';
|
||||
import { RendererControl, RenderOptions } from '../rendererBundle/types';
|
||||
import { ResourceInfos } from '@joplin/renderer/types';
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import { defaultSearchState } from '../../components/NoteEditor/SearchPanel';
|
||||
|
||||
const logger = Logger.create('useWebViewSetup');
|
||||
@@ -50,6 +51,7 @@ const useMessenger = (props: UseMessengerProps) => {
|
||||
noteHash: '',
|
||||
initialScroll: 0,
|
||||
pluginAssetContainerSelector: null,
|
||||
removeUnusedPluginAssets: true,
|
||||
};
|
||||
|
||||
return useMemo(() => {
|
||||
@@ -70,6 +72,7 @@ const useMessenger = (props: UseMessengerProps) => {
|
||||
splitted: options.splitted,
|
||||
pluginAssetContainerSelector: options.pluginAssetContainerSelector,
|
||||
mapsToLine: options.mapsToLine,
|
||||
removeUnusedPluginAssets: options.removeUnusedPluginAssets,
|
||||
},
|
||||
);
|
||||
return renderResult;
|
||||
@@ -77,6 +80,7 @@ const useMessenger = (props: UseMessengerProps) => {
|
||||
onPasteFile: async (type: string, base64: string) => {
|
||||
onAttachRef.current(type, base64);
|
||||
},
|
||||
onLocalize: _,
|
||||
};
|
||||
|
||||
const messenger = new RNToWebViewMessenger<MainProcessApi, EditorProcessApi>(
|
||||
|
||||
Reference in New Issue
Block a user