diff --git a/Libraries/LibWeb/DOM/Document.h b/Libraries/LibWeb/DOM/Document.h index cce5c4f496b..8f906c91132 100644 --- a/Libraries/LibWeb/DOM/Document.h +++ b/Libraries/LibWeb/DOM/Document.h @@ -1101,6 +1101,8 @@ private: GC::Ref 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 }; diff --git a/Libraries/LibWeb/Editing/ExecCommand.cpp b/Libraries/LibWeb/Editing/ExecCommand.cpp index ae9c0f8ec47..fdbf2a42e0e 100644 --- a/Libraries/LibWeb/Editing/ExecCommand.cpp +++ b/Libraries/LibWeb/Editing/ExecCommand.cpp @@ -20,6 +20,12 @@ WebIDL::ExceptionOr 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 diff --git a/Tests/LibWeb/Text/expected/Editing/execCommand-no-recursion.txt b/Tests/LibWeb/Text/expected/Editing/execCommand-no-recursion.txt new file mode 100644 index 00000000000..fe8bf367251 --- /dev/null +++ b/Tests/LibWeb/Text/expected/Editing/execCommand-no-recursion.txt @@ -0,0 +1,4 @@ +input event +inner result: false +outer result: true +foo diff --git a/Tests/LibWeb/Text/input/Editing/execCommand-no-recursion.html b/Tests/LibWeb/Text/input/Editing/execCommand-no-recursion.html new file mode 100644 index 00000000000..d3baa7c12cf --- /dev/null +++ b/Tests/LibWeb/Text/input/Editing/execCommand-no-recursion.html @@ -0,0 +1,20 @@ + +
+