Title: [294753] trunk
Revision
294753
Author
timothy_hor...@apple.com
Date
2022-05-24 10:28:58 -0700 (Tue, 24 May 2022)

Log Message

isContentEditable returns false for `display:none` contenteditable elements, but true for children
https://bugs.webkit.org/show_bug.cgi?id=240834

Reviewed by Ryosuke Niwa.

* Source/WebCore/dom/Node.cpp:
(WebCore::computeEditabilityFromComputedStyle):
Remove a `display: none` check. This check is wrong for two reasons:

1) It only consults the style of the immediate element, not whether or not
   that element is in a `display: none` subtree. This regressed in r160966.
   This causes a confusing situation where `display: none` affects the editability
   of only the element it is directly applied to.

2) isContentEditable is not specified to be affected by `display: none`.

* LayoutTests/editing/editability/isContentEditable-in-display-none-expected.txt: Added.
* LayoutTests/editing/editability/isContentEditable-in-display-none.html: Added.
Add a test that dumps the editability of a variety of different configurations of
contenteditable elements and their children.

Before this change, this test would have said that #nonVisible (the display: none
contenteditable element) was read-only, but its child <p> was editable. Now we
agree with Gecko and Blink who both say that both are editable.

* LayoutTests/fast/events/event-input-contentEditable-expected.txt:
* LayoutTests/fast/events/event-input-contentEditable.html:
Adjust this test to expect an input event to be dispatched for programmatic
editing in display: none elements. Also add a sub-test that checks the same,
but in a child element.

Before this change, we would not dispatch an input event to the display: none
contenteditable itself, but *would* dispatch an input event for input into a child element.
Now we agree with Gecko, who dispatch events in both cases.

Canonical link: https://commits.webkit.org/250921@main

Modified Paths

Added Paths

Diff

Added: trunk/LayoutTests/editing/editability/isContentEditable-in-display-none-expected.txt (0 => 294753)


--- trunk/LayoutTests/editing/editability/isContentEditable-in-display-none-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/editing/editability/isContentEditable-in-display-none-expected.txt	2022-05-24 17:28:58 UTC (rev 294753)
@@ -0,0 +1,19 @@
+BODY: Read-only
+	#nonEditable: Read-only
+		Directly inside a normal div.
+		P: Read-only
+			In a child of a normal div.
+	#visible: Editable
+		Directly inside a contenteditable.
+		P: Editable
+			In a child of a contenteditable.
+	#nonVisible: Editable
+		Directly inside a display:none contenteditable.
+		P: Editable
+			In a child of a display:none contenteditable.
+	DIV: Read-only
+		#nonVisibleParent: Editable
+			Directly inside a contenteditable with a display:none parent.
+			P: Editable
+				In a child of a contenteditable with a display:none parent.
+

Added: trunk/LayoutTests/editing/editability/isContentEditable-in-display-none.html (0 => 294753)


--- trunk/LayoutTests/editing/editability/isContentEditable-in-display-none.html	                        (rev 0)
+++ trunk/LayoutTests/editing/editability/isContentEditable-in-display-none.html	2022-05-24 17:28:58 UTC (rev 294753)
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html>
+<style>
+    body { white-space: pre-wrap; }
+</style>
+<script>
+if (window.testRunner)
+    testRunner.dumpAsText();
+
+function visit(node, f, depth) {
+    f(node, depth);
+    for (let child of node.childNodes)
+        visit(child, f, depth + 1);
+}
+
+window._onload_ = function () {
+    let description = "";
+    visit(document.body, function (node, depth) {
+        let indent = "\t".repeat(depth);
+
+        if (node.nodeType == Node.TEXT_NODE) {
+            let trimmedContent = node.textContent.trim();
+            if (trimmedContent)
+                description += `${indent}${trimmedContent}\n`;
+            return;
+        }
+
+        let identifier = node.id ? `#${node.id}` : node.nodeName;
+        let editability = node.isContentEditable ? "Editable" : "Read-only";
+        description += `${indent}${identifier}: ${editability}\n`;
+    }, 0);
+    document.body.innerText = description;
+}
+</script>
+<body>
+<div id="nonEditable">Directly inside a normal div.
+    <p>In a child of a normal div.</p>
+</div>
+<div id="visible" contenteditable>Directly inside a contenteditable.
+    <p>In a child of a contenteditable.</p>
+</div>
+<div id="nonVisible" style="display: none" contenteditable>Directly inside a display:none contenteditable.
+    <p>In a child of a display:none contenteditable.</p>
+</div>
+<div style="display: none">
+<div id="nonVisibleParent" contenteditable>Directly inside a contenteditable with a display:none parent.
+    <p>In a child of a contenteditable with a display:none parent.</p>
+</div>
+</div>
+</body>
+</html>
\ No newline at end of file

Modified: trunk/LayoutTests/fast/events/event-input-contentEditable-expected.txt (294752 => 294753)


--- trunk/LayoutTests/fast/events/event-input-contentEditable-expected.txt	2022-05-24 16:57:53 UTC (rev 294752)
+++ trunk/LayoutTests/fast/events/event-input-contentEditable-expected.txt	2022-05-24 17:28:58 UTC (rev 294753)
@@ -11,6 +11,10 @@
 PASS event.target.innerHTML is '<br>'
 PASS event.target.id is 'target4'
 PASS event.target.innerHTML is '<a href="" text should be a link.</a>'
+PASS event.target.id is 'target5A'
+PASS event.target.innerHTML is 'Text'
+PASS event.target.id is 'target5B'
+PASS event.target.innerHTML is 'This <span id="target5BDestination">text</span> will not be rendered.'
 PASS event.target.id is 'target6parent'
 PASS event.target.innerHTML is '<a href="" id="target6start">Start,</span><span id="target6middle">Middle,</span><span id="target6end">End.</span></a>'
 PASS event.target.id is 'target7'

Modified: trunk/LayoutTests/fast/events/event-input-contentEditable.html (294752 => 294753)


--- trunk/LayoutTests/fast/events/event-input-contentEditable.html	2022-05-24 16:57:53 UTC (rev 294752)
+++ trunk/LayoutTests/fast/events/event-input-contentEditable.html	2022-05-24 17:28:58 UTC (rev 294753)
@@ -67,13 +67,19 @@
 var target4 = setupForFiringTest('<p id="target4" contentEditable>This text should be a link.</p>', "<a href="" text should be a link.</a>");
 document.execCommand("createLink", false, "http://www.example.com/");
 
-// An event shouldn't be dispatched to a 'display:none' node.
-var target5 = makeTestTarget('<p id="target5" contentEditable>This will not be rendered.</p>');
-target5.addEventListener("input", function(evt) { testFailed("should not be reached"); });
-sel.selectAllChildren(target5);
-target5.style.display = "none";
+// An event should be dispatched to a 'display:none' node.
+var target5A = setupForFiringTest('<p id="target5A" contentEditable>This will not be rendered.</p>', 'Text');
+sel.selectAllChildren(target5A);
+target5A.style.display = "none";
 document.execCommand("insertText", false, "Text");
 
+// An event should be dispatched to a child of a 'display:none' node.
+var target5B = setupForFiringTest('<p id="target5B" contentEditable>This <span id="target5BDestination">replace</span> will not be rendered.</p>', 'This <span id="target5BDestination">text</span> will not be rendered.');
+var target5BDestination = document.getElementById("target5BDestination");
+sel.selectAllChildren(target5BDestination);
+target5B.style.display = "none";
+document.execCommand("insertText", false, "text");
+
 // The event should be dispatched from the editable root.
 makeTestTarget('<p id="target6parent" contentEditable><span id="target6start">Start,</span><span id="target6middle">Middle,</span><span id="target6end">End.</span></p>');
 var target6parent = document.getElementById("target6parent");

Modified: trunk/Source/WebCore/dom/Node.cpp (294752 => 294753)


--- trunk/Source/WebCore/dom/Node.cpp	2022-05-24 16:57:53 UTC (rev 294752)
+++ trunk/Source/WebCore/dom/Node.cpp	2022-05-24 17:28:58 UTC (rev 294753)
@@ -764,8 +764,7 @@
         auto* style = node->isDocumentNode() ? node->renderStyle() : const_cast<Node*>(node)->computedStyle();
         if (!style)
             continue;
-        if (style->display() == DisplayType::None)
-            continue;
+
         // Elements with user-select: all style are considered atomic
         // therefore non editable.
         if (treatment == Node::UserSelectAllIsAlwaysNonEditable && style->effectiveUserSelect() == UserSelect::All)
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to