diff --git a/Telegram/Resources/export_html/css/style.css b/Telegram/Resources/export_html/css/style.css index 79b680cc2..102f5f3a5 100644 --- a/Telegram/Resources/export_html/css/style.css +++ b/Telegram/Resources/export_html/css/style.css @@ -559,3 +559,26 @@ div.toast_shown { opacity: 0; user-select: none; } + +.bot_buttons_table { + border-spacing: 0px 2px; + width: 100%; +} +.bot_button { + border-radius: 8px; + text-align: center; + vertical-align: middle; + background-color: #168acd40; +} +.bot_button_row { + display: table; + table-layout: fixed; + padding: 0px; + width:100%; +} +.bot_button_row div { + display: table-cell; +} +.bot_button_column_separator { + width: 2px +} diff --git a/Telegram/Resources/export_html/js/script.js b/Telegram/Resources/export_html/js/script.js index 8d25f5302..284232202 100644 --- a/Telegram/Resources/export_html/js/script.js +++ b/Telegram/Resources/export_html/js/script.js @@ -62,6 +62,12 @@ function ShowNotAvailableEmoji() { return false; } +function ShowTextCopied(content) { + navigator.clipboard.writeText(content); + ShowToast("Text copied to clipboard."); + return false; +} + function ShowSpoiler(target) { if (target.classList.contains("hidden")) { target.classList.toggle("hidden"); diff --git a/Telegram/SourceFiles/export/data/export_data_types.cpp b/Telegram/SourceFiles/export/data/export_data_types.cpp index f7928f006..1f56f9ec1 100644 --- a/Telegram/SourceFiles/export/data/export_data_types.cpp +++ b/Telegram/SourceFiles/export/data/export_data_types.cpp @@ -160,6 +160,30 @@ std::vector> ButtonRowsFromTL( } // namespace +QByteArray HistoryMessageMarkupButton::TypeToString( + const HistoryMessageMarkupButton &button) { + using Type = HistoryMessageMarkupButton::Type; + switch (button.type) { + case Type::Default: return "default"; + case Type::Url: return "url"; + case Type::Callback: return "callback"; + case Type::CallbackWithPassword: return "callback_with_password"; + case Type::RequestPhone: return "request_phone"; + case Type::RequestLocation: return "request_location"; + case Type::RequestPoll: return "request_poll"; + case Type::RequestPeer: return "request_peer"; + case Type::SwitchInline: return "switch_inline"; + case Type::SwitchInlineSame: return "switch_inline_same"; + case Type::Game: return "game"; + case Type::Buy: return "buy"; + case Type::Auth: return "auth"; + case Type::UserProfile: return "user_profile"; + case Type::WebView: return "web_view"; + case Type::SimpleWebView: return "simple_web_view"; + } + Unexpected("Type in HistoryMessageMarkupButton::Type."); +} + uint8 PeerColorIndex(BareId bareId) { const uint8 map[] = { 0, 7, 4, 1, 6, 3, 5 }; return map[bareId % base::array_size(map)]; diff --git a/Telegram/SourceFiles/export/data/export_data_types.h b/Telegram/SourceFiles/export/data/export_data_types.h index 5f2c2da39..76585991c 100644 --- a/Telegram/SourceFiles/export/data/export_data_types.h +++ b/Telegram/SourceFiles/export/data/export_data_types.h @@ -690,6 +690,8 @@ struct HistoryMessageMarkupButton { SimpleWebView, }; + static QByteArray TypeToString(const HistoryMessageMarkupButton &); + Type type; QString text; QByteArray data; diff --git a/Telegram/SourceFiles/export/output/export_output_html.cpp b/Telegram/SourceFiles/export/output/export_output_html.cpp index 395315227..9df6bcbb3 100644 --- a/Telegram/SourceFiles/export/output/export_output_html.cpp +++ b/Telegram/SourceFiles/export/output/export_output_html.cpp @@ -1443,6 +1443,55 @@ auto HtmlWriter::Wrap::pushMessage( block.append(text); block.append(popTag()); } + if (!message.inlineButtonRows.empty()) { + using Type = HistoryMessageMarkupButton::Type; + const auto endline = u" | "_q; + block.append(pushTag("table", { { "class", "bot_buttons_table" } })); + block.append(pushTag("tbody")); + for (const auto &row : message.inlineButtonRows) { + block.append(pushTag("tr")); + block.append(pushTag("td", { { "class", "bot_button_row" } })); + for (const auto &button : row) { + using Attribute = std::pair; + const auto content = (!button.data.isEmpty() + ? (u"Data: "_q + button.data + endline) + : QString()) + + (!button.forwardText.isEmpty() + ? (u"Forward text: "_q + button.forwardText + endline) + : QString()) + + (u"Type: "_q + + HistoryMessageMarkupButton::TypeToString(button)); + const auto link = (button.type == Type::Url) + ? button.data + : QByteArray(); + const auto onclick = (button.type != Type::Url) + ? ("return ShowTextCopied('" + content + "');").toUtf8() + : QByteArray(); + block.append(pushTag("div", { { "class", "bot_button" } })); + block.append(pushTag("a", { + link.isEmpty() ? Attribute() : Attribute{ "href", link }, + onclick.isEmpty() + ? Attribute() + : Attribute{ "onclick", onclick }, + })); + block.append(pushTag("div")); + block.append(button.text.toUtf8()); + block.append(popTag()); + block.append(popTag()); + block.append(popTag()); + + if (&button != &row.back()) { + block.append(pushTag("div", { + { "class", "bot_button_column_separator" } + })); + block.append(popTag()); + } + } + block.append(popTag()); + block.append(popTag()); + } + block.append(popTag()); + } if (!message.signature.isEmpty()) { block.append(pushDiv("signature details")); block.append(SerializeString(message.signature)); diff --git a/Telegram/SourceFiles/export/output/export_output_json.cpp b/Telegram/SourceFiles/export/output/export_output_json.cpp index dde36a5a3..5bd7f2c37 100644 --- a/Telegram/SourceFiles/export/output/export_output_json.cpp +++ b/Telegram/SourceFiles/export/output/export_output_json.cpp @@ -784,29 +784,6 @@ QByteArray SerializeMessage( pushBare("text_entities", SerializeText(context, message.text, true)); if (!message.inlineButtonRows.empty()) { - const auto typeString = []( - const HistoryMessageMarkupButton &entry) -> QByteArray { - using Type = HistoryMessageMarkupButton::Type; - switch (entry.type) { - case Type::Default: return "default"; - case Type::Url: return "url"; - case Type::Callback: return "callback"; - case Type::CallbackWithPassword: return "callback_with_password"; - case Type::RequestPhone: return "request_phone"; - case Type::RequestLocation: return "request_location"; - case Type::RequestPoll: return "request_poll"; - case Type::RequestPeer: return "request_peer"; - case Type::SwitchInline: return "switch_inline"; - case Type::SwitchInlineSame: return "switch_inline_same"; - case Type::Game: return "game"; - case Type::Buy: return "buy"; - case Type::Auth: return "auth"; - case Type::UserProfile: return "user_profile"; - case Type::WebView: return "web_view"; - case Type::SimpleWebView: return "simple_web_view"; - } - Unexpected("Type in HistoryMessageMarkupButton::Type."); - }; const auto serializeRow = [&]( const std::vector &row) { context.nesting.push_back(Context::kArray); @@ -817,7 +794,8 @@ QByteArray SerializeMessage( auto pairs = std::vector>(); pairs.push_back({ "type", - SerializeString(typeString(entry)), + SerializeString( + HistoryMessageMarkupButton::TypeToString(entry)), }); if (!entry.text.isEmpty()) { pairs.push_back({