1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-08-10 22:11:50 +02:00

Mobile: Resolves #12843: Rich Text Editor: Improve support for HTML notes (#12912)

This commit is contained in:
Henry Heino
2025-08-10 01:32:42 -07:00
committed by GitHub
parent 9ea1808766
commit 6bd702ae24
4 changed files with 26 additions and 5 deletions

View File

@@ -173,6 +173,21 @@ describe('RichTextEditor', () => {
}); });
}); });
it('should save repeated spaces using nonbreaking spaces', async () => {
let body = 'Test';
render(<WrappedEditor
noteBody={body}
onBodyChange={newBody => { body = newBody; }}
/>);
const window = await getEditorWindow();
mockTyping(window, ' test');
await waitFor(async () => {
expect(body.trim()).toBe('Test \u00A0test');
});
});
it('should render clickable checkboxes', async () => { it('should render clickable checkboxes', async () => {
let body = '- [ ] Test\n- [x] Another test'; let body = '- [ ] Test\n- [x] Another test';
render(<WrappedEditor render(<WrappedEditor

View File

@@ -923,7 +923,7 @@ class NoteScreenComponent extends BaseScreenComponent<ComponentProps, State> imp
resource = await Resource.save(resource, { isNew: true }); resource = await Resource.save(resource, { isNew: true });
const resourceTag = Resource.markupTag(resource); const resourceTag = Resource.markupTag(resource, this.state.note.markup_language);
const newNote = await this.insertText(resourceTag, { newLine: true }); const newNote = await this.insertText(resourceTag, { newLine: true });
void this.refreshResource(resource, newNote.body); void this.refreshResource(resource, newNote.body);

View File

@@ -4,6 +4,8 @@ import { Decoration, DecorationSet } from 'prosemirror-view';
import schema from '../schema'; import schema from '../schema';
import changedDescendants from '../vendor/changedDescendants'; import changedDescendants from '../vendor/changedDescendants';
const nonbreakingSpace = '\u00A0';
// Creates a custom serializer that can preserve empty paragraphs. // Creates a custom serializer that can preserve empty paragraphs.
// See https://discuss.prosemirror.net/t/how-to-preserve-br-tags-in-empty-paragraphs/2051/8. // See https://discuss.prosemirror.net/t/how-to-preserve-br-tags-in-empty-paragraphs/2051/8.
const createSerializer = () => { const createSerializer = () => {
@@ -21,10 +23,10 @@ const createSerializer = () => {
return result; return result;
}, },
// Prevent empty paragraphs from being removed by padding them with &nbsp;s: // Prevent empty paragraphs from being removed by padding them with nonbreaking spaces:
paragraph: (node) => { paragraph: (node) => {
if (node.content.size === 0) { if (node.content.size === 0) {
return ['p', '&nbsp;']; return ['p', nonbreakingSpace];
} else { } else {
return ['p', 0]; return ['p', 0];
} }
@@ -39,7 +41,8 @@ const createSerializer = () => {
} }
// Replace repeated spaces with a space followed by a nonbreaking space: // Replace repeated spaces with a space followed by a nonbreaking space:
return node.text.replace(/ {2}/g, ' &nbsp;'); // Use \u00A0 as the nonbreaking space character, since &nbsp; will be escaped.
return node.text.replace(/ {2}/g, ` ${nonbreakingSpace}`);
}, },
// However, &nbsp;s don't render as nonbreaking spaces in code blocks. // However, &nbsp;s don't render as nonbreaking spaces in code blocks.
@@ -76,7 +79,8 @@ const originalMarkupPlugin = (htmlToMarkup: (html: Node)=> string) => {
}); });
if (matchingDecorations.length === 0) { if (matchingDecorations.length === 0) {
const markup = htmlToMarkup(proseMirrorSerializer.serializeNode(node)); const serialized = proseMirrorSerializer.serializeNode(node);
const markup = htmlToMarkup(serialized);
decorations = decorations.add(doc, [makeDecoration(position, node, markup)]); decorations = decorations.add(doc, [makeDecoration(position, node, markup)]);
} }

View File

@@ -3,4 +3,6 @@
outline: none; outline: none;
padding-left: 15px; padding-left: 15px;
padding-right: 15px; padding-right: 15px;
color: var(--joplin-color);
} }