Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fit.Dom.Text - preserve linebreaks on modern browsers #159

Open
Jemt opened this issue Apr 3, 2022 · 0 comments
Open

Fit.Dom.Text - preserve linebreaks on modern browsers #159

Jemt opened this issue Apr 3, 2022 · 0 comments

Comments

@Jemt
Copy link
Owner

Jemt commented Apr 3, 2022

Fit.Dom.Text(elm):string does not preserve linebreaks on modern browsers due to the use of textContent.
Consider using innerHTML, replace <br> with \n, strip HTML, and replace HEX and HTML entities with real characters. This will produce a value identical to the one .textContent produces, but with linebreaks preserved. This would also allow us to completely get rid of the use of innerText which first of all is not cross browser compatible, and second is aware of rendered content (e.g. excludes content with display:hidden). This in turn results in different results across different browsers.

The example below demonstrates the desired logic and proves the results is identical to the result of .textContent - except for the preserved linebreaks, of course.

function replaceHexEntities(str)
{
	return str.replace(/&#(\d+);/g, function(fullMatch, captureGroup) { return String.fromCharCode(captureGroup); });
}

function replaceHtmlEntities(str)
{
	var result = str;
	result = result.replace(/&amp;/g, "&");
	result = result.replace(/&lt;/g, "<");
	result = result.replace(/&gt;/g, ">");
	result = result.replace(/&nbsp;/g, " "); // NOTICE: Not a space but a non-breaking space (ALT+Space on Mac)
	result = result.replace(/&quot;/g, "\"");
	return result;
}

function getText(elm)
{
	var val = elm.innerHTML;
	val = val.replace(/<br ?\/?>/g, "\n");
	val = Fit.String.StripHtml(val);
	val = replaceHexEntities(val);
	val = replaceHtmlEntities(val);
	return val;
}

var elm = Fit.Dom.CreateElement("<h1>Hello there</h1>  <br><br>  Super <b>cool</b> &gt;text&lt; &nbsp;&nbsp;&nbsp; goes here &#128514;  <script>alert(123)</script>  <div style='display: none'>This text is hidden</div>");
var val = getText(elm);

console.log("Result with new getText(..) - like .textContent, but with linebreaks preserved:", "'" + val + "'");
console.log("Result with .textContent - same as above, except linebreaks are not preserved:", "'" + elm.textContent + "'");
console.log("Are values identical if linebreaks are eliminated (expected: true)?:", (val.replace(/\n/g, "") === elm.textContent));

New implementation should naturally also work as a setter function, allowing for new text values to be applied - also with line breaks preserved (\n being replaced by <br> and special HTML characters being replaced by HTML entities). Value should be assigned to element using cross browser compatible innerHTML.

function setText(elm, str)
{
	var html = str;
	html = html.replace(/&/g, "&amp;");
	html = html.replace(/</g, "&lt;");
	html = html.replace(/>/g, "&gt;");
	html = html.replace(/ /g, "&nbsp;"); // NOTICE: Not a space but a non-breaking space (ALT+Space on Mac)
	html = html.replace(/"/g, "&quot;");
	html = html.replace(/\n/g, "\n<br>");
	console.log("Value being set with setText(..):", html);
	elm.innerHTML = html;
}

var div1 = document.createElement("div");
var div2 = document.createElement("div");
var test = "Hi there - want som \"pizza\"? 🍕 \n\n Non-breaking spaces (ALT+Space on Mac):      . 1 < 2 is true & 2 > 1 is also true. <b>HTML</b> &amp; entities such as &lt; and &#128514; is not a problem.";

setText(div1, test);
div2.textContent = test;

console.log("div1.textContent:", div1.textContent);
console.log("div2.textContent:", div2.textContent);
console.log("Are .textContent values identical using different setter approaches (expected: true):", div1.textContent === div2.textContent);

console.log("How does different setter approaches affect HTML result if linebreak differences (which were preserved with setText(..)) are eliminated?:");
console.log("div1.innerHTML:", div1.innerHTML.replace(/<br>/g, ""));
console.log("div2.innerHTML:", div2.innerHTML);
console.log("Are .innerHTML values identical using different setter approaches (expected: true):", div1.innerHTML.replace(/<br>/g, "") === div2.innerHTML);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants