diff --git a/Web/Models/Repositories/Posts.php b/Web/Models/Repositories/Posts.php index 36082f24..da1f9c8d 100644 --- a/Web/Models/Repositories/Posts.php +++ b/Web/Models/Repositories/Posts.php @@ -53,9 +53,9 @@ class Posts $offset--; } } - } else if(!is_null($offset)) { + } /*else if(!is_null($offset)) { $offset--; - } + }*/ $sel = $this->posts->where([ "wall" => $user, diff --git a/Web/Presenters/NotesPresenter.php b/Web/Presenters/NotesPresenter.php index 67105fe3..37475013 100644 --- a/Web/Presenters/NotesPresenter.php +++ b/Web/Presenters/NotesPresenter.php @@ -22,15 +22,10 @@ final class NotesPresenter extends OpenVKPresenter if(!$user->getPrivacyPermission('notes.read', $this->user->identity ?? NULL)) $this->flashFail("err", tr("forbidden"), tr("forbidden_comment")); - $this->template->notes = $this->notes->getUserNotes($user, (int)($this->queryParam("p") ?? 1)); + $this->template->page = (int)($this->queryParam("p") ?? 1); + $this->template->notes = $this->notes->getUserNotes($user, $this->template->page); $this->template->count = $this->notes->getUserNotesCount($user); $this->template->owner = $user; - $this->template->paginatorConf = (object) [ - "count" => $this->template->count, - "page" => $this->queryParam("p") ?? 1, - "amount" => NULL, - "perPage" => OPENVK_DEFAULT_PER_PAGE, - ]; } function renderView(int $owner, int $note_id): void diff --git a/Web/Presenters/OpenVKPresenter.php b/Web/Presenters/OpenVKPresenter.php index a5a76011..60858bcc 100644 --- a/Web/Presenters/OpenVKPresenter.php +++ b/Web/Presenters/OpenVKPresenter.php @@ -283,6 +283,11 @@ abstract class OpenVKPresenter extends SimplePresenter } } + /*if($this->queryParam('al') == '1') { + $this->assertNoCSRF(); + header('Content-Type: text/plain; charset=UTF-8'); + }*/ + parent::onStartup(); } diff --git a/Web/Presenters/SearchPresenter.php b/Web/Presenters/SearchPresenter.php index a7f3f151..9e16450e 100644 --- a/Web/Presenters/SearchPresenter.php +++ b/Web/Presenters/SearchPresenter.php @@ -125,5 +125,6 @@ final class SearchPresenter extends OpenVKPresenter ]; $this->template->extendedPaginatorConf = clone $this->template->paginatorConf; $this->template->extendedPaginatorConf->space = 11; + $this->template->paginatorConf->atTop = true; } } diff --git a/Web/Presenters/templates/@layout.xml b/Web/Presenters/templates/@layout.xml index d7a15912..0e514bb8 100644 --- a/Web/Presenters/templates/@layout.xml +++ b/Web/Presenters/templates/@layout.xml @@ -87,7 +87,14 @@ {/if}
- ⬆ {_to_top} +
+ + {_to_top} +
+ +
+ +
@@ -384,6 +391,7 @@ {script "js/al_polls.js"} {script "js/al_suggestions.js"} {script "js/al_navigation.js"} + {script "js/al_comments.js"} {ifset $thisUser} {script "js/al_notifs.js"} diff --git a/Web/Presenters/templates/@listView.xml b/Web/Presenters/templates/@listView.xml index 4b2dd9ff..f97d0da5 100644 --- a/Web/Presenters/templates/@listView.xml +++ b/Web/Presenters/templates/@listView.xml @@ -19,7 +19,7 @@ {ifset specpage} {include specpage, x => $dat} {else} -
+
{var $data = is_array($iterator) ? $iterator : iterator_to_array($iterator)} {ifset top} @@ -27,7 +27,7 @@ {/ifset} {if sizeof($data) > 0} -
+
diff --git a/Web/Presenters/templates/Audio/List.xml b/Web/Presenters/templates/Audio/List.xml index b67bb208..32d2e26b 100644 --- a/Web/Presenters/templates/Audio/List.xml +++ b/Web/Presenters/templates/Audio/List.xml @@ -64,8 +64,8 @@
{include "../components/content_error.xml", description => $ownerId > 0 ? ($ownerId == $thisUser->getId() ? tr("no_audios_thisuser") : tr("no_audios_user")) : tr("no_audios_club")}
-
-
+
+
{include "player.xml", audio => $audio, club => $club}
@@ -86,10 +86,10 @@ {include "../components/content_error.xml", description => $ownerId > 0 ? ($ownerId == $thisUser->getId() ? tr("no_playlists_thisuser") : tr("no_playlists_user")) : tr("no_playlists_club")}
-
- {foreach $playlists as $playlist} +
+
{include 'playlistListView.xml', playlist => $playlist} - {/foreach} +
diff --git a/Web/Presenters/templates/Audio/Playlist.xml b/Web/Presenters/templates/Audio/Playlist.xml index 4139fa2f..7f8c7348 100644 --- a/Web/Presenters/templates/Audio/Playlist.xml +++ b/Web/Presenters/templates/Audio/Playlist.xml @@ -67,11 +67,11 @@
-
+
{if $count < 1} {_empty_playlist} {else} -
+
{include "player.xml", audio => $audio}
diff --git a/Web/Presenters/templates/Gifts/Pick.xml b/Web/Presenters/templates/Gifts/Pick.xml index dad30839..cb01b944 100644 --- a/Web/Presenters/templates/Gifts/Pick.xml +++ b/Web/Presenters/templates/Gifts/Pick.xml @@ -12,8 +12,8 @@ {/block} {block content} -
-
+
+
{_gift} diff --git a/Web/Presenters/templates/Group/Suggested.xml b/Web/Presenters/templates/Group/Suggested.xml index 1c882675..1a07e0a8 100644 --- a/Web/Presenters/templates/Group/Suggested.xml +++ b/Web/Presenters/templates/Group/Suggested.xml @@ -12,9 +12,9 @@ {include "../components/error.xml", title => "", description => $type == "my" ? tr("no_suggested_posts_by_you") : tr("no_suggested_posts_by_people")} {else}

{if $type == "my"}{tr("suggested_posts_in_group_by_you", $count)}{else}{tr("suggested_posts_in_group", $count)}{/if}

-
+
{var $microblog = $thisUser->hasMicroblogEnabled()} -
+
{if $microblog} {include "../components/post/microblogpost.xml", post => $post, commentSection => false, suggestion => true, forceNoCommentsLink => true, forceNoPinLink => true, forceNoLike => true, forceNoShareLink => true, forceNoDeleteLink => false} {else} diff --git a/Web/Presenters/templates/Messenger/Index.xml b/Web/Presenters/templates/Messenger/Index.xml index 5c62bf9f..b045c06f 100644 --- a/Web/Presenters/templates/Messenger/Index.xml +++ b/Web/Presenters/templates/Messenger/Index.xml @@ -17,9 +17,9 @@
{if sizeof($corresps) > 0} -
+
{var $recipient = $coresp->getCorrespondents()[1]} {var $lastMsg = $coresp->getPreviewMessage()} diff --git a/Web/Presenters/templates/Notes/List.xml b/Web/Presenters/templates/Notes/List.xml index 7f2fcf7c..3189a146 100644 --- a/Web/Presenters/templates/Notes/List.xml +++ b/Web/Presenters/templates/Notes/List.xml @@ -1,6 +1,5 @@ {extends "../@listView.xml"} {var $iterator = iterator_to_array($notes)} -{var $page = $paginatorConf->page} {block title}{_notes}{/block} @@ -60,12 +59,12 @@ } -
+
+
{var $sxModel = $dat->getModel(1)} diff --git a/Web/Presenters/templates/Photos/Album.xml b/Web/Presenters/templates/Photos/Album.xml index e8157dd1..fa779e11 100644 --- a/Web/Presenters/templates/Photos/Album.xml +++ b/Web/Presenters/templates/Photos/Album.xml @@ -30,10 +30,10 @@ {/if}

{if $album->getPhotosCount() > 0} -
@@ -125,10 +125,14 @@ {elseif $section === 'groups'} -
+
@@ -180,10 +184,14 @@ {elseif $section === 'apps'} -
+
@@ -210,10 +218,14 @@ {elseif $section === 'posts'} -
+
{if !$dat || $dat->getWallOwner()->isHideFromGlobalFeedEnabled()} {_closed_group_post}. {else} @@ -222,31 +234,47 @@
{elseif $section === 'videos'} -
+
{include "../components/video.xml", video => $dat}
{elseif $section === 'audios'} -
+
{include "../Audio/player.xml", audio => $dat}
{elseif $section === 'audios_playlists'} -
+
{include "../Audio/playlistListView.xml", playlist => $dat}
{/if} {else} diff --git a/Web/Presenters/templates/User/Groups.xml b/Web/Presenters/templates/User/Groups.xml index bca006e8..d3528268 100644 --- a/Web/Presenters/templates/User/Groups.xml +++ b/Web/Presenters/templates/User/Groups.xml @@ -2,6 +2,7 @@ {var $iterator = $user->getClubs($page, $admin)} {var $count = $user->getClubCount($admin)} +{block noscroll}{/block} {block title} {_groups} {/block} @@ -121,8 +122,8 @@

{_search_group}

{_search_group_desc}
- - + +
diff --git a/Web/Presenters/templates/Wall/Feed.xml b/Web/Presenters/templates/Wall/Feed.xml index e609419c..94658a81 100644 --- a/Web/Presenters/templates/Wall/Feed.xml +++ b/Web/Presenters/templates/Wall/Feed.xml @@ -23,10 +23,12 @@ {include "../components/textArea.xml", route => "/wall" . $thisUser->getId() . "/makePost", graffiti => true, polls => true, notes => true, hasSource => true}
- {foreach $posts as $post} -
- {include "../components/post.xml", post => $post, onWallOf => true, commentSection => true} - {/foreach} +
+
+ + {include "../components/post.xml", post => $post, onWallOf => true, commentSection => true} +
+
@@ -55,8 +57,4 @@ window.location.assign(url.replace("__padding", e.target.value)); }); - - {if isset($thisUser) && $thisUser->hasMicroblogEnabled()} - {script "js/al_comments.js"} - {/if} {/block} diff --git a/Web/Presenters/templates/Wall/Wall.xml b/Web/Presenters/templates/Wall/Wall.xml index 80452295..4d3d1cee 100644 --- a/Web/Presenters/templates/Wall/Wall.xml +++ b/Web/Presenters/templates/Wall/Wall.xml @@ -31,13 +31,13 @@ {include "../components/textArea.xml", route => "/wall$owner/makePost", hasSource => true}
-
+
{if sizeof($posts) > 0} - {foreach $posts as $post} +
{include "../components/post.xml", post => $post, commentSection => true} - {/foreach} +
{include "../components/paginator.xml", conf => $paginatorConf} {else} {_no_posts_abstract} @@ -45,8 +45,4 @@
- - {if isset($thisUser) && $thisUser->hasMicroblogEnabled()} - {script "js/al_comments.js"} - {/if} {/block} diff --git a/Web/Presenters/templates/components/comments.xml b/Web/Presenters/templates/components/comments.xml index 0df0c91f..53253b5f 100644 --- a/Web/Presenters/templates/components/comments.xml +++ b/Web/Presenters/templates/components/comments.xml @@ -9,14 +9,14 @@
{if sizeof($comments) > 0} - {foreach $comments as $comment} - {include "comment.xml", comment => $comment} - {/foreach} +
+
+ {include "comment.xml", comment => $comment} +
+
{include "paginator.xml", conf => (object) ["page" => $page, "count" => $count, "amount" => sizeof($comments), "perPage" => 10]}
{else} {_comments_tip} {/if} - -{script "js/al_comments.js"} diff --git a/Web/Presenters/templates/components/paginator.xml b/Web/Presenters/templates/components/paginator.xml index 0dffd004..3db45de9 100644 --- a/Web/Presenters/templates/components/paginator.xml +++ b/Web/Presenters/templates/components/paginator.xml @@ -2,7 +2,7 @@ {var $pageCount = ceil($conf->count / $conf->perPage)}
-
+
« {for $j = $conf->page - ($space-1); $j <= $conf->page + ($space-1); $j++} {$j} diff --git a/Web/Presenters/templates/components/wall.xml b/Web/Presenters/templates/components/wall.xml index 91e08fbc..b00681a1 100644 --- a/Web/Presenters/templates/components/wall.xml +++ b/Web/Presenters/templates/components/wall.xml @@ -13,13 +13,13 @@ {include "../components/textArea.xml", route => "/wall$owner/makePost", graffiti => true, polls => true, notes => true, hasSource => true}
-
+
{if sizeof($posts) > 0} - {foreach $posts as $post} +
{include "../components/post.xml", post => $post, commentSection => true} - {/foreach} +
{include "../components/paginator.xml", conf => $paginatorConf} {else} {_no_posts_abstract} @@ -28,7 +28,3 @@
- -{if isset($thisUser) && $thisUser->hasMicroblogEnabled()} - {script "js/al_comments.js"} -{/if} diff --git a/Web/static/css/main.css b/Web/static/css/main.css index 69147a03..617f1036 100644 --- a/Web/static/css/main.css +++ b/Web/static/css/main.css @@ -1435,7 +1435,7 @@ textarea { .toTop { position: fixed; - padding: 20px; + padding: 12px; width: 100px; height: 100%; background-color: #f3f3f3; @@ -1445,9 +1445,34 @@ textarea { opacity: 0; transition: .1s all; z-index: 129; + user-select: none; } -body.scrolled .toTop:hover { +.toTop > div svg { + display: inline-block; + margin-right: 2px; + width: 8px; + height: 7px; + fill: #3f3f3f; +} + +.toTop > div span { + font-weight: bold; +} + +.toTop.has_down #to_up, .toTop #to_back { + display: none; +} + +.toTop.has_down #to_back { + display: block; +} + +.toTop.has_down { + opacity: .3; +} + +body.scrolled .toTop:hover, .toTop.has_down:hover { opacity: .5; cursor: pointer; } diff --git a/Web/static/js/al_comments.js b/Web/static/js/al_comments.js index f4172428..ad398637 100644 --- a/Web/static/js/al_comments.js +++ b/Web/static/js/al_comments.js @@ -1,4 +1,4 @@ -u(".comment-reply").on("click", function(e) { +u(document).on("click", ".comment-reply", function(e) { let comment = u(e.target).closest(".post"); let authorId = comment.data("owner-id"); let authorNm = u(".post-author > a > b", comment.first()).text().trim(); @@ -8,6 +8,8 @@ u(".comment-reply").on("click", function(e) { let mention = ("[" + (fromGroup ? "club" : "id") + authorId + "|" + authorNm + "], "); // Substitute pervious mention if present, prepend otherwise - inputbox.nodes[0].value = inputbox.nodes[0].value.replace(/(^\[([A-Za-z0-9]+)\|([\p{L} 0-9@]+)\], |^)/u, mention); + inputbox.nodes.forEach(node => { + node.value = node.value.replace(/(^\[([A-Za-z0-9]+)\|([\p{L} 0-9@]+)\], |^)/u, mention); + }) inputbox.trigger("focusin"); }); diff --git a/Web/static/js/al_feed.js b/Web/static/js/al_feed.js index 2831d6f1..7ca8a798 100644 --- a/Web/static/js/al_feed.js +++ b/Web/static/js/al_feed.js @@ -84,6 +84,7 @@ u(document).on('click', '#__feed_settings_link', (e) => { const CURRENT_PERPAGE = Number(__temp_url.searchParams.get('posts') ?? 10) const CURRENT_PAGE = Number(__temp_url.searchParams.get('p') ?? 1) const CURRENT_RETURN_BANNED = Number(__temp_url.searchParams.get('return_banned') ?? 0) + const CURRENT_AUTO_SCROLL = Number(localStorage.getItem('ux.auto_scroll') ?? 1) const COUNT = [1, 5, 10, 20, 30, 40, 50] u('#_feed_settings_container #__content').html(`
@@ -107,11 +108,21 @@ u(document).on('click', '#__feed_settings_link', (e) => { + + + + @@ -268,3 +279,7 @@ u(document).on('click', '#__feed_settings_link', (e) => { __switchTab('main') }) + +u(document).on('change', `input[data-act='localstorage_item']`, (e) => { + localStorage.setItem(e.target.name, Number(e.target.checked)) +}) diff --git a/Web/static/js/al_mentions.js b/Web/static/js/al_mentions.js index 1be77563..d324cca6 100644 --- a/Web/static/js/al_mentions.js +++ b/Web/static/js/al_mentions.js @@ -19,7 +19,8 @@ var tooltipTemplate = Handlebars.compile(`
- + - ${tr('show_ignored_sources')} + +
+ + + + +
`); -tippy(".mention", { +tippy.delegate("body", { + target: '.mention', theme: "light vk", content: "⌛", allowHTML: true, diff --git a/Web/static/js/al_music.js b/Web/static/js/al_music.js index ac609358..2c8e11db 100644 --- a/Web/static/js/al_music.js +++ b/Web/static/js/al_music.js @@ -631,6 +631,35 @@ class bigPlayer { duration: this.tracks["currentTrack"].length }) } + + loadContextPage(page, lesser = false) { + const formdata = new FormData() + formdata.append("context", this.context["context_type"]) + formdata.append("context_entity", this.context["context_id"]) + formdata.append("hash", u("meta[name=csrf]").attr("value")) + formdata.append("page", page) + + ky.post("/audios/context", { + hooks: { + afterResponse: [ + async (_request, _options, response) => { + const newArr = await response.json() + + if(lesser) + this.tracks["tracks"] = newArr["items"].concat(this.tracks["tracks"]) + else + this.tracks["tracks"] = this.tracks["tracks"].concat(newArr["items"]) + + this.context["playedPages"].push(String(newArr["page"])) + + this.updateButtons() + console.info("Loaded context for page " + page) + } + ] + }, + body: formdata + }) + } } document.addEventListener("DOMContentLoaded", function() { diff --git a/Web/static/js/al_suggestions.js b/Web/static/js/al_suggestions.js index 1c3da3e8..befe78b7 100644 --- a/Web/static/js/al_suggestions.js +++ b/Web/static/js/al_suggestions.js @@ -201,7 +201,7 @@ $(document).on("click", ".sugglist a", (e) => { }) // нажатие на пагинатор у постов предложки -$(document).on("click", "#postz .paginator a", (e) => { +/*$(document).on("click", "#postz .paginator a", (e) => { e.preventDefault() ky(e.currentTarget.href, { @@ -228,4 +228,4 @@ $(document).on("click", "#postz .paginator a", (e) => { ] } }) -}) +})*/ diff --git a/Web/static/js/al_wall.js b/Web/static/js/al_wall.js index 0ad15df7..320ab9e4 100644 --- a/Web/static/js/al_wall.js +++ b/Web/static/js/al_wall.js @@ -399,6 +399,7 @@ async function OpenVideo(video_arr = [], init_player = true) details.find('.media-page-wrapper-description b').remove() u('#ovk-player-info').html(details.html()) + bsdnHydrate() } }) @@ -542,7 +543,8 @@ var tooltipClientNoInfoTemplate = Handlebars.compile(` `); -tippy(".client_app", { +tippy.delegate("body", { + target: '.client_app', theme: "light vk", content: "⌛", allowHTML: true, @@ -2003,6 +2005,85 @@ $(document).on("click", ".avatarDelete", (e) => { ]); }) +async function __processPaginatorNextPage(page) +{ + const container = u('.scroll_container') + const container_node = '.scroll_node' + const parser = new DOMParser + + const replace_url = new URL(location.href) + replace_url.searchParams.set('p', page) + /*replace_url.searchParams.set('al', 1) + replace_url.searchParams.set('hash', u("meta[name=csrf]").attr("value"))*/ + + const new_content = await fetch(replace_url.href) + const new_content_response = await new_content.text() + const parsed_content = parser.parseFromString(new_content_response, 'text/html') + + const nodes = parsed_content.querySelectorAll(container_node) + nodes.forEach(node => { + container.append(node) + }) + + u(`.paginator:not(.paginator-at-top)`).html(parsed_content.querySelector('.paginator:not(.paginator-at-top)').innerHTML) + if(u(`.paginator:not(.paginator-at-top)`).nodes[0].closest('.scroll_container')) { + container.nodes[0].append(u(`.paginator:not(.paginator-at-top)`).nodes[0].parentNode) + } + + if(window.player) { + window.player.loadContextPage(page) + } + + if(typeof __scrollHook != 'undefined') { + __scrollHook(page) + } +} + +const showMoreObserver = new IntersectionObserver(entries => { + entries.forEach(async x => { + if(x.isIntersecting) { + if(Number(localStorage.getItem('ux.auto_scroll') ?? 1) == 0) { + return + } + + if(u('.scroll_container').length < 1) { + return + } + + const target = u(x.target) + if(target.length < 1 || target.hasClass('paginator-at-top')) { + return + } + + const current_url = new URL(location.href) + if(current_url.searchParams && !isNaN(parseInt(current_url.searchParams.get('p')))) { + return + } + + target.addClass('lagged') + const active_tab = target.find('.active') + const next_page = u(active_tab.nodes[0] ? active_tab.nodes[0].nextElementSibling : null) + if(next_page.length < 1) { + u('.paginator:not(.paginator-at-top)').removeClass('lagged') + return + } + + const page_number = Number(next_page.html()) + await __processPaginatorNextPage(page_number) + bsdnHydrate() + u('.paginator:not(.paginator-at-top)').removeClass('lagged') + } + }) +}, { + root: null, + rootMargin: '0px', + threshold: 0, +}) + +if(u('.paginator:not(.paginator-at-top)').length > 0) { + showMoreObserver.observe(u('.paginator:not(.paginator-at-top)').nodes[0]) +} + u(document).on('click', '#__sourceAttacher', (e) => { MessageBox(tr('add_source'), `
diff --git a/Web/static/js/openvk.cls.js b/Web/static/js/openvk.cls.js index 428fd165..709630c8 100644 --- a/Web/static/js/openvk.cls.js +++ b/Web/static/js/openvk.cls.js @@ -63,7 +63,7 @@ document.addEventListener("DOMContentLoaded", function() { //BEGIN }); /* @rem-pai why this func wasn't named as "#_deleteDialog"? It looks universal IMO */ - u("#_noteDelete").on("click", function(e) { + u(document).on("click", "#_noteDelete", function(e) { var formHtml = "
"; formHtml += ""; formHtml += "
"; @@ -140,7 +140,7 @@ document.addEventListener("DOMContentLoaded", function() { //BEGIN return false; }); - u("#_submitUserSubscriptionAction").handle("submit", async function(e) { + u(document).handle("submit", "#_submitUserSubscriptionAction", async function(e) { u(this).nodes[0].parentElement.classList.add('loading'); u(this).nodes[0].parentElement.classList.add('disable'); console.log(e.target); diff --git a/Web/static/js/scroll.js b/Web/static/js/scroll.js index 3b652afd..dff0ca4b 100644 --- a/Web/static/js/scroll.js +++ b/Web/static/js/scroll.js @@ -1,14 +1,35 @@ window.addEventListener("scroll", function(e) { if(window.scrollY < 100) { + if(window.temp_y_scroll) { + u('.toTop').addClass('has_down') + } document.body.classList.toggle("scrolled", false); } else { document.body.classList.toggle("scrolled", true); + u('.toTop').removeClass('has_down') } }); u(".toTop").on("click", function(e) { - window.scrollTo({ - top: 0, - behavior: "smooth" - }); -}); \ No newline at end of file + const y_scroll = window.scrollY + const scroll_margin = 20 + + if(y_scroll > 100) { + window.temp_y_scroll = y_scroll + window.scrollTo(0, scroll_margin) + window.scrollTo({ + top: 0, + behavior: "smooth" + }) + } else { + if(window.temp_y_scroll) { + window.scrollTo(0, window.temp_y_scroll - scroll_margin) + window.scrollTo({ + top: window.temp_y_scroll, + behavior: "smooth" + }) + } + } + + u(document).trigger('scroll') +}) diff --git a/locales/en.strings b/locales/en.strings index 7a84ae09..c1ff0822 100644 --- a/locales/en.strings +++ b/locales/en.strings @@ -220,6 +220,7 @@ "all_news" = "All news"; "posts_per_page" = "Number of posts per page"; "show_ignored_sources" = "Show ignored sources"; +"auto_scroll" = "Autoscroll"; "attachment" = "Attachment"; "post_as_group" = "Post as group"; diff --git a/locales/ru.strings b/locales/ru.strings index 33dd70d1..8a2d4e8c 100644 --- a/locales/ru.strings +++ b/locales/ru.strings @@ -205,6 +205,7 @@ "all_news" = "Все новости"; "posts_per_page" = "Количество записей на странице"; "show_ignored_sources" = "Показывать игнорируемые источники"; +"auto_scroll" = "Автоматическая прокрутка"; "attachment" = "Вложение"; "post_as_group" = "От имени сообщества"; "comment_as_group" = "От имени сообщества";