diff --git a/Libraries/LibWeb/Editing/Commands.cpp b/Libraries/LibWeb/Editing/Commands.cpp index f148c137b6f..11ddb720a44 100644 --- a/Libraries/LibWeb/Editing/Commands.cpp +++ b/Libraries/LibWeb/Editing/Commands.cpp @@ -1135,6 +1135,75 @@ bool command_indent_action(DOM::Document& document, String const&) return true; } +// https://w3c.github.io/editing/docs/execCommand/#the-inserthorizontalrule-command +bool command_insert_horizontal_rule_action(DOM::Document& document, String const&) +{ + // 1. Let start node, start offset, end node, and end offset be the active range's start and end nodes and offsets. + auto range = active_range(document); + auto start = range->start(); + auto end = range->end(); + + // 2. While start offset is 0 and start node's parent is not null, set start offset to start node's index, then set + // start node to its parent. + while (start.offset == 0 && start.node->parent()) { + start.offset = start.node->index(); + start.node = *start.node->parent(); + } + + // 3. While end offset is end node's length, and end node's parent is not null, set end offset to one plus end + // node's index, then set end node to its parent. + while (end.offset == end.node->length() && end.node->parent()) { + end.offset = end.node->index() + 1; + end.node = *end.node->parent(); + } + + // 4. Call collapse(start node, start offset) on the context object's selection. + auto& selection = *document.get_selection(); + MUST(selection.collapse(start.node, start.offset)); + + // 5. Call extend(end node, end offset) on the context object's selection. + MUST(selection.extend(end.node, end.offset)); + + // 6. Delete the selection, with block merging false. + delete_the_selection(selection, false); + + // 7. If the active range's start node is neither editable nor an editing host, return true. + range = active_range(document); + start = range->start(); + if (!start.node->is_editable_or_editing_host()) + return true; + + // 8. If the active range's start node is a Text node and its start offset is zero, call collapse() on the context + // object's selection, with first argument the active range's start node's parent and second argument the active + // range's start node's index. + if (is(*start.node) && start.offset == 0) + MUST(selection.collapse(start.node->parent(), start.node->index())); + + // 9. If the active range's start node is a Text node and its start offset is the length of its start node, call + // collapse() on the context object's selection, with first argument the active range's start node's parent, and + // the second argument one plus the active range's start node's index. + range = active_range(document); + start = range->start(); + if (is(*start.node) && start.offset == start.node->length()) + MUST(selection.collapse(start.node->parent(), start.node->index() + 1)); + + // 10. Let hr be the result of calling createElement("hr") on the context object. + auto hr = MUST(DOM::create_element(document, HTML::TagNames::hr, Namespace::HTML)); + + // 11. Run insertNode(hr) on the active range. + MUST(active_range(document)->insert_node(hr)); + + // 12. Fix disallowed ancestors of hr. + fix_disallowed_ancestors_of_node(hr); + + // 13. Run collapse() on the context object's selection, with first argument hr's parent and the second argument + // equal to one plus hr's index. + MUST(selection.collapse(hr->parent(), hr->index() + 1)); + + // 14. Return true. + return true; +} + // https://w3c.github.io/editing/docs/execCommand/#the-insertlinebreak-command bool command_insert_linebreak_action(DOM::Document& document, String const&) { @@ -1879,6 +1948,12 @@ static Array const commands { .action = command_indent_action, .preserves_overrides = true, }, + // https://w3c.github.io/editing/docs/execCommand/#the-inserthorizontalrule-command + CommandDefinition { + .command = CommandNames::insertHorizontalRule, + .action = command_insert_horizontal_rule_action, + .preserves_overrides = true, + }, // https://w3c.github.io/editing/docs/execCommand/#the-insertlinebreak-command CommandDefinition { .command = CommandNames::insertLineBreak, diff --git a/Libraries/LibWeb/Editing/Commands.h b/Libraries/LibWeb/Editing/Commands.h index 7350c265385..fb7b0672dd7 100644 --- a/Libraries/LibWeb/Editing/Commands.h +++ b/Libraries/LibWeb/Editing/Commands.h @@ -44,6 +44,7 @@ bool command_format_block_indeterminate(DOM::Document const&); String command_format_block_value(DOM::Document const&); bool command_forward_delete_action(DOM::Document&, String const&); bool command_indent_action(DOM::Document&, String const&); +bool command_insert_horizontal_rule_action(DOM::Document&, String const&); bool command_insert_linebreak_action(DOM::Document&, String const&); bool command_insert_paragraph_action(DOM::Document&, String const&); bool command_italic_action(DOM::Document&, String const&); diff --git a/Tests/LibWeb/Text/expected/Editing/execCommand-insertHorizontalRule.txt b/Tests/LibWeb/Text/expected/Editing/execCommand-insertHorizontalRule.txt new file mode 100644 index 00000000000..d1e2e128db8 --- /dev/null +++ b/Tests/LibWeb/Text/expected/Editing/execCommand-insertHorizontalRule.txt @@ -0,0 +1 @@ +foo
bar diff --git a/Tests/LibWeb/Text/input/Editing/execCommand-insertHorizontalRule.html b/Tests/LibWeb/Text/input/Editing/execCommand-insertHorizontalRule.html new file mode 100644 index 00000000000..6f1be5ffa7f --- /dev/null +++ b/Tests/LibWeb/Text/input/Editing/execCommand-insertHorizontalRule.html @@ -0,0 +1,18 @@ + +
foobar
+