mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-06-09 17:44:56 +09:00
LibWeb: Implement the "createLink" editing command
This commit is contained in:
parent
05386fe99c
commit
1b02e0dea3
Notes:
github-actions[bot]
2025-01-10 22:37:08 +00:00
Author: https://github.com/gmta
Commit: 1b02e0dea3
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3216
4 changed files with 64 additions and 0 deletions
|
@ -64,6 +64,39 @@ bool command_bold_action(DOM::Document& document, String const&)
|
||||||
return true;
|
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<DOM::Node*> visited_ancestors;
|
||||||
|
auto set_value_for_ancestor_anchors = [&](GC::Ref<DOM::Node> node) {
|
||||||
|
node->for_each_ancestor([&](GC::Ref<DOM::Node> ancestor) {
|
||||||
|
if (visited_ancestors.contains(ancestor.ptr()))
|
||||||
|
return IterationDecision::Break;
|
||||||
|
if (is<HTML::HTMLAnchorElement>(*ancestor) && ancestor->is_editable()
|
||||||
|
&& static_cast<DOM::Element&>(*ancestor).has_attribute(HTML::AttributeNames::href))
|
||||||
|
MUST(static_cast<HTML::HTMLAnchorElement&>(*ancestor).set_href(value));
|
||||||
|
visited_ancestors.set(ancestor.ptr());
|
||||||
|
return IterationDecision::Continue;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
for_each_node_effectively_contained_in_range(active_range(document), [&](GC::Ref<DOM::Node> 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
|
// https://w3c.github.io/editing/docs/execCommand/#the-defaultparagraphseparator-command
|
||||||
bool command_default_paragraph_separator_action(DOM::Document& document, String const& input_value)
|
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,
|
.relevant_css_property = CSS::PropertyID::FontWeight,
|
||||||
.inline_activated_values = { "bold"sv, "600"sv, "700"sv, "800"sv, "900"sv },
|
.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
|
// https://w3c.github.io/editing/docs/execCommand/#the-delete-command
|
||||||
CommandDefinition {
|
CommandDefinition {
|
||||||
.command = CommandNames::delete_,
|
.command = CommandNames::delete_,
|
||||||
|
|
|
@ -31,6 +31,7 @@ Optional<CommandDefinition const&> find_command_definition(FlyString const&);
|
||||||
// Command implementations
|
// Command implementations
|
||||||
bool command_back_color_action(DOM::Document&, String const&);
|
bool command_back_color_action(DOM::Document&, String const&);
|
||||||
bool command_bold_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&);
|
bool command_default_paragraph_separator_action(DOM::Document&, String const&);
|
||||||
String command_default_paragraph_separator_value(DOM::Document const&);
|
String command_default_paragraph_separator_value(DOM::Document const&);
|
||||||
bool command_delete_action(DOM::Document&, String const&);
|
bool command_delete_action(DOM::Document&, String const&);
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
d1 contents: "foo<a href="https://ladybird.org">bar</a>"
|
||||||
|
d2 contents: "<a href="https://ladybird.org">ladybird</a>"
|
23
Tests/LibWeb/Text/input/Editing/execCommand-createLink.html
Normal file
23
Tests/LibWeb/Text/input/Editing/execCommand-createLink.html
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<script src="../include.js"></script>
|
||||||
|
<div contenteditable="true" id="d1">foobar</div>
|
||||||
|
<div contenteditable="true" id="d2"><a href="https://ladybird.dev">ladybird</a></div>
|
||||||
|
<script>
|
||||||
|
test(() => {
|
||||||
|
const range = document.createRange();
|
||||||
|
getSelection().addRange(range);
|
||||||
|
|
||||||
|
// Make d1's 'bar' a link
|
||||||
|
const div1 = document.querySelector('#d1');
|
||||||
|
range.setStart(div1.childNodes[0], 3);
|
||||||
|
range.setEnd(div1.childNodes[0], 6);
|
||||||
|
document.execCommand('createLink', false, 'https://ladybird.org');
|
||||||
|
println(`d1 contents: "${div1.innerHTML}"`);
|
||||||
|
|
||||||
|
// Change d2's 'ladybird' href
|
||||||
|
const div2 = document.querySelector('#d2');
|
||||||
|
range.setStart(div2.childNodes[0].childNodes[0], 4);
|
||||||
|
range.setEnd(div2.childNodes[0].childNodes[0], 5);
|
||||||
|
document.execCommand('createLink', false, 'https://ladybird.org');
|
||||||
|
println(`d2 contents: "${div2.innerHTML}"`);
|
||||||
|
});
|
||||||
|
</script>
|
Loading…
Add table
Add a link
Reference in a new issue