diff --git a/Libraries/LibWeb/Editing/Commands.cpp b/Libraries/LibWeb/Editing/Commands.cpp index cb33aba5dcb..e925ab06575 100644 --- a/Libraries/LibWeb/Editing/Commands.cpp +++ b/Libraries/LibWeb/Editing/Commands.cpp @@ -64,6 +64,39 @@ bool command_bold_action(DOM::Document& document, String const&) return true; } +// https://w3c.github.io/editing/docs/execCommand/#the-createlink-command +bool command_create_link_action(DOM::Document& document, String const& value) +{ + // 1. If value is the empty string, return false. + if (value.is_empty()) + return false; + + // 2. For each editable a element that has an href attribute and is an ancestor of some node effectively contained + // in the active range, set that a element's href attribute to value. + HashTable visited_ancestors; + auto set_value_for_ancestor_anchors = [&](GC::Ref node) { + node->for_each_ancestor([&](GC::Ref ancestor) { + if (visited_ancestors.contains(ancestor.ptr())) + return IterationDecision::Break; + if (is(*ancestor) && ancestor->is_editable() + && static_cast(*ancestor).has_attribute(HTML::AttributeNames::href)) + MUST(static_cast(*ancestor).set_href(value)); + visited_ancestors.set(ancestor.ptr()); + return IterationDecision::Continue; + }); + }; + for_each_node_effectively_contained_in_range(active_range(document), [&](GC::Ref descendant) { + set_value_for_ancestor_anchors(descendant); + return TraversalDecision::Continue; + }); + + // 3. Set the selection's value to value. + set_the_selections_value(document, CommandNames::createLink, value); + + // 4. Return true. + return true; +} + // https://w3c.github.io/editing/docs/execCommand/#the-defaultparagraphseparator-command bool command_default_paragraph_separator_action(DOM::Document& document, String const& input_value) { @@ -1065,6 +1098,11 @@ static Array const commands { .relevant_css_property = CSS::PropertyID::FontWeight, .inline_activated_values = { "bold"sv, "600"sv, "700"sv, "800"sv, "900"sv }, }, + // https://w3c.github.io/editing/docs/execCommand/#the-createlink-command + CommandDefinition { + .command = CommandNames::createLink, + .action = command_create_link_action, + }, // https://w3c.github.io/editing/docs/execCommand/#the-delete-command CommandDefinition { .command = CommandNames::delete_, diff --git a/Libraries/LibWeb/Editing/Commands.h b/Libraries/LibWeb/Editing/Commands.h index 43000f60789..f333b0cef39 100644 --- a/Libraries/LibWeb/Editing/Commands.h +++ b/Libraries/LibWeb/Editing/Commands.h @@ -31,6 +31,7 @@ Optional find_command_definition(FlyString const&); // Command implementations bool command_back_color_action(DOM::Document&, String const&); bool command_bold_action(DOM::Document&, String const&); +bool command_create_link_action(DOM::Document&, String const&); bool command_default_paragraph_separator_action(DOM::Document&, String const&); String command_default_paragraph_separator_value(DOM::Document const&); bool command_delete_action(DOM::Document&, String const&); diff --git a/Tests/LibWeb/Text/expected/Editing/execCommand-createLink.txt b/Tests/LibWeb/Text/expected/Editing/execCommand-createLink.txt new file mode 100644 index 00000000000..9162ed1a3da --- /dev/null +++ b/Tests/LibWeb/Text/expected/Editing/execCommand-createLink.txt @@ -0,0 +1,2 @@ +d1 contents: "foobar" +d2 contents: "ladybird" diff --git a/Tests/LibWeb/Text/input/Editing/execCommand-createLink.html b/Tests/LibWeb/Text/input/Editing/execCommand-createLink.html new file mode 100644 index 00000000000..3c24db1f5a5 --- /dev/null +++ b/Tests/LibWeb/Text/input/Editing/execCommand-createLink.html @@ -0,0 +1,23 @@ + +
foobar
+ +