LibWeb: Refuse to recursively execute .execCommand()

Spec issue:

  https://github.com/w3c/editing/issues/477
This commit is contained in:
Jelle Raaijmakers 2025-01-23 11:19:20 +01:00 committed by Andreas Kling
parent 0c854f9afc
commit f731cffbd8
Notes: github-actions[bot] 2025-01-24 22:54:31 +00:00
4 changed files with 32 additions and 0 deletions

View file

@ -1101,6 +1101,8 @@ private:
GC::Ref<EditingHostManager> m_editing_host_manager;
bool m_inside_exec_command { false };
// https://w3c.github.io/editing/docs/execCommand/#default-single-line-container-name
FlyString m_default_single_line_container_name { HTML::TagNames::div };

View file

@ -20,6 +20,12 @@ WebIDL::ExceptionOr<bool> Document::exec_command(FlyString const& command, [[may
if (!is_html_document())
return WebIDL::InvalidStateError::create(realm(), "execCommand is only supported on HTML documents"_string);
// AD-HOC: All major browsers refuse to recursively execute execCommand() (e.g. inside input event handlers).
if (m_inside_exec_command)
return false;
ScopeGuard guard_recursion = [&] { m_inside_exec_command = false; };
m_inside_exec_command = true;
// 1. If only one argument was provided, let show UI be false.
// 2. If only one or two arguments were provided, let value be the empty string.
// NOTE: these steps are dealt by the default values for both show_ui and value

View file

@ -0,0 +1,4 @@
input event
inner result: false
outer result: true
foo

View file

@ -0,0 +1,20 @@
<script src="../include.js"></script>
<div contenteditable="true"></div>
<script>
test(() => {
const range = document.createRange();
getSelection().addRange(range);
const divElm = document.querySelector('div');
range.setStart(divElm, 0);
range.setEnd(divElm, 0);
divElm.addEventListener('input', () => {
println('input event');
println(`inner result: ${document.execCommand('insertText', false, 'bar')}`);
});
println(`outer result: ${document.execCommand('insertText', false, 'foo')}`);
println(divElm.innerHTML);
});
</script>