mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-09 09:39:39 +00:00
LibWeb: Use default paragraph separator in delete command
This commit is contained in:
parent
4a64557876
commit
bb618736e9
Notes:
github-actions[bot]
2024-11-30 16:37:08 +00:00
Author: https://github.com/gmta
Commit: bb618736e9
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/2655
Reviewed-by: https://github.com/shannonbooth
Reviewed-by: https://github.com/yyny
3 changed files with 100 additions and 8 deletions
|
@ -62,7 +62,7 @@ bool command_delete_action(DOM::Document& document, String const&)
|
|||
canonicalize_whitespace(active_range.start_container(), active_range.start_offset());
|
||||
|
||||
// 3. Let node and offset be the active range's start node and offset.
|
||||
auto node = active_range.start_container();
|
||||
GC::Ptr<DOM::Node> node = active_range.start_container();
|
||||
int offset = active_range.start_offset();
|
||||
|
||||
// 4. Repeat the following steps:
|
||||
|
@ -89,7 +89,7 @@ bool command_delete_action(DOM::Document& document, String const&)
|
|||
|
||||
// 3. Otherwise, if offset is zero and node is an inline node, or if node is an invisible
|
||||
// node, set offset to the index of node, then set node to its parent.
|
||||
if ((offset == 0 && is_inline_node(node)) || is_invisible_node(node)) {
|
||||
if ((offset == 0 && is_inline_node(*node)) || is_invisible_node(*node)) {
|
||||
offset = node->index();
|
||||
node = *node->parent();
|
||||
continue;
|
||||
|
@ -118,7 +118,7 @@ bool command_delete_action(DOM::Document& document, String const&)
|
|||
// 5. If node is a Text node and offset is not zero, or if node is a block node that has a child
|
||||
// with index offset − 1 and that child is a br or hr or img:
|
||||
bool block_node_child_is_relevant_type = false;
|
||||
if (is_block_node(node)) {
|
||||
if (is_block_node(*node)) {
|
||||
if (auto* child_node = node->child_at_index(offset - 1)) {
|
||||
auto& child_element = static_cast<DOM::Element&>(*child_node);
|
||||
block_node_child_is_relevant_type = child_element.local_name().is_one_of(HTML::TagNames::br, HTML::TagNames::hr, HTML::TagNames::img);
|
||||
|
@ -139,7 +139,7 @@ bool command_delete_action(DOM::Document& document, String const&)
|
|||
}
|
||||
|
||||
// 6. If node is an inline node, return true.
|
||||
if (is_inline_node(node))
|
||||
if (is_inline_node(*node))
|
||||
return true;
|
||||
|
||||
// 7. If node is an li or dt or dd and is the first child of its parent, and offset is zero:
|
||||
|
@ -162,19 +162,33 @@ bool command_delete_action(DOM::Document& document, String const&)
|
|||
|
||||
// 3. Record the values of the one-node list consisting of node, and let values be the
|
||||
// result.
|
||||
auto values = record_the_values_of_nodes({ node });
|
||||
auto values = record_the_values_of_nodes({ *node });
|
||||
|
||||
// 4. Split the parent of the one-node list consisting of node.
|
||||
split_the_parent_of_nodes({ node });
|
||||
split_the_parent_of_nodes({ *node });
|
||||
|
||||
// 5. Restore the values from values.
|
||||
restore_the_values_of_nodes(values);
|
||||
|
||||
// FIXME: 6. If node is a dd or dt, and it is not an allowed child of any of its ancestors in the
|
||||
// 6. If node is a dd or dt, and it is not an allowed child of any of its ancestors in the
|
||||
// same editing host, set the tag name of node to the default single-line container name
|
||||
// and let node be the result.
|
||||
if (node_element.local_name().is_one_of(HTML::TagNames::dd, HTML::TagNames::dt)) {
|
||||
ancestor = node->parent();
|
||||
bool allowed_child_of_any_ancestor = false;
|
||||
do {
|
||||
if (is_in_same_editing_host(*node, *ancestor) && is_allowed_child_of_node(GC::Ref { *node }, GC::Ref { *ancestor })) {
|
||||
allowed_child_of_any_ancestor = true;
|
||||
break;
|
||||
}
|
||||
ancestor = ancestor->parent();
|
||||
} while (ancestor);
|
||||
if (!allowed_child_of_any_ancestor)
|
||||
node = set_the_tag_name(node_element, document.default_single_line_container_name());
|
||||
}
|
||||
|
||||
// FIXME: 7. Fix disallowed ancestors of node.
|
||||
// 7. Fix disallowed ancestors of node.
|
||||
fix_disallowed_ancestors_of_node(node);
|
||||
|
||||
// 8. Return true.
|
||||
return true;
|
||||
|
|
|
@ -379,6 +379,75 @@ GC::Ptr<DOM::Node> editing_host_of_node(GC::Ref<DOM::Node> node)
|
|||
return {};
|
||||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#fix-disallowed-ancestors
|
||||
void fix_disallowed_ancestors_of_node(GC::Ptr<DOM::Node> node)
|
||||
{
|
||||
// 1. If node is not editable, abort these steps.
|
||||
if (!node->is_editable())
|
||||
return;
|
||||
|
||||
// 2. If node is not an allowed child of any of its ancestors in the same editing host:
|
||||
bool allowed_child_of_any_ancestor = false;
|
||||
GC::Ptr<DOM::Node> ancestor = node->parent();
|
||||
do {
|
||||
if (is_in_same_editing_host(*ancestor, *node) && is_allowed_child_of_node(GC::Ref { *node }, GC::Ref { *ancestor })) {
|
||||
allowed_child_of_any_ancestor = true;
|
||||
break;
|
||||
}
|
||||
ancestor = ancestor->parent();
|
||||
} while (ancestor);
|
||||
if (!allowed_child_of_any_ancestor) {
|
||||
// FIXME: 1. If node is a dd or dt, wrap the one-node list consisting of node, with sibling criteria returning true for
|
||||
// any dl with no attributes and false otherwise, and new parent instructions returning the result of calling
|
||||
// createElement("dl") on the context object. Then abort these steps.
|
||||
|
||||
// 2. If "p" is not an allowed child of the editing host of node, abort these steps.
|
||||
if (!is_allowed_child_of_node(HTML::TagNames::p, GC::Ref { *editing_host_of_node(*node) }))
|
||||
return;
|
||||
|
||||
// 3. If node is not a prohibited paragraph child, abort these steps.
|
||||
if (!is_prohibited_paragraph_child(*node))
|
||||
return;
|
||||
|
||||
// 4. Set the tag name of node to the default single-line container name, and let node be the result.
|
||||
node = set_the_tag_name(static_cast<DOM::Element&>(*node), node->document().default_single_line_container_name());
|
||||
|
||||
// 5. Fix disallowed ancestors of node.
|
||||
fix_disallowed_ancestors_of_node(node);
|
||||
|
||||
// 6. Let children be node's children.
|
||||
// 7. For each child in children, if child is a prohibited paragraph child:
|
||||
node->for_each_child([](DOM::Node& child) {
|
||||
if (!is_prohibited_paragraph_child(child))
|
||||
return IterationDecision::Continue;
|
||||
|
||||
// 1. Record the values of the one-node list consisting of child, and let values be the result.
|
||||
auto values = record_the_values_of_nodes({ child });
|
||||
|
||||
// 2. Split the parent of the one-node list consisting of child.
|
||||
split_the_parent_of_nodes({ child });
|
||||
|
||||
// 3. Restore the values from values.
|
||||
restore_the_values_of_nodes(values);
|
||||
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
|
||||
// 8. Abort these steps.
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. Record the values of the one-node list consisting of node, and let values be the result.
|
||||
auto values = record_the_values_of_nodes({ *node });
|
||||
|
||||
// 4. While node is not an allowed child of its parent, split the parent of the one-node list consisting of node.
|
||||
while (!is_allowed_child_of_node(GC::Ref { *node }, GC::Ref { *node->parent() }))
|
||||
split_the_parent_of_nodes({ *node });
|
||||
|
||||
// 5. Restore the values from values.
|
||||
restore_the_values_of_nodes(values);
|
||||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#follows-a-line-break
|
||||
bool follows_a_line_break(GC::Ref<DOM::Node> node)
|
||||
{
|
||||
|
@ -863,6 +932,13 @@ bool is_name_of_an_element_with_inline_contents(FlyString const& local_name)
|
|||
HTML::TagNames::tt);
|
||||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#prohibited-paragraph-child
|
||||
bool is_prohibited_paragraph_child(GC::Ref<DOM::Node> node)
|
||||
{
|
||||
// A prohibited paragraph child is an HTML element whose local name is a prohibited paragraph child name.
|
||||
return is<HTML::HTMLElement>(*node) && is_prohibited_paragraph_child_name(static_cast<DOM::Element&>(*node).local_name());
|
||||
}
|
||||
|
||||
// https://w3c.github.io/editing/docs/execCommand/#prohibited-paragraph-child-name
|
||||
bool is_prohibited_paragraph_child_name(FlyString const& local_name)
|
||||
{
|
||||
|
|
|
@ -25,6 +25,7 @@ String canonical_space_sequence(u32 length, bool non_breaking_start, bool non_br
|
|||
void canonicalize_whitespace(GC::Ref<DOM::Node>, u32 offset, bool fix_collapsed_space = true);
|
||||
void delete_the_selection(Selection::Selection const&);
|
||||
GC::Ptr<DOM::Node> editing_host_of_node(GC::Ref<DOM::Node>);
|
||||
void fix_disallowed_ancestors_of_node(GC::Ptr<DOM::Node>);
|
||||
bool follows_a_line_break(GC::Ref<DOM::Node>);
|
||||
bool is_allowed_child_of_node(Variant<GC::Ref<DOM::Node>, FlyString> child, Variant<GC::Ref<DOM::Node>, FlyString> parent);
|
||||
bool is_block_boundary_point(GC::Ref<DOM::Node>, u32 offset);
|
||||
|
@ -39,6 +40,7 @@ bool is_in_same_editing_host(GC::Ref<DOM::Node>, GC::Ref<DOM::Node>);
|
|||
bool is_inline_node(GC::Ref<DOM::Node>);
|
||||
bool is_invisible_node(GC::Ref<DOM::Node>);
|
||||
bool is_name_of_an_element_with_inline_contents(FlyString const&);
|
||||
bool is_prohibited_paragraph_child(GC::Ref<DOM::Node>);
|
||||
bool is_prohibited_paragraph_child_name(FlyString const&);
|
||||
bool is_visible_node(GC::Ref<DOM::Node>);
|
||||
bool is_whitespace_node(GC::Ref<DOM::Node>);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue