LibWeb: Implement the "insertImage" editing command

This commit is contained in:
Jelle Raaijmakers 2025-01-10 09:45:02 +01:00 committed by Andreas Kling
parent 20fb7b1a49
commit 01ce9cb151
Notes: github-actions[bot] 2025-01-10 22:35:23 +00:00
4 changed files with 71 additions and 0 deletions

View file

@ -1276,6 +1276,51 @@ bool command_insert_html_action(DOM::Document& document, String const& value)
return true;
}
// https://w3c.github.io/editing/docs/execCommand/#the-insertimage-command
bool command_insert_image_action(DOM::Document& document, String const& value)
{
// 1. If value is the empty string, return false.
if (value.is_empty())
return false;
// 2. Delete the selection, with strip wrappers false.
auto& selection = *document.get_selection();
delete_the_selection(selection, true, false);
// 3. Let range be the active range.
auto range = active_range(document);
// 4. If the active range's start node is neither editable nor an editing host, return true.
if (!range->start_container()->is_editable_or_editing_host())
return true;
// 5. If range's start node is a block node whose sole child is a br, and its start offset is 0, remove its start
// node's child from it.
auto start_node = range->start_container();
if (is_block_node(start_node) && start_node->child_count() == 1 && is<HTML::HTMLBRElement>(*start_node->first_child())
&& range->start_offset() == 0)
start_node->first_child()->remove();
// 6. Let img be the result of calling createElement("img") on the context object.
auto img = MUST(DOM::create_element(document, HTML::TagNames::img, Namespace::HTML));
// 7. Run setAttribute("src", value) on img.
MUST(img->set_attribute(HTML::AttributeNames::src, value));
// 8. Run insertNode(img) on range.
MUST(range->insert_node(img));
// 9. Let selection be the result of calling getSelection() on the context object.
// NOTE: Already done so in step 2.
// 10. Run collapse() on selection, with first argument equal to the parent of img and the second argument equal to
// one plus the index of img.
MUST(selection.collapse(img->parent(), img->index() + 1));
// 11. Return true.
return true;
}
// https://w3c.github.io/editing/docs/execCommand/#the-insertlinebreak-command
bool command_insert_linebreak_action(DOM::Document& document, String const&)
{
@ -2032,6 +2077,12 @@ static Array const commands {
.action = command_insert_html_action,
.preserves_overrides = true,
},
// https://w3c.github.io/editing/docs/execCommand/#the-insertimage-command
CommandDefinition {
.command = CommandNames::insertImage,
.action = command_insert_image_action,
.preserves_overrides = true,
},
// https://w3c.github.io/editing/docs/execCommand/#the-insertlinebreak-command
CommandDefinition {
.command = CommandNames::insertLineBreak,

View file

@ -46,6 +46,7 @@ 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_html_action(DOM::Document&, String const&);
bool command_insert_image_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&);

View file

@ -0,0 +1 @@
foo<img src="../../../Assets/120.png">bar

View file

@ -0,0 +1,18 @@
<script src="../include.js"></script>
<div contenteditable="true">foobar</div>
<script>
test(() => {
var divElm = document.querySelector('div');
// Put cursor between 'foo' and 'bar'
var range = document.createRange();
getSelection().addRange(range);
range.setStart(divElm.childNodes[0], 3);
range.setEnd(divElm.childNodes[0], 3);
// Insert HTML
document.execCommand('insertImage', false, '../../../Assets/120.png');
println(divElm.innerHTML);
});
</script>