From e4fdb07c7fedbf4d28f40d4f6495881db7f7e3a7 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 16 Jul 2026 19:46:04 +0400 Subject: [PATCH] Paste block-formatted text as blocks in the article editor. --- .../iv/editor/iv_editor_widget.cpp | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/Telegram/SourceFiles/iv/editor/iv_editor_widget.cpp b/Telegram/SourceFiles/iv/editor/iv_editor_widget.cpp index de93ef5b05..aa3e867138 100644 --- a/Telegram/SourceFiles/iv/editor/iv_editor_widget.cpp +++ b/Telegram/SourceFiles/iv/editor/iv_editor_widget.cpp @@ -1416,6 +1416,38 @@ struct InlineFieldTrimResult { return context; } +[[nodiscard]] std::optional BlockClipboardDataFromFieldTags( + not_null data) { + const auto textMime = TextUtilities::TagsTextMimeType(); + const auto tagsMime = TextUtilities::TagsMimeType(); + if (!data->hasFormat(textMime) || !data->hasFormat(tagsMime)) { + return std::nullopt; + } + auto text = QString::fromUtf8(data->data(textMime)); + const auto tags = TextUtilities::DeserializeTags( + data->data(tagsMime), + int(text.size())); + auto entities = TextUtilities::ConvertTextTagsToEntities(tags); + const auto isBlockEntity = [](const EntityInText &entity) { + const auto type = entity.type(); + return (type == EntityType::Pre) + || (type == EntityType::Blockquote); + }; + if (!ranges::any_of(entities, isBlockEntity)) { + return std::nullopt; + } + auto page = SplitTextIntoRichPage({ + std::move(text), + std::move(entities), + }); + if (page.blocks.empty()) { + return std::nullopt; + } + auto result = ClipboardBlockData(); + result.blocks = std::move(page.blocks); + return ClipboardData(std::move(result)); +} + [[nodiscard]] std::optional PreparedMediaFromClipboard( not_null data, bool premium) { @@ -8599,6 +8631,17 @@ bool Widget::handleIvClipboardMime( }); return true; } + auto blockData = BlockClipboardDataFromFieldTags(data); + if (blockData + && ClipboardPasteInsertContext(activeTextInsertContext())) { + if (action == Ui::InputField::MimeAction::Check) { + return true; + } + crl::on_main(this, [=, blockData = std::move(*blockData)] { + pasteStructuredClipboardData(blockData); + }); + return true; + } if (action == Ui::InputField::MimeAction::Check) { return CanPrepareMediaFromClipboard(data); } else if (auto list = PreparedMediaFromClipboard(