Skip to content

Commit

Permalink
fix: preformatted content being re-formatted (#376)
Browse files Browse the repository at this point in the history
The issue had to do with how Firefox handles pasting newlines inside a <pre
contenteditable> tag (TinyMCE's editor works via contenteditable) and
fast-xml-parser's parsing. In Firefox, newlines are converted to <br> when
pasted, while Chrome preserves them. The parser by default trims spaces in text
nodes. In Firefox, the parser creates individual text nodes between the <br>
elements, and those have leading spaces in the example. In Chrome, there are no
<br> elements and the entire content is a single text node as-is. Setting
trimValues to false disables the trimming and resolves this issue in Firefox.

While investigating this, I noticed the builder also mishandles <br /> tags
emitted by the editor, converting them to <br></br>. The unpairedTags option in
the builder ensures they are output correctly as a single tag, and setting
suppressUnpairedNode to false ensures that single tag is <br/> rather than <br>
to remain XML compatible.

While trying to resolve this, I was looking into the paste plugin in TinyMCE.
It changes the behavior of pasting, making it more consistent between Chrome
and Firefox (i.e. both emit <br>) and is incorporated into TinyMCE 6 core.
Unfortunately, it seems to mangle pasting inside a <pre> tag by inserting
redundant nbsp characters (tinymce/tinymce#9017). TinyMCE 6 also outputs <br>
rather than <br /> - adding unpairedTags to the parser options is meant to
handle this, but it does not seem to behave entirely correct
(NaturalIntelligence/fast-xml-parser#609). These should be kept in mind if/when
upgrading to TinyMCE 6 (the different behaviors can be seen easily at
https://fiddle.tiny.cloud).
  • Loading branch information
mohd-akram authored Sep 11, 2023
1 parent 9ebe187 commit 25e4e39
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 1 deletion.
11 changes: 10 additions & 1 deletion src/editors/containers/ProblemEditor/data/ReactStateOLXParser.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,26 @@ class ReactStateOLXParser {
hex: false,
},
preserveOrder: true,
// Ensure whitespace inside <pre> tags is preserved
trimValues: false,
// Parse <br> correctly
unpairedTags: ['br'],
};
const richTextBuilderOptions = {
ignoreAttributes: false,
attributeNamePrefix: '@_',
suppressBooleanAttributes: false,
format: true,
// Avoid formatting as it adds unwanted newlines and whitespace,
// breaking <pre> tags
format: false,
numberParseOptions: {
leadingZeros: false,
hex: false,
},
preserveOrder: true,
unpairedTags: ['br'],
// Output <br/> rather than <br>
suppressUnpairedNode: false,
};

this.richTextParser = new XMLParser(richTextParserOptions);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,5 +104,15 @@ describe('Check React State OLXParser problem', () => {
const buildOLX = stateParser.buildOLX();
expect(buildOLX.replace(/\s/g, '')).toEqual(numberParseTestOLX.buildOLX.replace(/\s/g, ''));
});
test('correctly preserves whitespace inside pre tags', () => {
const stateParser = new ReactStateOLXParser({
problem: { problemType: 'optionresponse', answers: [] },
editorObject: { question: '<pre> 1 a<br /> 2 b<br /></pre>', hints: [] },
});
const buildOLX = stateParser.buildOLX();
expect(buildOLX).toEqual(
'<problem><optionresponse>\n<pre> 1 a<br/> 2 b<br/></pre><optioninput></optioninput></optionresponse>\n</problem>',
);
});
});
});

0 comments on commit 25e4e39

Please sign in to comment.