Skip to content

Commit

Permalink
Make HTMLEditor replace collapsible ASCII white-space with an NBSP …
Browse files Browse the repository at this point in the history
…if it's visible by a following <br> but it's removed

This is a hack until bug 503838 is fixed.

The other browsers puts an NBSP for the last ASCII white-space immediately
before a block boundary to make it visible.  However, we currently need to
keep using an ASCII white-space as-is with putting a padding `<br>` element.

However, web apps may delete the `<br>` for some reasons without maintaining
the preceding collapsible white-space visibility since it's not required in
the other browsers.

Therefore, this patch replaces the white-spaces only when we meet such
situation.  Of course, this breaks the undo stack, but touching the DOM anyway
causes breaking the undo stack.  Thus, we can trust the web app as that it
manages their on undo stack.

Differential Revision: https://phabricator.services.mozilla.com/D233472

bugzilla-url: https://bugzilla.mozilla.org/show_bug.cgi?id=1940278
gecko-commit: 020e3aecfaaa47b5ed8497bcc9572d70a9b5e549
gecko-reviewers: m_kato
  • Loading branch information
masayuki-nakano authored and moz-wptsync-bot committed Jan 9, 2025
1 parent d431fd4 commit f09f9ad
Showing 1 changed file with 94 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>If browsers inserts a br element to make preceding collapsible white-space visible,
it should be maintained even if the web app deletes the br element</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="../include/editor-test-utils.js"></script>
<script>
"use strict";

document.addEventListener("DOMContentLoaded", () => {
const editingHost = document.querySelector("div[contenteditable]");
editingHost.focus();
const utils = new EditorTestUtils(editingHost);

promise_test(async t => {
utils.setupEditingHost("abc d[]");
await utils.sendBackspaceKey();
assert_in_array(
editingHost.innerHTML,
["abc <br>", "abc&nbsp;"],
`${t.name}: Deleting the first char of the second word should not make the preceding white-space invisible`
);
const br = editingHost.querySelector("br");
if (br) {
br.remove();
assert_in_array(
editingHost.innerHTML,
["abc <br>", "abc&nbsp;"],
`${t.name}: Browser should keep the collapsible white-space as visible even if the padding <br> is removed`
);
}
await utils.sendKey("d");
assert_equals(
editingHost.innerHTML,
"abc d",
`${t.name}: Typing a character should make the last white-space as an ASCII space and delete the unnecessary <br>`
);
}, "The last ASCII white-space should be replaced with an NBSP even if <br> is removed by web app");

promise_test(async t => {
utils.setupEditingHost("abc d[]<div>ef</div>");
await utils.sendBackspaceKey();
assert_in_array(
editingHost.innerHTML,
["abc <br><div>ef</div>", "abc&nbsp;<div>ef</div>"],
`${t.name}: Deleting the first char of the second word should not make the preceding white-space invisible`
);
const br = editingHost.querySelector("br");
if (br) {
br.remove();
assert_in_array(
editingHost.innerHTML,
["abc <br><div>ef</div>", "abc&nbsp;<div>ef</div>"],
`${t.name}: Browser should keep the collapsible white-space as visible even if the padding <br> is removed`
);
}
await utils.sendKey("d");
assert_equals(
editingHost.innerHTML,
"abc d<div>ef</div>",
`${t.name}: Typing a character should make the last white-space as an ASCII space and delete the unnecessary <br>`
);
}, "The last ASCII white-space should be replaced with an NBSP even if <br> followed by a child block boundary is removed by web app");

promise_test(async t => {
utils.setupEditingHost("abc <br>def");
editingHost.querySelector("br").remove();
assert_equals(
editingHost.innerHTML,
"abc def"
);
}, "The last ASCII white-space should not be replaced with an NBSP if following <br> is not a padding <br>");

promise_test(async t => {
utils.setupEditingHost(`<div contenteditable="false">abc <br></div>`);
editingHost.querySelector("br").remove();
assert_equals(
editingHost.innerHTML,
`<div contenteditable="false">abc </div>`
);
}, "The last ASCII white-space in non-editable Text node should not be replaced with an NBSP if following <br> is not a padding <br>");
}, {once: true});
</script>
</head>
<body>
<div contenteditable></div>
</body>
</html>

0 comments on commit f09f9ad

Please sign in to comment.