mirror of
https://github.com/laurent22/joplin.git
synced 2026-06-18 20:16:34 +02:00
Desktop: Fixes #12059: Fix Rich Text Editor deletes paragraphs when pressing enter after a resized image (#12090)
This commit is contained in:
@@ -57,7 +57,7 @@ const logger = Logger.create('TinyMCE');
|
||||
//
|
||||
// The problem is that the list plugin was, unknown to me, relying on this <br/>
|
||||
// being present. Without it, trying to add a bullet point or checkbox on an
|
||||
// empty document, does nothing. The exact reason for this is unclear
|
||||
// empty document, adds an empty paragraph. The exact reason for this is unclear
|
||||
// so as a workaround we manually add this <br> for empty documents,
|
||||
// which fixes the issue.
|
||||
//
|
||||
@@ -70,8 +70,8 @@ const logger = Logger.create('TinyMCE');
|
||||
//
|
||||
// Perhaps upgrading the list plugin (which is a fork of TinyMCE own list plugin)
|
||||
// would help?
|
||||
function awfulInitHack(html: string): string {
|
||||
return html === '<div id="rendered-md"></div>' ? '<div id="rendered-md"><p></p></div>' : html;
|
||||
function preprocessHtml(html: string): string {
|
||||
return html === '' ? '<p></p>' : html;
|
||||
}
|
||||
|
||||
|
||||
@@ -1045,6 +1045,11 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
||||
// This prevents HTML-style resource URLs (e.g. <a href="file://path/to/resource/.../"></a>)
|
||||
// from being discarded.
|
||||
allowedFilePrefixes: [props.resourceDirectory],
|
||||
|
||||
// Remove the wrapping <div id="rendered-md">...</div>, which can cause
|
||||
// TinyMCE to crash in some cases.
|
||||
// See https://github.com/tinymce/tinymce/issues/10276
|
||||
bodyOnly: true,
|
||||
}),
|
||||
);
|
||||
if (cancelled) return;
|
||||
@@ -1056,7 +1061,11 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
||||
// when the note content is updated externally.
|
||||
const offsetBookmarkId = 2;
|
||||
const bookmark = editor.selection.getBookmark(offsetBookmarkId);
|
||||
editor.setContent(awfulInitHack(result.html));
|
||||
const htmlAndCss = [
|
||||
`<style>${result.cssStrings?.join('\n')}</style>`,
|
||||
preprocessHtml(result.html),
|
||||
].join('\n');
|
||||
editor.setContent(htmlAndCss);
|
||||
lastNoteIdRef.current = props.noteId;
|
||||
|
||||
if (lastOnChangeEventInfo.current.contentKey !== props.contentKey) {
|
||||
@@ -1089,6 +1098,7 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
||||
|
||||
const allAssetsOptions: NoteStyleOptions = {
|
||||
contentMaxWidthTarget: '.mce-content-body',
|
||||
contentWrapperSelector: '.mce-content-body',
|
||||
scrollbarSize: props.scrollbarSize,
|
||||
themeId: props.contentMarkupLanguage === MarkupLanguage.Html ? 1 : null,
|
||||
whiteBackgroundNoteRendering: props.whiteBackgroundNoteRendering,
|
||||
|
||||
@@ -85,6 +85,44 @@ test.describe('richTextEditor', () => {
|
||||
expect(await openPathResult).toContain(basename(pathToAttach));
|
||||
});
|
||||
|
||||
test('should not remove text when pressing [enter] at the end of a line with an image', async ({ mainWindow }) => {
|
||||
const mainScreen = await new MainScreen(mainWindow).setup();
|
||||
await mainScreen.createNewNote('Testing pressing enter!');
|
||||
const editor = mainScreen.noteEditor;
|
||||
|
||||
// Set the initial content
|
||||
await editor.codeMirrorEditor.click();
|
||||
await mainWindow.keyboard.type([
|
||||
'<img',
|
||||
' src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAADCAYAAABWKLW/AAAAEklEQVQIW2P8z8AARBDAiJMDAIzoBf635fcVAAAAAElFTkSuQmCC"',
|
||||
' width="200"',
|
||||
' height="200"',
|
||||
' alt="test image"',
|
||||
'/>',
|
||||
].join(' '));
|
||||
await mainWindow.keyboard.press('Enter');
|
||||
await mainWindow.keyboard.press('Enter');
|
||||
await mainWindow.keyboard.type('Test secondary paragraph.');
|
||||
|
||||
// Switch to the RTE
|
||||
await editor.toggleEditorsButton.click();
|
||||
await editor.richTextEditor.waitFor();
|
||||
|
||||
const richTextEditorFrame = editor.getRichTextFrameLocator();
|
||||
const testParagraph = richTextEditorFrame.getByText('Test secondary paragraph.');
|
||||
await expect(testParagraph).toBeAttached();
|
||||
|
||||
// Move the cursor just after the image, then press enter.
|
||||
const testImage = richTextEditorFrame.getByRole('img', { name: 'test image' });
|
||||
await testImage.click();
|
||||
await mainWindow.keyboard.press('ArrowRight');
|
||||
await mainWindow.keyboard.press('Enter');
|
||||
|
||||
// Should not have removed the image or the test paragraph.
|
||||
await expect(testImage).toBeAttached();
|
||||
await expect(testParagraph).toBeAttached();
|
||||
});
|
||||
|
||||
test('pressing Tab should indent', async ({ mainWindow }) => {
|
||||
const mainScreen = await new MainScreen(mainWindow).setup();
|
||||
await mainScreen.createNewNote('Testing tabs!');
|
||||
|
||||
@@ -11,6 +11,7 @@ function formatCssSize(v: any): string {
|
||||
export interface Options {
|
||||
contentMaxWidth?: number;
|
||||
contentMaxWidthTarget?: string;
|
||||
contentWrapperSelector?: string;
|
||||
scrollbarSize?: number;
|
||||
themeId?: number;
|
||||
whiteBackgroundNoteRendering?: boolean;
|
||||
@@ -84,7 +85,8 @@ export default function(theme: any, options: Options = null) {
|
||||
|
||||
const fontFamily = '\'Avenir Next\', \'Avenir\', \'Arial\', sans-serif';
|
||||
|
||||
const maxWidthTarget = options.contentMaxWidthTarget ? options.contentMaxWidthTarget : '#rendered-md';
|
||||
const contentWrapperTarget = options.contentWrapperSelector ?? '#rendered-md';
|
||||
const maxWidthTarget = options.contentMaxWidthTarget ? options.contentMaxWidthTarget : contentWrapperTarget;
|
||||
const maxWidthCss = options.contentMaxWidth ? `
|
||||
${maxWidthTarget} {
|
||||
max-width: ${options.contentMaxWidth}px;
|
||||
@@ -150,16 +152,16 @@ export default function(theme: any, options: Options = null) {
|
||||
|
||||
/* Remove top padding and margin from first child so that top of rendered text is aligned to top of text editor text */
|
||||
|
||||
#rendered-md > h1:first-child,
|
||||
#rendered-md > h2:first-child,
|
||||
#rendered-md > h3:first-child,
|
||||
#rendered-md > h4:first-child,
|
||||
#rendered-md > ul:first-child,
|
||||
#rendered-md > ol:first-child,
|
||||
#rendered-md > table:first-child,
|
||||
#rendered-md > blockquote:first-child,
|
||||
#rendered-md > img:first-child,
|
||||
#rendered-md > p:first-child {
|
||||
${contentWrapperTarget} > h1:first-child,
|
||||
${contentWrapperTarget} > h2:first-child,
|
||||
${contentWrapperTarget} > h3:first-child,
|
||||
${contentWrapperTarget} > h4:first-child,
|
||||
${contentWrapperTarget} > ul:first-child,
|
||||
${contentWrapperTarget} > ol:first-child,
|
||||
${contentWrapperTarget} > table:first-child,
|
||||
${contentWrapperTarget} > blockquote:first-child,
|
||||
${contentWrapperTarget} > img:first-child,
|
||||
${contentWrapperTarget} > p:first-child {
|
||||
margin-top: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user