Skip to content

Commit

Permalink
LibWeb: Implement the "unlink" editing command
Browse files Browse the repository at this point in the history
  • Loading branch information
gmta committed Jan 8, 2025
1 parent 6bcf649 commit f1d9077
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 0 deletions.
43 changes: 43 additions & 0 deletions Libraries/LibWeb/Editing/Commands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1451,6 +1451,44 @@ bool command_underline_action(DOM::Document& document, String const&)
return true;
}

// https://w3c.github.io/editing/docs/execCommand/#the-unlink-command
bool command_unlink_action(DOM::Document& document, String const&)
{
// 1. Let hyperlinks be a list of every a element that has an href attribute and is contained in the active range or
// is an ancestor of one of its boundary points.
Vector<GC::Ref<DOM::Element>> hyperlinks;
if (auto range = active_range(document)) {
auto node_matches = [](GC::Ref<DOM::Node> node) {
return is<HTML::HTMLAnchorElement>(*node)
&& static_cast<HTML::HTMLAnchorElement&>(*node).has_attribute(HTML::AttributeNames::href);
};
range->common_ancestor_container()->for_each_in_subtree([&](GC::Ref<DOM::Node> descendant) {
if (!range->contains_node(descendant))
return TraversalDecision::SkipChildrenAndContinue;
if (node_matches(descendant))
hyperlinks.append(static_cast<DOM::Element&>(*descendant));
return TraversalDecision::Continue;
});
auto add_matching_ancestors = [&](GC::Ref<DOM::Node> node) {
GC::Ptr<DOM::Node> ancestor = node->parent();
while (ancestor) {
if (node_matches(*ancestor))
hyperlinks.append(static_cast<DOM::Element&>(*ancestor));
ancestor = ancestor->parent();
}
};
add_matching_ancestors(range->start_container());
add_matching_ancestors(range->end_container());
}

// 2. Clear the value of each member of hyperlinks.
for (auto member : hyperlinks)
clear_the_value(CommandNames::unlink, member);

// 3. Return true.
return true;
}

static Array const commands {
// https://w3c.github.io/editing/docs/execCommand/#the-backcolor-command
CommandDefinition {
Expand Down Expand Up @@ -1569,6 +1607,11 @@ static Array const commands {
.action = command_underline_action,
.inline_activated_values = { "underline"sv },
},
// https://w3c.github.io/editing/docs/execCommand/#the-unlink-command
CommandDefinition {
.command = CommandNames::unlink,
.action = command_unlink_action,
},
};

Optional<CommandDefinition const&> find_command_definition(FlyString const& command)
Expand Down
1 change: 1 addition & 0 deletions Libraries/LibWeb/Editing/Commands.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,6 @@ bool command_subscript_indeterminate(DOM::Document const&);
bool command_superscript_action(DOM::Document&, String const&);
bool command_superscript_indeterminate(DOM::Document const&);
bool command_underline_action(DOM::Document&, String const&);
bool command_unlink_action(DOM::Document&, String const&);

}
2 changes: 2 additions & 0 deletions Tests/LibWeb/Text/expected/Editing/execCommand-unlink.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
d1 contents: "ladybird"
d2 contents: "ladybird"
23 changes: 23 additions & 0 deletions Tests/LibWeb/Text/input/Editing/execCommand-unlink.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<script src="../include.js"></script>
<div contenteditable="true" id="d1"><a href="https://ladybird.dev">ladybird</a></div>
<div contenteditable="true" id="d2">lady<a href="https://ladybird.dev">bird</a></div>
<script>
test(() => {
const range = document.createRange();
getSelection().addRange(range);

// Unlink d1's ladybird
const div1 = document.querySelector('#d1');
range.setStart(div1.childNodes[0].childNodes[0], 0);
range.setEnd(div1.childNodes[0].childNodes[0], 8);
document.execCommand('unlink');
println(`d1 contents: "${div1.innerHTML}"`);

// Unlink d2's 'bird'
const div2 = document.querySelector('#d2');
range.setStart(div2.childNodes[1].childNodes[0], 2);
range.setEnd(div2.childNodes[1].childNodes[0], 3);
document.execCommand('unlink');
println(`d2 contents: "${div2.innerHTML}"`);
});
</script>

0 comments on commit f1d9077

Please sign in to comment.