You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-11-23 22:36:32 +02:00
131 lines
4.4 KiB
TypeScript
131 lines
4.4 KiB
TypeScript
import '../../utils/polyfills';
|
|
import { createEditor } from '@joplin/editor/ProseMirror';
|
|
import { EditorProcessApi, EditorProps, MainProcessApi } from '../types';
|
|
import WebViewToRNMessenger from '../../../utils/ipc/WebViewToRNMessenger';
|
|
import { MarkupLanguage } from '@joplin/renderer/types';
|
|
import '@joplin/editor/ProseMirror/styles';
|
|
import readFileToBase64 from '../../utils/readFileToBase64';
|
|
import { EditorLanguageType } from '@joplin/editor/types';
|
|
import convertHtmlToMarkdown from './convertHtmlToMarkdown';
|
|
|
|
const postprocessHtml = (html: HTMLElement) => {
|
|
// Fix resource URLs
|
|
const resources = html.querySelectorAll<HTMLImageElement>('img[data-resource-id]');
|
|
for (const resource of resources) {
|
|
const resourceId = resource.getAttribute('data-resource-id');
|
|
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;
|
|
};
|
|
|
|
const wrapHtmlForMarkdownConversion = (html: HTMLElement) => {
|
|
// Add a container element -- when converting to HTML, Turndown
|
|
// sometimes doesn't process the toplevel element in the same way
|
|
// as other elements (e.g. in the case of Joplin source blocks).
|
|
const wrapper = html.ownerDocument.createElement('div');
|
|
wrapper.appendChild(html.cloneNode(true));
|
|
return wrapper;
|
|
};
|
|
|
|
|
|
const htmlToMarkdown = (html: HTMLElement): string => {
|
|
html = postprocessHtml(html);
|
|
|
|
return convertHtmlToMarkdown(html);
|
|
};
|
|
|
|
export const initialize = async ({
|
|
settings,
|
|
initialText,
|
|
initialNoteId,
|
|
parentElementClassName,
|
|
}: EditorProps) => {
|
|
const messenger = new WebViewToRNMessenger<EditorProcessApi, MainProcessApi>('rich-text-editor', null);
|
|
const parentElement = document.getElementsByClassName(parentElementClassName)[0];
|
|
if (!parentElement) throw new Error('Parent element not found');
|
|
if (!(parentElement instanceof HTMLElement)) {
|
|
throw new Error('Parent node is not an element.');
|
|
}
|
|
|
|
const assetContainer = document.createElement('div');
|
|
assetContainer.id = 'joplin-container-pluginAssetsContainer';
|
|
document.body.appendChild(assetContainer);
|
|
|
|
const editor = await createEditor(parentElement, {
|
|
settings,
|
|
initialText,
|
|
initialNoteId,
|
|
|
|
onPasteFile: async (data) => {
|
|
const base64 = await readFileToBase64(data);
|
|
await messenger.remoteApi.onPasteFile(data.type, base64);
|
|
},
|
|
onLogMessage: (message: string) => {
|
|
void messenger.remoteApi.logMessage(message);
|
|
},
|
|
onEvent: (event) => {
|
|
void messenger.remoteApi.onEditorEvent(event);
|
|
},
|
|
}, {
|
|
renderMarkupToHtml: async (markup) => {
|
|
return await messenger.remoteApi.onRender({
|
|
markup,
|
|
language: settings.language === EditorLanguageType.Html ? MarkupLanguage.Html : MarkupLanguage.Markdown,
|
|
}, {
|
|
pluginAssetContainerSelector: `#${assetContainer.id}`,
|
|
splitted: true,
|
|
mapsToLine: true,
|
|
});
|
|
},
|
|
renderHtmlToMarkup: (node) => {
|
|
// By default, if `src` is specified on an image, the browser will try to load the image, even if it isn't added
|
|
// to the DOM. (A similar problem is described here: https://stackoverflow.com/q/62019538).
|
|
// Since :/resourceId isn't a valid image URI, this results in a large number of warnings. As a workaround,
|
|
// move the element to a temporary document before processing:
|
|
const dom = document.implementation.createHTMLDocument();
|
|
node = dom.importNode(node, true);
|
|
|
|
let html: HTMLElement;
|
|
if ((node instanceof HTMLElement)) {
|
|
html = node;
|
|
} else {
|
|
const container = document.createElement('div');
|
|
container.appendChild(html);
|
|
html = container;
|
|
}
|
|
|
|
if (settings.language === EditorLanguageType.Markdown) {
|
|
return htmlToMarkdown(wrapHtmlForMarkdownConversion(html));
|
|
} else {
|
|
return postprocessHtml(html).outerHTML;
|
|
}
|
|
},
|
|
});
|
|
|
|
messenger.setLocalInterface({
|
|
editor,
|
|
});
|
|
|
|
return editor;
|
|
};
|
|
|
|
export { default as setUpLogger } from '../../utils/setUpLogger';
|
|
|