Skip to content

Commit 1eaecaa

Browse files
LibWeb: Insert newlines between block-level elements when copying text
The visible_text_in_range() helper used for clipboard serialisation only iterated over Text nodes, ignoring the block-level element boundaries between them. Selecting text that spans multiple <div> (or other block) elements would therefore produce a result with all the text concatenated without any separating newlines. Fix by also processing Element nodes while iterating the range: if an element's layout node is a block container or a line-break node (<br>), and the output buffer already contains some text, append a newline before continuing. This matches the plain-text serialisation behaviour of other browsers for the common case. Fixes #7315.
1 parent de10db6 commit 1eaecaa

File tree

1 file changed

+15
-1
lines changed

1 file changed

+15
-1
lines changed

Libraries/LibWeb/HTML/Navigable.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
#include <LibWeb/HTML/Window.h>
4949
#include <LibWeb/HTML/WindowProxy.h>
5050
#include <LibWeb/Infra/Strings.h>
51+
#include <LibWeb/Layout/BreakNode.h>
5152
#include <LibWeb/Layout/Node.h>
5253
#include <LibWeb/Layout/Viewport.h>
5354
#include <LibWeb/Loader/GeneratedPagesLoader.h>
@@ -2977,8 +2978,21 @@ static String visible_text_in_range(DOM::Range const& range)
29772978
builder.append(static_cast<DOM::Text const&>(*range.start_container()).data().substring_view(range.start_offset()));
29782979

29792980
range.for_each_contained([&](GC::Ref<DOM::Node> node) {
2980-
if (is<DOM::Text>(*node) && node->layout_node())
2981+
if (is<DOM::Text>(*node) && node->layout_node()) {
29812982
builder.append(static_cast<DOM::Text const&>(*node).data());
2983+
} else if (auto const* layout_node = node->layout_node()) {
2984+
// Block-level elements (div, p, h1–h6, etc.) and <br> elements
2985+
// each produce a newline in the plain-text clipboard representation.
2986+
// We only insert a newline if there is already some text in the
2987+
// buffer (to avoid a leading blank line) and if the last character
2988+
// is not already a newline (to avoid consecutive blank lines when
2989+
// block elements are nested).
2990+
if ((layout_node->is_block_container() || layout_node->is_break_node())
2991+
&& !builder.is_empty()
2992+
&& !builder.string_view().ends_with('\n')) {
2993+
builder.append('\n');
2994+
}
2995+
}
29822996
return IterationDecision::Continue;
29832997
});
29842998

0 commit comments

Comments
 (0)