Compare commits

...

6 commits

Author SHA1 Message Date
mrilyew
6ab9ca13e6
Merge a4d5bb8088 into b4fd4f018c 2024-11-04 13:30:22 +03:00
Jillian Österreich
b4fd4f018c
chore(about,readme): dev force update and small changes 2024-11-04 04:00:36 +07:00
mrilyew
a4d5bb8088 Merge branch 'master' into infinityscroll2 2024-11-02 14:16:42 +03:00
mrilyew
c4fec2bf97 rework to up button 2024-11-02 13:02:34 +03:00
mrilyew
389f0b4bb4 allow comments scroll 2024-11-02 12:13:17 +03:00
mrilyew
8fc47ff6cd rewrite 2024-11-02 11:16:25 +03:00
26 changed files with 261 additions and 72 deletions

View file

@ -4,7 +4,7 @@ _[Русский](README_RU.md)_
**OpenVK** is an attempt to create a simple CMS that ~~cosplays~~ imitates old VKontakte. Code provided here is not stable yet. **OpenVK** is an attempt to create a simple CMS that ~~cosplays~~ imitates old VKontakte. Code provided here is not stable yet.
VKontakte belongs to Pavel Durov and VK Group. VKontakte belongs to VK (formerly Mail.ru Group).
To be honest, we don't know whether if it even works. However, this version is maintained and we will be happy to accept your bugreports [in our bug tracker](https://github.com/openvk/openvk/projects/1). You should also be able to submit them using [ticketing system](https://ovk.to/support?act=new) (you will need an OpenVK account for this). To be honest, we don't know whether if it even works. However, this version is maintained and we will be happy to accept your bugreports [in our bug tracker](https://github.com/openvk/openvk/projects/1). You should also be able to submit them using [ticketing system](https://ovk.to/support?act=new) (you will need an OpenVK account for this).

View file

@ -4,7 +4,7 @@ _[English](README.md)_
**OpenVK** — это попытка создать простую CMS, которая ~~косплеит~~ имитирует старый ВКонтакте. На данный момент, представленный здесь исходный код проекта пока не является стабильным. **OpenVK** — это попытка создать простую CMS, которая ~~косплеит~~ имитирует старый ВКонтакте. На данный момент, представленный здесь исходный код проекта пока не является стабильным.
ВКонтакте принадлежит Павлу Дурову и VK Group. ВКонтакте принадлежит VK (в прошлом Mail.ru Group).
Честно говоря, мы даже не знаем, работает ли она вообще. Однако, эта версия поддерживается, и мы будем рады принять ваши сообщения об ошибках [в нашем баг-трекере](https://github.com/openvk/openvk/projects/1). Вы также можете отправлять их через [вкладку "Помощь"](https://ovk.to/support?act=new) (для этого вам понадобится учетная запись OpenVK). Честно говоря, мы даже не знаем, работает ли она вообще. Однако, эта версия поддерживается, и мы будем рады принять ваши сообщения об ошибках [в нашем баг-трекере](https://github.com/openvk/openvk/projects/1). Вы также можете отправлять их через [вкладку "Помощь"](https://ovk.to/support?act=new) (для этого вам понадобится учетная запись OpenVK).

View file

@ -22,15 +22,10 @@ final class NotesPresenter extends OpenVKPresenter
if(!$user->getPrivacyPermission('notes.read', $this->user->identity ?? NULL)) if(!$user->getPrivacyPermission('notes.read', $this->user->identity ?? NULL))
$this->flashFail("err", tr("forbidden"), tr("forbidden_comment")); $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->count = $this->notes->getUserNotesCount($user);
$this->template->owner = $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 function renderView(int $owner, int $note_id): void

View file

@ -125,5 +125,6 @@ final class SearchPresenter extends OpenVKPresenter
]; ];
$this->template->extendedPaginatorConf = clone $this->template->paginatorConf; $this->template->extendedPaginatorConf = clone $this->template->paginatorConf;
$this->template->extendedPaginatorConf->space = 11; $this->template->extendedPaginatorConf->space = 11;
$this->template->paginatorConf->atTop = true;
} }
} }

View file

@ -82,7 +82,14 @@
{/if} {/if}
<div class="toTop"> <div class="toTop">
⬆ {_to_top} <div id='to_up'>
<svg id="to_up_icon" viewBox="0 0 10 6"><polygon points="0 6 5 0 10 6 0 6"/></svg>
<span>{_to_top}</span>
</div>
<div id='to_back'>
<svg id="to_back_icon" viewBox="0 0 10 6"><polygon points="0 0 5 6 10 0 0 0"/></svg>
</div>
</div> </div>
<div class="layout"> <div class="layout">

View file

@ -19,7 +19,7 @@
{ifset specpage} {ifset specpage}
{include specpage, x => $dat} {include specpage, x => $dat}
{else} {else}
<div class="container_gray"> <div class="container_gray {ifset noscroll}no_scroll_container{else}scroll_container{/ifset}">
{var $data = is_array($iterator) ? $iterator : iterator_to_array($iterator)} {var $data = is_array($iterator) ? $iterator : iterator_to_array($iterator)}
{ifset top} {ifset top}
@ -27,7 +27,7 @@
{/ifset} {/ifset}
{if sizeof($data) > 0} {if sizeof($data) > 0}
<div class="content" n:foreach="$data as $dat"> <div class="scroll_node content" n:foreach="$data as $dat">
<table> <table>
<tbody n:attr="id => is_null($table_body_id) ? NULL : $table_body_id"> <tbody n:attr="id => is_null($table_body_id) ? NULL : $table_body_id">
<tr> <tr>

View file

@ -385,8 +385,8 @@
<tr> <tr>
<td class="e"> <td class="e">
Vladimir Barinov (veselcraft), Celestora, Konstantin Kichulkin (kosfurler), Vladimir Barinov (veselcraft), Celestora, Konstantin Kichulkin (kosfurler),
Nikita Volkov (sup_ban), Daniel Myslivets, Maxim Leshchenko (maksales / maksalees) Daniel Myslivets, Maxim Leshchenko (maksales / maksalees), n1rwana and
and n1rwana Jillian Österreich (Lumaeris)
</td> </td>
</tr> </tr>
</tbody> </tbody>
@ -400,7 +400,7 @@
<tr> <tr>
<td class="e"> <td class="e">
Vladimir Barinov (veselcraft) and Konstantin Kichulkin (kosfurler)<br/> Vladimir Barinov (veselcraft) and Konstantin Kichulkin (kosfurler)<br/>
OpenVK is a free open source software that "cosplays" (or imitates) older versions of a Russian social network called VKontakte. VKontakte belongs to Pavel Durov and VK Group. OpenVK is a free open source software that "cosplays" (or imitates) older versions of a Russian social network called VKontakte. VKontakte belongs to VK (formerly Mail.ru Group).
</td> </td>
</tr> </tr>
</tbody> </tbody>
@ -447,7 +447,7 @@
</tr> </tr>
<tr> <tr>
<td class="e">Initial hosting</td> <td class="e">Initial hosting</td>
<td class="v">Lumaeris and Celestora</td> <td class="v">Jillian Österreich (Lumaeris) and Celestora</td>
</tr> </tr>
<tr> <tr>
<td class="e">Initial bug-tracker hosting</td> <td class="e">Initial bug-tracker hosting</td>
@ -459,7 +459,7 @@
</tr> </tr>
<tr> <tr>
<td class="e">Illustrations</td> <td class="e">Illustrations</td>
<td class="v">Ash Defenders, Polina Katunina (RousPhaul)</td> <td class="v">Ash Defenders, Polina Katunina (ktp0li)</td>
</tr> </tr>
<tr> <tr>
<td class="e">Best barmaid</td> <td class="e">Best barmaid</td>
@ -479,9 +479,9 @@
</tr> </tr>
<tr class="e"> <tr class="e">
<td> <td>
kovaltim, Vladimir Lapskiy (0x7d5), Alexander Minkin (WerySkok), Polina Katunina (RousPhaul), veth, kovaltim, Vladimir Lapskiy (0x7d5), Alexander Minkin (WerySkok), Polina Katunina (ktp0li), veth,
Egor Shevchenko, Vadim Korovin (yuni), Ash Defenders, Egor Shevchenko, Vadim Korovin (yuni), Ash Defenders,
Pavel Silaev, Dmitriy Daemon, Lumaeris, Pavel Silaev, Dmitriy Daemon, Jillian Österreich (Lumaeris),
cmed404 and unknown tester, who disappeared shortly after trying to upload post with cat. cmed404 and unknown tester, who disappeared shortly after trying to upload post with cat.
</td> </td>
</tr> </tr>

View file

@ -64,8 +64,8 @@
<div n:if="$audiosCount <= 0" style='height: 50%;'> <div n:if="$audiosCount <= 0" style='height: 50%;'>
{include "../components/content_error.xml", description => $ownerId > 0 ? ($ownerId == $thisUser->getId() ? tr("no_audios_thisuser") : tr("no_audios_user")) : tr("no_audios_club")} {include "../components/content_error.xml", description => $ownerId > 0 ? ($ownerId == $thisUser->getId() ? tr("no_audios_thisuser") : tr("no_audios_user")) : tr("no_audios_club")}
</div> </div>
<div n:if="$audiosCount > 0" class="infContainer"> <div n:if="$audiosCount > 0" class="scroll_container infContainer">
<div class="infObj" n:foreach="$audios as $audio"> <div class="scroll_node infObj" n:foreach="$audios as $audio">
{include "player.xml", audio => $audio, club => $club} {include "player.xml", audio => $audio, club => $club}
</div> </div>
</div> </div>
@ -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")} {include "../components/content_error.xml", description => $ownerId > 0 ? ($ownerId == $thisUser->getId() ? tr("no_playlists_thisuser") : tr("no_playlists_user")) : tr("no_playlists_club")}
</div> </div>
<div class="infContainer playlistContainer" n:if="$playlistsCount > 0"> <div class="scroll_container infContainer playlistContainer" n:if="$playlistsCount > 0">
{foreach $playlists as $playlist} <div class='scroll_node' n:foreach='$playlists as $playlist'>
{include 'playlistListView.xml', playlist => $playlist} {include 'playlistListView.xml', playlist => $playlist}
{/foreach} </div>
</div> </div>
<div> <div>

View file

@ -67,11 +67,11 @@
<hr style="color: #f7f7f7;"> <hr style="color: #f7f7f7;">
</div> </div>
</div> </div>
<div class="audiosContainer infContainer" style="margin-top: 14px;"> <div class="audiosContainer scroll_container infContainer" style="margin-top: 14px;">
{if $count < 1} {if $count < 1}
{_empty_playlist} {_empty_playlist}
{else} {else}
<div class="infObj" n:foreach="$audios as $audio"> <div class="scroll_node" n:foreach="$audios as $audio">
{include "player.xml", audio => $audio} {include "player.xml", audio => $audio}
</div> </div>

View file

@ -12,8 +12,8 @@
{/block} {/block}
{block content} {block content}
<div class="gift_grid"> <div class="gift_grid scroll_container">
<div n:foreach="$gifts as $gift" n:class="gift_sel, !$gift->canUse($thisUser) ? disabled" data-gift="{$gift->getId()}"> <div n:foreach="$gifts as $gift" n:class="scroll_node, gift_sel, !$gift->canUse($thisUser) ? disabled" data-gift="{$gift->getId()}">
<img class="gift_pic" src="{$gift->getImage(2)}" alt="{_gift}" loading=lazy /> <img class="gift_pic" src="{$gift->getImage(2)}" alt="{_gift}" loading=lazy />
<strong class="gift_price"> <strong class="gift_price">

View file

@ -12,9 +12,9 @@
{include "../components/error.xml", title => "", description => $type == "my" ? tr("no_suggested_posts_by_you") : tr("no_suggested_posts_by_people")} {include "../components/error.xml", title => "", description => $type == "my" ? tr("no_suggested_posts_by_you") : tr("no_suggested_posts_by_people")}
{else} {else}
<h4 id="cound">{if $type == "my"}{tr("suggested_posts_in_group_by_you", $count)}{else}{tr("suggested_posts_in_group", $count)}{/if}</h4> <h4 id="cound">{if $type == "my"}{tr("suggested_posts_in_group_by_you", $count)}{else}{tr("suggested_posts_in_group", $count)}{/if}</h4>
<div id="postz" class="infContainer"> <div id="postz" class="infContainer scroll_container">
{var $microblog = $thisUser->hasMicroblogEnabled()} {var $microblog = $thisUser->hasMicroblogEnabled()}
<div class="infObj" n:foreach="$posts as $post"> <div class="infObj scroll_node" n:foreach="$posts as $post">
{if $microblog} {if $microblog}
{include "../components/post/microblogpost.xml", post => $post, commentSection => false, suggestion => true, forceNoCommentsLink => true, forceNoPinLink => true, forceNoLike => true, forceNoShareLink => true, forceNoDeleteLink => false} {include "../components/post/microblogpost.xml", post => $post, commentSection => false, suggestion => true, forceNoCommentsLink => true, forceNoPinLink => true, forceNoLike => true, forceNoShareLink => true, forceNoDeleteLink => false}
{else} {else}

View file

@ -17,9 +17,9 @@
</div> </div>
{if sizeof($corresps) > 0} {if sizeof($corresps) > 0}
<div class="crp-list"> <div class="crp-list scroll_container">
<div n:foreach="$corresps as $coresp" <div n:foreach="$corresps as $coresp"
class="crp-entry" class="scroll_node crp-entry"
onmousedown="window.location.href = {$coresp->getURL()};" > onmousedown="window.location.href = {$coresp->getURL()};" >
{var $recipient = $coresp->getCorrespondents()[1]} {var $recipient = $coresp->getCorrespondents()[1]}
{var $lastMsg = $coresp->getPreviewMessage()} {var $lastMsg = $coresp->getPreviewMessage()}

View file

@ -1,6 +1,5 @@
{extends "../@listView.xml"} {extends "../@listView.xml"}
{var $iterator = iterator_to_array($notes)} {var $iterator = iterator_to_array($notes)}
{var $page = $paginatorConf->page}
{block title}{_notes}{/block} {block title}{_notes}{/block}
@ -60,12 +59,12 @@
} }
</style> </style>
<div class="container_gray" style="background: white; border-top: none;"> <div class="container_gray scroll_container" style="background: white; border-top: none;">
{var $data = is_array($iterator) ? $iterator : iterator_to_array($iterator)} {var $data = is_array($iterator) ? $iterator : iterator_to_array($iterator)}
{if sizeof($data) > 0} {if sizeof($data) > 0}
<div n:foreach="$data as $dat"> <div class='scroll_node' n:foreach="$data as $dat">
<div class="profile_thumb"> <div class="profile_thumb">
<a href="{$owner->getURL()}"> <a href="{$owner->getURL()}">
<img src="{$owner->getAvatarUrl('miniscule')}" style="width: 50px;"> <img src="{$owner->getAvatarUrl('miniscule')}" style="width: 50px;">
@ -107,6 +106,14 @@
</article> </article>
</div> </div>
{include "../components/paginator.xml", conf => (object) [
"page" => $page,
"count" => $count,
"amount" => sizeof($data),
"perPage" => 10,
"atBottom" => true,
]}
{else} {else}
{if isset($thisUser) && $thisUser->getId() == $owner->getId()} {if isset($thisUser) && $thisUser->getId() == $owner->getId()}

View file

@ -21,8 +21,8 @@
</div> </div>
{var $data = is_array($iterator) ? $iterator : iterator_to_array($iterator)} {var $data = is_array($iterator) ? $iterator : iterator_to_array($iterator)}
{if sizeof($data) > 0} {if sizeof($data) > 0}
<div> <div n:class="$mode !== 'new' ? scroll_container">
<table class="post post-divider" border="0" style="font-size: 11px;" n:foreach="$data as $dat"> <table class="scroll_node post post-divider" border="0" style="font-size: 11px;" n:foreach="$data as $dat">
<tbody> <tbody>
<tr> <tr>
{var $sxModel = $dat->getModel(1)} {var $sxModel = $dat->getModel(1)}

View file

@ -30,10 +30,10 @@
{/if} {/if}
<br/><br/> <br/><br/>
{if $album->getPhotosCount() > 0} {if $album->getPhotosCount() > 0}
<div class="container_gray album-flex"> <div class="container_gray scroll_container album-flex">
{foreach $photos as $photo} {foreach $photos as $photo}
{php if($photo->isDeleted()) continue; } {php if($photo->isDeleted()) continue; }
<div class="album-photo"> <div class="album-photo scroll_node">
<a <a
n:if="!is_null($thisUser) && $album->canBeModifiedBy($thisUser)" n:if="!is_null($thisUser) && $album->canBeModifiedBy($thisUser)"
href="/album{$album->getPrettyId()}/remove_photo/{$photo->getId()}" class="album-photo--delete"> href="/album{$album->getPrettyId()}/remove_photo/{$photo->getId()}" class="album-photo--delete">

View file

@ -29,10 +29,10 @@
</div> </div>
<div class='page_wrap_content' id='search_page'> <div class='page_wrap_content' id='search_page'>
<div n:class='page_wrap_content_main, $section == "audios" && $count > 0 ? audios_padding'> <div n:class='page_wrap_content_main, $section != "posts" ? scroll_container, $section == "audios" && $count > 0 ? audios_padding'>
{if $count > 0} {if $count > 0}
{if $section === 'users'} {if $section === 'users'}
<div class='search_content content def_row_content' n:foreach="$data as $dat"> <div class='scroll_node search_content content def_row_content' n:foreach="$data as $dat">
<table> <table>
<tbody> <tbody>
<tr> <tr>
@ -125,10 +125,14 @@
</div> </div>
<script n:if='$count > 0 && !empty($query)'> <script n:if='$count > 0 && !empty($query)'>
function __scrollHook(page) {
highlightText({$query}, '.page_wrap_content_main', ['text']) highlightText({$query}, '.page_wrap_content_main', ['text'])
}
__scrollHook()
</script> </script>
{elseif $section === 'groups'} {elseif $section === 'groups'}
<div class='search_content content def_row_content' n:foreach="$data as $dat"> <div class='scroll_node search_content content def_row_content' n:foreach="$data as $dat">
<table> <table>
<tbody> <tbody>
<tr> <tr>
@ -180,10 +184,14 @@
</div> </div>
<script n:if='$count > 0 && !empty($query)'> <script n:if='$count > 0 && !empty($query)'>
function __scrollHook(page) {
highlightText({$query}, '.page_wrap_content_main', ['text', "td[data-highlight='_clubDesc']"]) highlightText({$query}, '.page_wrap_content_main', ['text', "td[data-highlight='_clubDesc']"])
}
__scrollHook()
</script> </script>
{elseif $section === 'apps'} {elseif $section === 'apps'}
<div class='search_content content def_row_content' n:foreach="$data as $dat"> <div class='scroll_node search_content content def_row_content' n:foreach="$data as $dat">
<table> <table>
<tbody> <tbody>
<tr> <tr>
@ -210,10 +218,14 @@
</div> </div>
<script n:if='$count > 0 && !empty($query)'> <script n:if='$count > 0 && !empty($query)'>
function __scrollHook(page) {
highlightText({$query}, '.page_wrap_content_main', ['text', "span[data-highlight='_appDesc']"]) highlightText({$query}, '.page_wrap_content_main', ['text', "span[data-highlight='_appDesc']"])
}
__scrollHook()
</script> </script>
{elseif $section === 'posts'} {elseif $section === 'posts'}
<div class='search_content' n:foreach="$data as $dat"> <div class='scroll_node search_content' n:foreach="$data as $dat">
{if !$dat || $dat->getWallOwner()->isHideFromGlobalFeedEnabled()} {if !$dat || $dat->getWallOwner()->isHideFromGlobalFeedEnabled()}
{_closed_group_post}. {_closed_group_post}.
{else} {else}
@ -222,31 +234,47 @@
</div> </div>
<script n:if='$count > 0 && !empty($query)'> <script n:if='$count > 0 && !empty($query)'>
function __scrollHook(page) {
highlightText({$query}, '.page_wrap_content_main', [".post:not(.comment) > tbody > tr > td > .post-content > .text .really_text"]) highlightText({$query}, '.page_wrap_content_main', [".post:not(.comment) > tbody > tr > td > .post-content > .text .really_text"])
}
__scrollHook()
</script> </script>
{elseif $section === 'videos'} {elseif $section === 'videos'}
<div class='search_content' n:foreach="$data as $dat"> <div class='scroll_node search_content' n:foreach="$data as $dat">
{include "../components/video.xml", video => $dat} {include "../components/video.xml", video => $dat}
</div> </div>
<script n:if='$count > 0 && !empty($query)'> <script n:if='$count > 0 && !empty($query)'>
function __scrollHook(page) {
highlightText({$query}, '.page_wrap_content_main', [".video_name", ".video_description"]) highlightText({$query}, '.page_wrap_content_main', [".video_name", ".video_description"])
}
__scrollHook()
</script> </script>
{elseif $section === 'audios'} {elseif $section === 'audios'}
<div class='search_content' n:foreach="$data as $dat"> <div class='scroll_node search_content' n:foreach="$data as $dat">
{include "../Audio/player.xml", audio => $dat} {include "../Audio/player.xml", audio => $dat}
</div> </div>
<script n:if="$count > 0 && !empty($query) && empty($_REQUEST['only_performers'])"> <script n:if="$count > 0 && !empty($query) && empty($_REQUEST['only_performers'])">
function __scrollHook(page) {
highlightText({$query}, '.page_wrap_content_main', [".mediaInfo .performer a", ".mediaInfo .title"]) highlightText({$query}, '.page_wrap_content_main', [".mediaInfo .performer a", ".mediaInfo .title"])
}
__scrollHook()
</script> </script>
{elseif $section === 'audios_playlists'} {elseif $section === 'audios_playlists'}
<div class='search_content' n:foreach="$data as $dat"> <div class='scroll_node search_content' n:foreach="$data as $dat">
{include "../Audio/playlistListView.xml", playlist => $dat} {include "../Audio/playlistListView.xml", playlist => $dat}
</div> </div>
<script n:if="$count > 0 && !empty($query) && empty($_REQUEST['only_performers'])"> <script n:if="$count > 0 && !empty($query) && empty($_REQUEST['only_performers'])">
function __scrollHook(page) {
highlightText({$query}, '.page_wrap_content_main', [".playlistName", ".playlistDesc"]) highlightText({$query}, '.page_wrap_content_main', [".playlistName", ".playlistDesc"])
}
__scrollHook()
</script> </script>
{/if} {/if}
{else} {else}

View file

@ -2,6 +2,7 @@
{var $iterator = $user->getClubs($page, $admin)} {var $iterator = $user->getClubs($page, $admin)}
{var $count = $user->getClubCount($admin)} {var $count = $user->getClubCount($admin)}
{block noscroll}{/block}
{block title} {block title}
{_groups} {_groups}
{/block} {/block}

View file

@ -9,9 +9,11 @@
</div> </div>
{if sizeof($comments) > 0} {if sizeof($comments) > 0}
{foreach $comments as $comment} <div class='scroll_container'>
<div class='scroll_node' n:foreach="$comments as $comment">
{include "comment.xml", comment => $comment} {include "comment.xml", comment => $comment}
{/foreach} </div>
</div>
<div style="margin-top: 11px;"> <div style="margin-top: 11px;">
{include "paginator.xml", conf => (object) ["page" => $page, "count" => $count, "amount" => sizeof($comments), "perPage" => 10]} {include "paginator.xml", conf => (object) ["page" => $page, "count" => $count, "amount" => sizeof($comments), "perPage" => 10]}
</div> </div>

View file

@ -2,7 +2,7 @@
{var $pageCount = ceil($conf->count / $conf->perPage)} {var $pageCount = ceil($conf->count / $conf->perPage)}
<div n:if="!($conf->page === 1 && $conf->count <= $conf->perPage)" n:attr="style => (!$conf->tidy ? 'padding: 8px;')"> <div n:if="!($conf->page === 1 && $conf->count <= $conf->perPage)" n:attr="style => (!$conf->tidy ? 'padding: 8px;')">
<div n:class="paginator, ($conf->atBottom ?? false) ? paginator-at-bottom, ($conf->tidy ? 'tidy')"> <div n:class="paginator, (($conf->atTop || $atTop) ?? false) ? paginator-at-top, ($conf->atBottom ?? false) ? paginator-at-bottom, ($conf->tidy ? 'tidy')">
<a n:if="$conf->page > $space" n:attr="class => ($conf->page === 1 ? 'active')" href="?{http_build_query(array_merge($_GET, ['p' => 1]), 'k', '&', PHP_QUERY_RFC3986)}">&laquo;</a> <a n:if="$conf->page > $space" n:attr="class => ($conf->page === 1 ? 'active')" href="?{http_build_query(array_merge($_GET, ['p' => 1]), 'k', '&', PHP_QUERY_RFC3986)}">&laquo;</a>
{for $j = $conf->page - ($space-1); $j <= $conf->page + ($space-1); $j++} {for $j = $conf->page - ($space-1); $j <= $conf->page + ($space-1); $j++}
<a n:if="$j > 0 && $j <= $pageCount" n:attr="class => ($conf->page === $j ? 'active')" href="?{http_build_query(array_merge($_GET, ['p' => $j]), 'k', '&', PHP_QUERY_RFC3986)}">{$j}</a> <a n:if="$j > 0 && $j <= $pageCount" n:attr="class => ($conf->page === $j ? 'active')" href="?{http_build_query(array_merge($_GET, ['p' => $j]), 'k', '&', PHP_QUERY_RFC3986)}">{$j}</a>

View file

@ -1391,7 +1391,7 @@ textarea {
.toTop { .toTop {
position: fixed; position: fixed;
padding: 20px; padding: 12px;
width: 100px; width: 100px;
height: 100%; height: 100%;
background-color: #f3f3f3; background-color: #f3f3f3;
@ -1401,9 +1401,34 @@ textarea {
opacity: 0; opacity: 0;
transition: .1s all; transition: .1s all;
z-index: 129; 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; opacity: .5;
cursor: pointer; cursor: pointer;
} }

View file

@ -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 comment = u(e.target).closest(".post");
let authorId = comment.data("owner-id"); let authorId = comment.data("owner-id");
let authorNm = u(".post-author > a > b", comment.first()).text().trim(); let authorNm = u(".post-author > a > b", comment.first()).text().trim();

View file

@ -641,6 +641,35 @@ class bigPlayer {
duration: this.tracks["currentTrack"].length 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() { document.addEventListener("DOMContentLoaded", function() {

View file

@ -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() e.preventDefault()
ky(e.currentTarget.href, { ky(e.currentTarget.href, {
@ -228,4 +228,4 @@ $(document).on("click", "#postz .paginator a", (e) => {
] ]
} }
}) })
}) })*/

View file

@ -1644,6 +1644,79 @@ $(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)
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)
// fffffuck
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(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)
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) => { u(document).on('click', '#__sourceAttacher', (e) => {
MessageBox(tr('add_source'), ` MessageBox(tr('add_source'), `
<div id='source_flex_kunteynir'> <div id='source_flex_kunteynir'>

View file

@ -90,7 +90,7 @@ document.addEventListener("DOMContentLoaded", function() { //BEGIN
}); });
/* @rem-pai why this func wasn't named as "#_deleteDialog"? It looks universal IMO */ /* @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 = "<form id='tmpPhDelF' action='" + u(this).attr("href") + "' >"; var formHtml = "<form id='tmpPhDelF' action='" + u(this).attr("href") + "' >";
formHtml += "<input type='hidden' name='hash' value='" + u("meta[name=csrf]").attr("value") + "' />"; formHtml += "<input type='hidden' name='hash' value='" + u("meta[name=csrf]").attr("value") + "' />";
formHtml += "</form>"; formHtml += "</form>";
@ -167,7 +167,7 @@ document.addEventListener("DOMContentLoaded", function() { //BEGIN
return false; 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('loading');
u(this).nodes[0].parentElement.classList.add('disable'); u(this).nodes[0].parentElement.classList.add('disable');
console.log(e.target); console.log(e.target);
@ -518,7 +518,7 @@ function highlightText(searchText, container_selector, selectors = []) {
node.parentNode.insertBefore(tempDiv.firstChild, node) node.parentNode.insertBefore(tempDiv.firstChild, node)
} }
node.parentNode.removeChild(node) node.parentNode.removeChild(node)
} else if(node.nodeType === 1 && node.tagName !== 'SCRIPT' && node.tagName !== 'BR' && node.tagName !== 'STYLE') { } else if(node.nodeType === 1 && node.tagName !== 'SCRIPT' && node.tagName !== 'BR' && node.tagName !== 'STYLE' && !node.classList.contains('highlight')) {
Array.from(node.childNodes).forEach(highlightNode); Array.from(node.childNodes).forEach(highlightNode);
} }
} }

View file

@ -1,14 +1,35 @@
window.addEventListener("scroll", function(e) { window.addEventListener("scroll", function(e) {
if(window.scrollY < 100) { if(window.scrollY < 100) {
if(window.temp_y_scroll) {
u('.toTop').addClass('has_down')
}
document.body.classList.toggle("scrolled", false); document.body.classList.toggle("scrolled", false);
} else { } else {
document.body.classList.toggle("scrolled", true); document.body.classList.toggle("scrolled", true);
u('.toTop').removeClass('has_down')
} }
}); });
u(".toTop").on("click", function(e) { u(".toTop").on("click", function(e) {
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({ window.scrollTo({
top: 0, top: 0,
behavior: "smooth" 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')
})