search: a bit refactor

This commit is contained in:
mrilyew 2024-10-18 22:29:40 +03:00
parent b3e57147b7
commit 8286173ed3
43 changed files with 1460 additions and 1329 deletions

View file

@ -1,76 +0,0 @@
<?php declare(strict_types=1);
namespace openvk\ServiceAPI;
use openvk\Web\Models\Entities\{User, Club};
use openvk\Web\Models\Repositories\{Users, Clubs, Videos};
use Chandler\Database\DatabaseConnection;
class Search implements Handler
{
protected $user;
private $users;
private $clubs;
private $videos;
function __construct(?User $user)
{
$this->user = $user;
$this->users = new Users;
$this->clubs = new Clubs;
$this->videos = new Videos;
}
function fastSearch(string $query, string $type = "users", callable $resolve, callable $reject)
{
if($query == "" || strlen($query) < 3)
$reject(12, "No input or input < 3");
$repo;
$sort;
switch($type) {
default:
case "users":
$repo = (new Users);
$sort = "rating DESC";
break;
case "groups":
$repo = (new Clubs);
$sort = "id ASC";
break;
case "videos":
$repo = (new Videos);
$sort = "created ASC";
break;
}
$res = $repo->find($query, ["doNotSearchMe" => $this->user->getId(), "doNotSearchPrivate" => true,], $sort);
$results = array_slice(iterator_to_array($res), 0, 5);
$count = sizeof($results);
$arr = [
"count" => $count,
"items" => []
];
if(sizeof($results) < 1) {
$reject(2, "No results");
}
foreach($results as $res) {
$arr["items"][] = [
"id" => $res->getId(),
"name" => $type == "users" ? $res->getCanonicalName() : $res->getName(),
"avatar" => $type != "videos" ? $res->getAvatarUrl() : $res->getThumbnailURL(),
"url" => $type != "videos" ? $res->getUrl() : "/video".$res->getPrettyId(),
"description" => ovk_proc_strtr($res->getDescription() ?? "...", 40)
];
}
$resolve($arr);
}
}

View file

@ -252,7 +252,7 @@ final class Groups extends VKAPIRequestHandler
return $response; return $response;
} }
function search(string $q, int $offset = 0, int $count = 100) function search(string $q, int $offset = 0, int $count = 100, string $fields = "screen_name,is_admin,is_member,is_advertiser,photo_50,photo_100,photo_200")
{ {
$clubs = new ClubsRepo; $clubs = new ClubsRepo;
@ -264,11 +264,7 @@ final class Groups extends VKAPIRequestHandler
return (object) [ return (object) [
"count" => $find->size(), "count" => $find->size(),
"items" => $this->getById(implode(',', $array), "", "is_admin,is_member,is_advertiser,photo_50,photo_100,photo_200", $offset, $count) "items" => $this->getById(implode(',', $array), "", $fields, $offset, $count)
/*
* As there is no thing as "fields" by the original documentation
* i'll just bake this param by the example shown here: https://dev.vk.com/method/groups.search
*/
]; ];
} }

View file

@ -263,6 +263,9 @@ final class Users extends VKAPIRequestHandler
case 'is_dead': case 'is_dead':
$response[$i]->is_dead = $usr->isDead(); $response[$i]->is_dead = $usr->isDead();
break; break;
case 'nickname':
$response[$i]->nickname = $usr->getPseudo();
break;
} }
} }
@ -314,89 +317,79 @@ final class Users extends VKAPIRequestHandler
int $count = 100, int $count = 100,
string $city = "", string $city = "",
string $hometown = "", string $hometown = "",
int $sex = 2, int $sex = 3,
int $status = 0, # это про marital status int $status = 0, # marital_status
bool $online = false, bool $online = false,
# дальше идут параметры которых нету в vkapi но есть на сайте # non standart params:
string $profileStatus = "", # а это уже нормальный статус
int $sort = 0, int $sort = 0,
int $before = 0, int $polit_views = 0,
int $politViews = 0,
int $after = 0,
string $interests = "",
string $fav_music = "", string $fav_music = "",
string $fav_films = "", string $fav_films = "",
string $fav_shows = "", string $fav_shows = "",
string $fav_books = "", string $fav_books = ""
string $fav_quotes = ""
) )
{ {
$users = new UsersRepo; $users = new UsersRepo;
$output_sort = ['type' => 'id', 'invert' => false];
$sortg = "id ASC"; $output_params = [
"ignore_private" => true,
$nfilds = $fields;
switch($sort) {
case 0:
$sortg = "id DESC";
break;
case 1:
$sortg = "id ASC";
break;
case 2:
$sortg = "first_name DESC";
break;
case 3:
$sortg = "first_name ASC";
break;
case 4:
$sortg = "rating DESC";
if(!str_contains($nfilds, "rating")) {
$nfilds .= "rating";
}
break;
case 5:
$sortg = "rating DESC";
if(!str_contains($nfilds, "rating")) {
$nfilds .= "rating";
}
break;
}
$array = [];
$parameters = [
"city" => !empty($city) ? $city : NULL,
"hometown" => !empty($hometown) ? $hometown : NULL,
"gender" => $sex < 2 ? $sex : NULL,
"maritalstatus" => (bool)$status ? $status : NULL,
"politViews" => (bool)$politViews ? $politViews : NULL,
"is_online" => $online ? 1 : NULL,
"status" => !empty($profileStatus) ? $profileStatus : NULL,
"before" => $before != 0 ? $before : NULL,
"after" => $after != 0 ? $after : NULL,
"interests" => !empty($interests) ? $interests : NULL,
"fav_music" => !empty($fav_music) ? $fav_music : NULL,
"fav_films" => !empty($fav_films) ? $fav_films : NULL,
"fav_shows" => !empty($fav_shows) ? $fav_shows : NULL,
"fav_books" => !empty($fav_books) ? $fav_books : NULL,
"fav_quotes" => !empty($fav_quotes) ? $fav_quotes : NULL,
"doNotSearchPrivate" => true,
]; ];
$find = $users->find($q, $parameters, $sortg); switch($sort) {
default:
case 0:
$output_sort = ['type' => 'id', 'invert' => false];
break;
case 1:
$output_sort = ['type' => 'id', 'invert' => true];
break;
case 4:
$output_sort = ['type' => 'rating', 'invert' => false];
break;
}
if(!empty($city))
$output_params['city'] = $city;
if(!empty($hometown))
$output_params['hometown'] = $hometown;
if($sex != 3)
$output_params['gender'] = $sex;
if($status != 0)
$output_params['marital_status'] = $status;
if($polit_views != 0)
$output_params['polit_views'] = $polit_views;
if(!empty($interests))
$output_params['interests'] = $interests;
if(!empty($fav_music))
$output_params['fav_music'] = $fav_music;
if(!empty($fav_films))
$output_params['fav_films'] = $fav_films;
if(!empty($fav_shows))
$output_params['fav_shows'] = $fav_shows;
if(!empty($fav_books))
$output_params['fav_books'] = $fav_books;
if($online)
$output_params['is_online'] = 1;
$array = [];
$find = $users->find($q, $output_params, $output_sort);
foreach ($find as $user) foreach ($find as $user)
$array[] = $user->getId(); $array[] = $user->getId();
return (object) [ return (object) [
"count" => $find->size(), "count" => $find->size(),
"items" => $this->get(implode(',', $array), $nfilds, $offset, $count) "items" => $this->get(implode(',', $array), $fields, $offset, $count)
]; ];
} }

View file

@ -60,4 +60,60 @@ final class Video extends VKAPIRequestHandler
]; ];
} }
} }
function search(string $q = '', int $sort = 0, int $offset = 0, int $count = 10, bool $extended = false, string $fields = ''): object
{
$this->requireUser();
$params = [];
$db_sort = ['type' => 'id', 'invert' => false];
$videos = (new VideosRepo)->find($q, $params, $db_sort);
$items = iterator_to_array($videos->offsetLimit($offset, $count));
$count = $videos->size();
$return_items = [];
$profiles = [];
$groups = [];
foreach($items as $item)
$return_item = $item->getApiStructure($this->getUser());
$return_item = $return_item->video;
$return_items[] = $return_item;
if($return_item['owner_id']) {
if($return_item['owner_id'] > 0)
$profiles[] = $return_item['owner_id'];
else
$groups[] = abs($return_item['owner_id']);
}
if($extended) {
$profiles = array_unique($profiles);
$groups = array_unique($groups);
$profilesFormatted = [];
$groupsFormatted = [];
foreach($profiles as $prof) {
$profile = (new UsersRepo)->get($prof);
$profilesFormatted[] = $profile->toVkApiStruct($this->getUser(), $fields);
}
foreach($groups as $gr) {
$group = (new ClubsRepo)->get($gr);
$groupsFormatted[] = $group->toVkApiStruct($this->getUser(), $fields);
}
return (object) [
"count" => $count,
"items" => $return_items,
"profiles" => $profilesFormatted,
"groups" => $groupsFormatted,
];
}
return (object) [
"count" => $count,
"items" => $return_items,
];
}
} }

View file

@ -437,7 +437,7 @@ class Club extends RowModel
return (new \openvk\Web\Models\Repositories\Audios)->getClubCollectionSize($this); return (new \openvk\Web\Models\Repositories\Audios)->getClubCollectionSize($this);
} }
function toVkApiStruct(?User $user = NULL): object function toVkApiStruct(?User $user = NULL, string $fields = ''): object
{ {
$res = (object) []; $res = (object) [];

View file

@ -140,4 +140,31 @@ class Comment extends Post
return $user->getId() == $this->getOwner(false)->getId(); return $user->getId() == $this->getOwner(false)->getId();
} }
function getTargetURL(): string
{
$target = $this->getTarget();
$target_name = 'wall';
if(!$target) {
return '/404';
}
switch(get_class($target)) {
case 'openvk\Web\Models\Entities\Note':
$target_name = 'note';
break;
case 'openvk\Web\Models\Entities\Photo':
$target_name = 'photo';
break;
case 'openvk\Web\Models\Entities\Video':
$target_name = 'video';
break;
case 'openvk\Web\Models\Entities\Topic':
$target_name = 'topic';
break;
}
return $target_name . $target->getPrettyId();
}
} }

View file

@ -200,6 +200,11 @@ class Playlist extends MediaCollection
return $this->getRecord()->cover_photo_id; return $this->getRecord()->cover_photo_id;
} }
function getCoverPhoto(): ?Photo
{
return (new Photos)->get((int) $this->getRecord()->cover_photo_id);
}
function canBeModifiedBy(User $user): bool function canBeModifiedBy(User $user): bool
{ {
if(!$user) if(!$user)

View file

@ -1331,7 +1331,7 @@ class User extends RowModel
return $this->getId(); return $this->getId();
} }
function toVkApiStruct(?User $user = NULL): object function toVkApiStruct(?User $user = NULL, string $fields = ''): object
{ {
$res = (object) []; $res = (object) [];
@ -1349,8 +1349,16 @@ class User extends RowModel
if(!is_null($user)) if(!is_null($user))
$res->can_access_closed = (bool)$this->canBeViewedBy($user); $res->can_access_closed = (bool)$this->canBeViewedBy($user);
if($user->isDead()) if(!is_array($fields))
$res->is_dead = 1; $fields = explode(',', $fields);
foreach($fields as $field) {
switch($field) {
case 'is_dead':
$res->is_dead = $user->isDead();
break;
}
}
return $res; return $res;
} }

View file

@ -181,8 +181,8 @@ class Video extends Media
{ {
if(preg_match(file_get_contents(__DIR__ . "/../VideoDrivers/regex/youtube.txt"), $link, $matches)) { if(preg_match(file_get_contents(__DIR__ . "/../VideoDrivers/regex/youtube.txt"), $link, $matches)) {
$pointer = "YouTube:$matches[1]"; $pointer = "YouTube:$matches[1]";
} else if(preg_match(file_get_contents(__DIR__ . "/../VideoDrivers/regex/vimeo.txt"), $link, $matches)) { /*} else if(preg_match(file_get_contents(__DIR__ . "/../VideoDrivers/regex/vimeo.txt"), $link, $matches)) {
$pointer = "Vimeo:$matches[1]"; $pointer = "Vimeo:$matches[1]";*/
} else { } else {
throw new ISE("Invalid link"); throw new ISE("Invalid link");
} }

View file

@ -67,11 +67,20 @@ class Applications
return sizeof($this->appRels->where("user", $user->getId())); return sizeof($this->appRels->where("user", $user->getId()));
} }
function find(string $query, array $pars = [], string $sort = "id"): Util\EntityStream function find(string $query = "", array $params = [], array $order = ['type' => 'id', 'invert' => false]): Util\EntityStream
{ {
$query = "%$query%"; $result = $this->apps->where("CONCAT_WS(' ', name, description) LIKE ?", "%$query%")->where("enabled", 1);
$result = $this->apps->where("CONCAT_WS(' ', name, description) LIKE ?", $query)->where("enabled", 1); $order_str = 'id';
return new Util\EntityStream("Application", $result->order("$sort")); switch($order['type']) {
case 'id':
$order_str = 'id ' . ($order['invert'] ? 'ASC' : 'DESC');
break;
}
if($order_str)
$result->order($order_str);
return new Util\EntityStream("Application", $result);
} }
} }

View file

@ -208,7 +208,7 @@ class Audios
$search = $this->audios->where([ $search = $this->audios->where([
"unlisted" => 0, "unlisted" => 0,
"deleted" => 0, "deleted" => 0,
])->where("MATCH ($columns) AGAINST (? WITH QUERY EXPANSION)", $query)->order($order); ])->where("MATCH ($columns) AGAINST (? IN BOOLEAN MODE)", "%$query%")->order($order);
if($withLyrics) if($withLyrics)
$search = $search->where("lyrics IS NOT NULL"); $search = $search->where("lyrics IS NOT NULL");
@ -243,32 +243,35 @@ class Audios
])->fetch()); ])->fetch());
} }
function find(string $query, array $pars = [], string $sort = "id DESC", int $page = 1, ?int $perPage = NULL): \Traversable function find(string $query, array $params = [], array $order = ['type' => 'id', 'invert' => false], int $page = 1, ?int $perPage = NULL): \Traversable
{ {
$query = "%$query%";
$result = $this->audios->where([ $result = $this->audios->where([
"unlisted" => 0, "unlisted" => 0,
"deleted" => 0, "deleted" => 0,
]); ]);
$order_str = 'id';
$notNullParams = []; switch($order['type']) {
case 'id':
foreach($pars as $paramName => $paramValue) $order_str = 'id ' . ($order['invert'] ? 'ASC' : 'DESC');
if($paramName != "before" && $paramName != "after" && $paramName != "only_performers") break;
$paramValue != NULL ? $notNullParams+=["$paramName" => "%$paramValue%"] : NULL; case 'length':
else $order_str = 'length ' . ($order['invert'] ? 'ASC' : 'DESC');
$paramValue != NULL ? $notNullParams+=["$paramName" => "$paramValue"] : NULL; break;
case 'listens':
$nnparamsCount = sizeof($notNullParams); $order_str = 'listens ' . ($order['invert'] ? 'ASC' : 'DESC');
break;
if($notNullParams["only_performers"] == "1") {
$result->where("performer LIKE ?", $query);
} else {
$result->where("name LIKE ? OR performer LIKE ?", $query, $query);
} }
if($nnparamsCount > 0) { if($params["only_performers"] == "1") {
foreach($notNullParams as $paramName => $paramValue) { $result->where("performer LIKE ?", "%$query%");
} else {
$result->where("name LIKE ? OR performer LIKE ?", "%$query%", "%$query%");
}
foreach($params as $paramName => $paramValue) {
if(is_null($paramValue) || $paramValue == '') continue;
switch($paramName) { switch($paramName) {
case "before": case "before":
$result->where("created < ?", $paramValue); $result->where("created < ?", $paramValue);
@ -279,17 +282,23 @@ class Audios
case "with_lyrics": case "with_lyrics":
$result->where("lyrics IS NOT NULL"); $result->where("lyrics IS NOT NULL");
break; break;
} case 'genre':
if($paramValue == 'any') break;
$result->where("genre", $paramValue);
break;
} }
} }
return new Util\EntityStream("Audio", $result->order($sort)); if($order_str)
$result->order($order_str);
return new Util\EntityStream("Audio", $result);
} }
function findPlaylists(string $query, int $page = 1, ?int $perPage = NULL): \Traversable function findPlaylists(string $query, int $page = 1, ?int $perPage = NULL): \Traversable
{ {
$query = "%$query%"; $result = $this->playlists->where("name LIKE ?", "%$query%");
$result = $this->playlists->where("name LIKE ?", $query);
return new Util\EntityStream("Playlist", $result); return new Util\EntityStream("Playlist", $result);
} }

View file

@ -43,12 +43,23 @@ class Clubs
return $this->toClub($this->clubs->get($id)); return $this->toClub($this->clubs->get($id));
} }
function find(string $query, array $pars = [], string $sort = "id DESC", int $page = 1, ?int $perPage = NULL): \Traversable function find(string $query, array $params = [], array $order = ['type' => 'id', 'invert' => false], int $page = 1, ?int $perPage = NULL): \Traversable
{ {
$query = "%$query%"; $result = $this->clubs;
$result = $this->clubs->where("name LIKE ? OR about LIKE ?", $query, $query); $order_str = 'id';
return new Util\EntityStream("Club", $result->order($sort)); switch($order['type']) {
case 'id':
$order_str = 'id ' . ($order['invert'] ? 'ASC' : 'DESC');
break;
}
$result = $result->where("name LIKE ? OR about LIKE ?", "%$query%", "%$query%");
if($order_str)
$result->order($order_str);
return new Util\EntityStream("Club", $result);
} }
function getCount(): int function getCount(): int

View file

@ -60,23 +60,18 @@ class Comments
])); ]));
} }
function find(string $query = "", array $pars = [], string $sort = "id"): Util\EntityStream function find(string $query, array $params = [], array $order = ['type' => 'id', 'invert' => false]): Util\EntityStream
{ {
$query = "%$query%"; $result = $this->comments->where("content LIKE ?", "%$query%")->where("deleted", 0);
$order_str = 'id';
$notNullParams = []; switch($order['type']) {
case 'id':
$order_str = 'created ' . ($order['invert'] ? 'ASC' : 'DESC');
break;
}
foreach($pars as $paramName => $paramValue) foreach($params as $paramName => $paramValue) {
if($paramName != "before" && $paramName != "after")
$paramValue != NULL ? $notNullParams+=["$paramName" => "%$paramValue%"] : NULL;
else
$paramValue != NULL ? $notNullParams+=["$paramName" => "$paramValue"] : NULL;
$result = $this->comments->where("content LIKE ?", $query)->where("deleted", 0);
$nnparamsCount = sizeof($notNullParams);
if($nnparamsCount > 0) {
foreach($notNullParams as $paramName => $paramValue) {
switch($paramName) { switch($paramName) {
case "before": case "before":
$result->where("created < ?", $paramValue); $result->where("created < ?", $paramValue);
@ -86,8 +81,10 @@ class Comments
break; break;
} }
} }
}
return new Util\EntityStream("Comment", $result->order("$sort")); if($order_str)
$result->order($order_str);
return new Util\EntityStream("Comment", $result);
} }
} }

View file

@ -154,23 +154,20 @@ class Posts
} }
function find(string $query = "", array $pars = [], string $sort = "id"): Util\EntityStream function find(string $query = "", array $params = [], array $order = ['type' => 'id', 'invert' => false]): Util\EntityStream
{ {
$query = "%$query%"; $result = $this->posts->where("content LIKE ?", "%$query%")->where("deleted", 0)->where("suggested", 0);
$order_str = 'id';
$notNullParams = []; switch($order['type']) {
case 'id':
$order_str = 'created ' . ($order['invert'] ? 'ASC' : 'DESC');
break;
}
foreach($pars as $paramName => $paramValue) foreach($params as $paramName => $paramValue) {
if($paramName != "before" && $paramName != "after") if(is_null($paramValue) || $paramValue == '') continue;
$paramValue != NULL ? $notNullParams+=["$paramName" => "%$paramValue%"] : NULL;
else
$paramValue != NULL ? $notNullParams+=["$paramName" => "$paramValue"] : NULL;
$result = $this->posts->where("content LIKE ?", $query)->where("deleted", 0)->where("suggested", 0);
$nnparamsCount = sizeof($notNullParams);
if($nnparamsCount > 0) {
foreach($notNullParams as $paramName => $paramValue) {
switch($paramName) { switch($paramName) {
case "before": case "before":
$result->where("created < ?", $paramValue); $result->where("created < ?", $paramValue);
@ -178,12 +175,22 @@ class Posts
case "after": case "after":
$result->where("created > ?", $paramValue); $result->where("created > ?", $paramValue);
break; break;
} /*case 'die_in_agony':
$result->where("nsfw", 1);
break;
case 'ads':
$result->where("ad", 1);
break;*/
case 'from_me':
$result->where("owner", $paramValue);
break;
} }
} }
if($order_str)
$result->order($order_str);
return new Util\EntityStream("Post", $result->order("$sort")); return new Util\EntityStream("Post", $result);
} }
function getPostCountOnUserWall(int $user): int function getPostCountOnUserWall(int $user): int

View file

@ -54,72 +54,51 @@ class Users
return $user ? $this->getByChandlerUserId($user->getId()) : NULL; return $user ? $this->getByChandlerUserId($user->getId()) : NULL;
} }
function find(string $query, array $pars = [], string $sort = "id DESC"): Util\EntityStream function find(string $query, array $params = [], array $order = ['type' => 'id', 'invert' => false]): Util\EntityStream
{ {
$query = "%$query%"; $result = $this->users->where("CONCAT_WS(' ', first_name, last_name, pseudo, shortcode) LIKE ?", "%$query%")->where("deleted", 0);
$result = $this->users->where("CONCAT_WS(' ', first_name, last_name, pseudo, shortcode) LIKE ?", $query)->where("deleted", 0); $order_str = 'id';
$notNullParams = []; switch($order['type']) {
$nnparamsCount = 0; case 'id':
case 'reg_date':
$order_str = 'since ' . ($order['invert'] ? 'ASC' : 'DESC');
break;
case 'rating':
$order_str = 'rating DESC';
break;
}
foreach($pars as $paramName => $paramValue) foreach($params as $paramName => $paramValue) {
if($paramName != "before" && $paramName != "after" && $paramName != "gender" && $paramName != "maritalstatus" && $paramName != "politViews" && $paramName != "doNotSearchMe") if(is_null($paramValue) || $paramValue == '') continue;
$paramValue != NULL ? $notNullParams += ["$paramName" => "%$paramValue%"] : NULL;
else
$paramValue != NULL ? $notNullParams += ["$paramName" => "$paramValue"] : NULL;
$nnparamsCount = sizeof($notNullParams);
if($nnparamsCount > 0) {
foreach($notNullParams as $paramName => $paramValue) {
switch($paramName) { switch($paramName) {
case "hometown": case "hometown":
$result->where("hometown LIKE ?", $paramValue); $result->where("hometown LIKE ?", "%$paramValue%");
break; break;
case "city": case "city":
$result->where("city LIKE ?", $paramValue); $result->where("city LIKE ?", "%$paramValue%");
break; break;
case "maritalstatus": case "marital_status":
$result->where("marital_status ?", $paramValue); $result->where("marital_status ?", $paramValue);
break; break;
case "status": case "polit_views":
$result->where("status LIKE ?", $paramValue);
break;
case "politViews":
$result->where("polit_views ?", $paramValue); $result->where("polit_views ?", $paramValue);
break; break;
case "email":
$result->where("email_contact LIKE ?", $paramValue);
break;
case "telegram":
$result->where("telegram LIKE ?", $paramValue);
break;
case "site":
$result->where("telegram LIKE ?", $paramValue);
break;
case "address":
$result->where("address LIKE ?", $paramValue);
break;
case "is_online": case "is_online":
$result->where("online >= ?", time() - 900); $result->where("online >= ?", time() - 900);
break; break;
case "interests":
$result->where("interests LIKE ?", $paramValue);
break;
case "fav_mus": case "fav_mus":
$result->where("fav_music LIKE ?", $paramValue); $result->where("fav_music LIKE ?", "%$paramValue%");
break; break;
case "fav_films": case "fav_films":
$result->where("fav_films LIKE ?", $paramValue); $result->where("fav_films LIKE ?", "%$paramValue%");
break; break;
case "fav_shows": case "fav_shows":
$result->where("fav_shows LIKE ?", $paramValue); $result->where("fav_shows LIKE ?", "%$paramValue%");
break; break;
case "fav_books": case "fav_books":
$result->where("fav_books LIKE ?", $paramValue); $result->where("fav_books LIKE ?", "%$paramValue%");
break;
case "fav_quote":
$result->where("fav_quote LIKE ?", $paramValue);
break; break;
case "before": case "before":
$result->where("UNIX_TIMESTAMP(since) < ?", $paramValue); $result->where("UNIX_TIMESTAMP(since) < ?", $paramValue);
@ -128,20 +107,22 @@ class Users
$result->where("UNIX_TIMESTAMP(since) > ?", $paramValue); $result->where("UNIX_TIMESTAMP(since) > ?", $paramValue);
break; break;
case "gender": case "gender":
$result->where("sex ?", $paramValue); if((int) $paramValue == 3) break;
$result->where("sex ?", (int) $paramValue);
break; break;
case "doNotSearchMe": case "ignore_id":
$result->where("id !=", $paramValue); $result->where("id != ?", $paramValue);
break; break;
case "doNotSearchPrivate": case "ignore_private":
$result->where("profile_type", 0); $result->where("profile_type", 0);
break; break;
} }
} }
}
if($order_str)
$result->order($order_str);
return new Util\EntityStream("User", $result->order($sort)); return new Util\EntityStream("User", $result);
} }
function getStatistics(): object function getStatistics(): object

View file

@ -46,23 +46,18 @@ class Videos
return sizeof($this->videos->where("owner", $user->getId())->where(["deleted" => 0, "unlisted" => 0])); return sizeof($this->videos->where("owner", $user->getId())->where(["deleted" => 0, "unlisted" => 0]));
} }
function find(string $query = "", array $pars = [], string $sort = "id"): Util\EntityStream function find(string $query = "", array $params = [], array $order = ['type' => 'id', 'invert' => false]): Util\EntityStream
{ {
$query = "%$query%"; $result = $this->videos->where("CONCAT_WS(' ', name, description) LIKE ?", "%$query%")->where("deleted", 0);
$order_str = 'id';
$notNullParams = []; switch($order['type']) {
case 'id':
$order_str = 'id ' . ($order['invert'] ? 'ASC' : 'DESC');
break;
}
foreach($pars as $paramName => $paramValue) foreach($params as $paramName => $paramValue) {
if($paramName != "before" && $paramName != "after")
$paramValue != NULL ? $notNullParams+=["$paramName" => "%$paramValue%"] : NULL;
else
$paramValue != NULL ? $notNullParams+=["$paramName" => "$paramValue"] : NULL;
$result = $this->videos->where("CONCAT_WS(' ', name, description) LIKE ?", $query)->where("deleted", 0);
$nnparamsCount = sizeof($notNullParams);
if($nnparamsCount > 0) {
foreach($notNullParams as $paramName => $paramValue) {
switch($paramName) { switch($paramName) {
case "before": case "before":
$result->where("created < ?", $paramValue); $result->where("created < ?", $paramValue);
@ -70,12 +65,17 @@ class Videos
case "after": case "after":
$result->where("created > ?", $paramValue); $result->where("created > ?", $paramValue);
break; break;
} case 'only_youtube':
if((int) $paramValue != 1) break;
$result->where("link != ?", 'NULL');
break;
} }
} }
if($order_str)
$result->order($order_str);
return new Util\EntityStream("Video", $result->order("$sort")); return new Util\EntityStream("Video", $result);
} }
function getLastVideo(User $user) function getLastVideo(User $user)

View file

@ -279,7 +279,7 @@ final class AudioPresenter extends OpenVKPresenter
function renderSearch(): void function renderSearch(): void
{ {
$this->redirect("/search?type=audios"); $this->redirect("/search?section=audios");
} }
function renderNewPlaylist(): void function renderNewPlaylist(): void
@ -475,6 +475,7 @@ final class AudioPresenter extends OpenVKPresenter
$this->template->playlist = $playlist; $this->template->playlist = $playlist;
$this->template->page = $page; $this->template->page = $page;
$this->template->cover = $playlist->getCoverPhoto();
$this->template->audios = iterator_to_array($playlist->fetch($page, 10)); $this->template->audios = iterator_to_array($playlist->fetch($page, 10));
$this->template->ownerId = $owner_id; $this->template->ownerId = $owner_id;
$this->template->owner = $playlist->getOwner(); $this->template->owner = $playlist->getOwner();

View file

@ -1,7 +1,7 @@
<?php declare(strict_types=1); <?php declare(strict_types=1);
namespace openvk\Web\Presenters; namespace openvk\Web\Presenters;
use openvk\Web\Models\Entities\{User, Club}; use openvk\Web\Models\Entities\{User, Club};
use openvk\Web\Models\Repositories\{Users, Clubs, Posts, Comments, Videos, Applications, Notes, Audios}; use openvk\Web\Models\Repositories\{Users, Clubs, Posts, Comments, Videos, Applications, Audios};
use Chandler\Database\DatabaseConnection; use Chandler\Database\DatabaseConnection;
final class SearchPresenter extends OpenVKPresenter final class SearchPresenter extends OpenVKPresenter
@ -15,15 +15,14 @@ final class SearchPresenter extends OpenVKPresenter
private $notes; private $notes;
private $audios; private $audios;
function __construct(Users $users, Clubs $clubs) function __construct()
{ {
$this->users = $users; $this->users = new Users;
$this->clubs = $clubs; $this->clubs = new Clubs;
$this->posts = new Posts; $this->posts = new Posts;
$this->comments = new Comments; $this->comments = new Comments;
$this->videos = new Videos; $this->videos = new Videos;
$this->apps = new Applications; $this->apps = new Applications;
$this->notes = new Notes;
$this->audios = new Audios; $this->audios = new Audios;
parent::__construct(); parent::__construct();
@ -33,13 +32,14 @@ final class SearchPresenter extends OpenVKPresenter
{ {
$this->assertUserLoggedIn(); $this->assertUserLoggedIn();
$query = $this->queryParam("query") ?? ""; $query = $this->queryParam("q") ?? "";
$type = $this->queryParam("type") ?? "users"; $section = $this->queryParam("section") ?? "users";
$sorter = $this->queryParam("sort") ?? "id"; $order = $this->queryParam("order") ?? "id";
$invert = $this->queryParam("invert") == 1 ? "ASC" : "DESC"; $invert = (int) ($this->queryParam("invert") ?? 0) == 1;
$page = (int) ($this->queryParam("p") ?? 1); $page = (int) ($this->queryParam("p") ?? 1);
# https://youtu.be/pSAWM5YuXx8 # https://youtu.be/pSAWM5YuXx8
# https://youtu.be/FfNZRhIn2Vk
$repos = [ $repos = [
"groups" => "clubs", "groups" => "clubs",
@ -48,70 +48,74 @@ final class SearchPresenter extends OpenVKPresenter
"comments" => "comments", "comments" => "comments",
"videos" => "videos", "videos" => "videos",
"audios" => "audios", "audios" => "audios",
"apps" => "apps", "apps" => "apps"
"notes" => "notes" ];
$parameters = [
"ignore_private" => true,
]; ];
switch($sorter) { foreach($_REQUEST as $param_name => $param_value) {
if(is_null($param_value)) continue;
switch($param_name) {
default: default:
case "id": $parameters[$param_name] = $param_value;
$sort = "id " . $invert;
break; break;
case "name": case 'marital_status':
$sort = "first_name " . $invert; case 'polit_views':
break; if((int) $param_value == 0) continue;
case "rating": $parameters[$param_name] = $param_value;
$sort = "rating " . $invert;
break;
case "length":
if($type != "audios") break;
$sort = "length " . $invert;
break; break;
case "listens": case 'is_online':
if($type != "audios") break; if((int) $param_value == 1)
$parameters['is_online'] = 1;
break;
case 'only_performers':
if((int) $param_value != 1 || $param_value != 'on') continue;
$parameters['only_performers'] = true;
break;
case 'with_lyrics':
if($param_value == 'on' || $param_value == '1')
$parameters['with_lyrics'] = true;
break;
case 'from_me':
if((int) $param_value != 1) continue;
$parameters['from_me'] = $this->user->id;
$sort = "listens " . $invert;
break; break;
} }
}
$parameters = [ $repo = $repos[$section] or $this->throwError(400, "Bad Request", "Invalid search entity $section.");
"type" => $this->queryParam("type"),
"city" => $this->queryParam("city") != "" ? $this->queryParam("city") : NULL,
"maritalstatus" => $this->queryParam("maritalstatus") != 0 ? $this->queryParam("maritalstatus") : NULL,
"with_photo" => $this->queryParam("with_photo"),
"status" => $this->queryParam("status") != "" ? $this->queryParam("status") : NULL,
"politViews" => $this->queryParam("politViews") != 0 ? $this->queryParam("politViews") : NULL,
"email" => $this->queryParam("email"),
"telegram" => $this->queryParam("telegram"),
"site" => $this->queryParam("site") != "" ? "https://".$this->queryParam("site") : NULL,
"address" => $this->queryParam("address"),
"is_online" => $this->queryParam("is_online") == 1 ? 1 : NULL,
"interests" => $this->queryParam("interests") != "" ? $this->queryParam("interests") : NULL,
"fav_mus" => $this->queryParam("fav_mus") != "" ? $this->queryParam("fav_mus") : NULL,
"fav_films" => $this->queryParam("fav_films") != "" ? $this->queryParam("fav_films") : NULL,
"fav_shows" => $this->queryParam("fav_shows") != "" ? $this->queryParam("fav_shows") : NULL,
"fav_books" => $this->queryParam("fav_books") != "" ? $this->queryParam("fav_books") : NULL,
"fav_quote" => $this->queryParam("fav_quote") != "" ? $this->queryParam("fav_quote") : NULL,
"hometown" => $this->queryParam("hometown") != "" ? $this->queryParam("hometown") : NULL,
"before" => $this->queryParam("datebefore") != "" ? strtotime($this->queryParam("datebefore")) : NULL,
"after" => $this->queryParam("dateafter") != "" ? strtotime($this->queryParam("dateafter")) : NULL,
"gender" => $this->queryParam("gender") != "" && $this->queryParam("gender") != 2 ? $this->queryParam("gender") : NULL,
"doNotSearchPrivate" => true,
"only_performers" => $this->queryParam("only_performers") == "on" ? "1" : NULL,
"with_lyrics" => $this->queryParam("with_lyrics") == "on" ? true : NULL,
];
$repo = $repos[$type] or $this->throwError(400, "Bad Request", "Invalid search entity $type."); $results = $this->{$repo}->find($query, $parameters, ['type' => $order, 'invert' => $invert]);
$iterator = $results->page($page, OPENVK_DEFAULT_PER_PAGE);
$results = $this->{$repo}->find($query, $parameters, $sort);
$iterator = $results->page($page, 14);
$count = $results->size(); $count = $results->size();
$this->template->iterator = iterator_to_array($iterator); $this->template->order = $order;
$this->template->data = $this->template->iterator = iterator_to_array($iterator);
$this->template->count = $count; $this->template->count = $count;
$this->template->type = $type; $this->template->section = $section;
$this->template->page = $page; $this->template->page = $page;
$this->template->perPage = 14; $this->template->perPage = OPENVK_DEFAULT_PER_PAGE;
$this->template->query = $query;
$this->template->atSearch = true;
$this->template->paginatorConf = (object) [
"page" => $page,
"count" => $count,
"amount" => sizeof($this->template->data),
"perPage" => $this->template->perPage,
"atBottom" => false,
"tidy" => true,
"space" => 6,
'pageCount' => ceil($count / $this->template->perPage),
];
$this->template->extendedPaginatorConf = clone $this->template->paginatorConf;
$this->template->extendedPaginatorConf->space = 12;
} }
} }

View file

@ -87,7 +87,7 @@
<div class="layout"> <div class="layout">
<div id="xhead" class="dm"></div> <div id="xhead" class="dm"></div>
<div class="page_header{if $instance_name != OPENVK_DEFAULT_INSTANCE_NAME} page_custom_header{/if}"> <div class="page_header{if $instance_name != OPENVK_DEFAULT_INSTANCE_NAME} page_custom_header{/if}{if $atSearch} search_expanded search_expanded_at_all{/if}">
<a href="/" class="home_button{if $instance_name != OPENVK_DEFAULT_INSTANCE_NAME} home_button_custom{/if}" title="{$instance_name}">{if $instance_name != OPENVK_DEFAULT_INSTANCE_NAME}{$instance_name}{/if}</a> <a href="/" class="home_button{if $instance_name != OPENVK_DEFAULT_INSTANCE_NAME} home_button_custom{/if}" title="{$instance_name}">{if $instance_name != OPENVK_DEFAULT_INSTANCE_NAME}{$instance_name}{/if}</a>
<div n:if="isset($thisUser) ? (!$thisUser->isBanned() XOR !$thisUser->isActivated()) : true" class="header_navigation"> <div n:if="isset($thisUser) ? (!$thisUser->isBanned() XOR !$thisUser->isActivated()) : true" class="header_navigation">
{ifset $thisUser} {ifset $thisUser}
@ -96,67 +96,46 @@
<a href="/logout?hash={urlencode($csrfToken)}">{_header_log_out}</a> <a href="/logout?hash={urlencode($csrfToken)}">{_header_log_out}</a>
</div> </div>
{else} {else}
<div class="link dec"> <div class="link">
<a href="/">{_header_home}</a> <a href="/">{_header_home}</a>
</div> </div>
<div class="link dec"> <div class="link">
<a href="/search?type=groups">{_header_groups}</a> <a href="/search?section=groups">{_header_groups}</a>
</div> </div>
<div class="link dec"> <div class="link">
<a href="/search">{_header_search}</a> <a href="/search?q=&section=users&order=rating">{_header_search}</a>
</div> </div>
<div class="link dec"> <div class="link">
<a href="/invite">{_header_invite}</a> <a href="/invite">{_header_invite}</a>
</div> </div>
<div class="link dec"> <div class="link">
<a href="/support">{_header_help} <b n:if="$ticketAnsweredCount > 0">({$ticketAnsweredCount})</b></a> <a href="/support">{_header_help} <b n:if="$ticketAnsweredCount > 0">({$ticketAnsweredCount})</b></a>
</div> </div>
<div class="link dec"> <div class="link">
<a href="/logout?hash={urlencode($csrfToken)}">{_header_log_out}</a> <a href="/logout?hash={urlencode($csrfToken)}">{_header_log_out}</a>
</div> </div>
{var $atSearch = str_contains($_SERVER['REQUEST_URI'], "/search")} <div id="search_box" class='header_divider_stick'>
<div id="srch" class="{if $atSearch}nodivider{else}link{/if}"> <div id="search_box_fr">
<form id='search_form' action="/search" method="get">
{if !$atSearch} <div id='search_and_one_more_wrapper'>
<form action="/search" method="get" id="searcher" style="position:relative;"> <input n:attr="value => $_REQUEST['q'] ? $_REQUEST['q'] : NULL" autocomplete="off" type="search" maxlength="79" name="q" placeholder="{_header_search}" title="{_header_search} [Alt+Shift+F]" accesskey="f" />
<input autocomplete="off" id="searchInput" oninput="checkSearchTips()" onfocus="expandSearch()" onblur="decreaseSearch()" class="sr" type="search" name="query" placeholder="{_header_search}" style="height: 20px;background: url('/assets/packages/static/openvk/img/search_icon.png') no-repeat 3px 4px; background-color: #fff; padding-left: 18px;width: 120px;" title="{_header_search} [Alt+Shift+F]" accesskey="f" /> <select name="section">
<select onchange="checkSearchTips()" id="typer" name="type" class="whatFind" style="display:none;top: 0px;"> <option n:attr="selected => $_REQUEST['section'] == 'users'" value="users">{_s_by_people}</option>
<option value="users">{_s_by_people}</option> <option n:attr="selected => $_REQUEST['section'] == 'groups'" value="groups">{_s_by_groups}</option>
<option value="groups">{_s_by_groups}</option> <option n:attr="selected => $_REQUEST['section'] == 'posts'" value="posts">{_s_by_posts}</option>
<option value="posts">{_s_by_posts}</option> <option n:attr="selected => $_REQUEST['section'] == 'comments'" value="comments">{_s_by_comments}</option>
<option value="comments">{_s_by_comments}</option> <option n:attr="selected => $_REQUEST['section'] == 'videos'" value="videos">{_s_by_videos}</option>
<option value="videos">{_s_by_videos}</option> <option n:attr="selected => $_REQUEST['section'] == 'apps'" value="apps">{_s_by_apps}</option>
<option value="apps">{_s_by_apps}</option> <option n:attr="selected => $_REQUEST['section'] == 'audios'" value="audios">{_s_by_audios}</option>
<option value="audios">{_s_by_audios}</option> <option n:attr="selected => $_REQUEST['section'] == 'playlists'" value="playlists">{_s_by_audios_playlists}</option>
</select> </select>
</form>
<div class="searchTips" id="srcht" hidden>
<table style="border:none;border-spacing: 0;">
<tbody id="srchrr">
</tbody>
</table>
</div> </div>
{else} <button class="search_box_button">
<form action="/search" method="get" id="searcher" style="margin-top: -1px;position:relative;"> <span>{_header_search}</span>
<input id="searchInput" value="{$_GET['query'] ?? ''}" type="search" class="sr" name="query" placeholder="{_header_search}" style="height: 20px; background-color: #fff; padding-left: 6px;width: 555px;" title="{_header_search} [Alt+Shift+F]" accesskey="f" /> </button>
<select name="type" class="whatFind">
<option value="users" {if str_contains($_SERVER['REQUEST_URI'], "type=users")}selected{/if}>{_s_by_people}</option>
<option value="groups" {if str_contains($_SERVER['REQUEST_URI'], "type=groups")}selected{/if}>{_s_by_groups}</option>
<option value="posts" {if str_contains($_SERVER['REQUEST_URI'], "type=posts")}selected{/if}>{_s_by_posts}</option>
<option value="comments" {if str_contains($_SERVER['REQUEST_URI'], "type=comments")}selected{/if}>{_s_by_comments}</option>
<option value="videos" {if str_contains($_SERVER['REQUEST_URI'], "type=videos")}selected{/if}>{_s_by_videos}</option>
<option value="apps" {if str_contains($_SERVER['REQUEST_URI'], "type=apps")}selected{/if}>{_s_by_apps}</option>
<option value="audios" {if str_contains($_SERVER['REQUEST_URI'], "type=audios")}selected{/if}>{_s_by_audios}</option>
</select>
<button class="searchBtn"><span style="color:white;font-weight: 600;font-size:12px;">{_header_search}</span></button>
</form> </form>
<script> </div>
let els = document.querySelectorAll("div.dec") <div id="searchBoxFastTips"></div>
for(const element of els) {
element.style.display = "none"
}
</script>
{/if}
</div> </div>
{/if} {/if}
{else} {else}
@ -400,6 +379,7 @@
{script "js/al_mentions.js"} {script "js/al_mentions.js"}
{script "js/al_polls.js"} {script "js/al_polls.js"}
{script "js/al_suggestions.js"} {script "js/al_suggestions.js"}
{script "js/al_navigation.js"}
{ifset $thisUser} {ifset $thisUser}
{script "js/al_notifs.js"} {script "js/al_notifs.js"}
@ -442,7 +422,8 @@
<script> <script>
window.openvk = { window.openvk = {
"audio_genres": {\openvk\Web\Models\Entities\Audio::genres} "audio_genres": {\openvk\Web\Models\Entities\Audio::genres},
"at_search": {$atSearch ?? false},
} }
</script> </script>

View file

@ -59,11 +59,10 @@
<input n:if="$mode == 'popular'" type="hidden" name="bigplayer_context" data-type="popular_audios" data-entity="0" data-page="1"> <input n:if="$mode == 'popular'" type="hidden" name="bigplayer_context" data-type="popular_audios" data-entity="0" data-page="1">
<div class="bigPlayerDetector"></div> <div class="bigPlayerDetector"></div>
<div style="width: 100%;display: flex;margin-bottom: -10px;" class="audiosDiv"> <div class="audiosDiv">
<div style="width: 74%;" class="audiosContainer" n:if="$mode != 'playlists'"> <div style="width: 74%;" class="audiosContainer audiosPaddingContainer" n:if="$mode != 'playlists'">
<div style="padding: 8px;"> <div n:if="$audiosCount <= 0" style='height: 50%;'>
<div n:if="$audiosCount <= 0"> {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/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="infContainer">
<div class="infObj" n:foreach="$audios as $audio"> <div class="infObj" n:foreach="$audios as $audio">
@ -81,16 +80,14 @@
]} ]}
</div> </div>
</div> </div>
</div>
<div style="width: 74%;" n:if="$mode == 'playlists'"> <div style="width: 74%;" class="audiosPaddingContainer" n:if="$mode == 'playlists'">
<div style="padding: 8px;"> <div n:if="$playlistsCount <= 0" style='height: 100%;'>
<div n:if="$playlistsCount <= 0"> {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/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="infContainer playlistContainer" n:if="$playlistsCount > 0">
<div class="infObj" n:foreach="$playlists as $playlist"> <div n:foreach="$playlists as $playlist">
<a href="/playlist{$playlist->getPrettyId()}"> <a href="/playlist{$playlist->getPrettyId()}">
<div class="playlistCover"> <div class="playlistCover">
<img src="{$playlist->getCoverURL()}" alt="{_playlist_cover}"> <img src="{$playlist->getCoverURL()}" alt="{_playlist_cover}">
@ -120,7 +117,6 @@
]} ]}
</div> </div>
</div> </div>
</div>
{include "tabs.xml"} {include "tabs.xml"}
</div> </div>
{/block} {/block}

View file

@ -35,8 +35,8 @@
<input type="hidden" name="bigplayer_context" data-type="playlist_context" data-entity="{$playlist->getId()}" data-page="{$page}"> <input type="hidden" name="bigplayer_context" data-type="playlist_context" data-entity="{$playlist->getId()}" data-page="{$page}">
<div class="playlistBlock"> <div class="playlistBlock">
<div class="playlistCover" style="float: left;"> <div class="playlistCover" style="float: left;">
<a href="{$playlist->getCoverURL()}" target="_blank"> <a href="{$cover->getURL()}" target="_blank">
<img src="{$playlist->getCoverURL('normal')}" alt="{_playlist_cover}"> <img onclick="OpenMiniature(event, {$cover->getURL()}, null, {$cover->getPrettyId()}, null)" src="{$playlist->getCoverURL('normal')}" alt="{_playlist_cover}">
</a> </a>
<div class="profile_links" style="width: 139px;" n:if="isset($thisUser)"> <div class="profile_links" style="width: 139px;" n:if="isset($thisUser)">

View file

@ -43,7 +43,7 @@
</form> </form>
</div><br/> </div><br/>
<span>{_you_can_also_add_audio_using} <b><a href="/search?type=audios">{_search_audio_inst}</a></b>.<span> <span>{_you_can_also_add_audio_using} <b><a href="/search?section=audios">{_search_audio_inst}</a></b>.<span>
</div> </div>
<div id="lastStep" style="display:none;"> <div id="lastStep" style="display:none;">

View file

@ -14,7 +14,7 @@
<div class="mediaInfo noOverflow" style="margin-bottom: -8px; cursor: pointer;display:flex;width: 85%;"> <div class="mediaInfo noOverflow" style="margin-bottom: -8px; cursor: pointer;display:flex;width: 85%;">
<div class="info"> <div class="info">
<strong class="performer"> <strong class="performer">
<a href="/search?query=&type=audios&sort=id&only_performers=on&query={$audio->getPerformer()}">{$audio->getPerformer()}</a> <a href="/search?query=&section=audios&order=listens&only_performers=on&q={$audio->getPerformer()}">{$audio->getPerformer()}</a>
</strong> </strong>
<span class="title {if !empty($audio->getLyrics())}withLyrics{/if}">{$audio->getTitle()}</span> <span class="title {if !empty($audio->getLyrics())}withLyrics{/if}">{$audio->getTitle()}</span>

View file

@ -1,10 +1,11 @@
<div class="searchOptions newer"> <div class='verticalGrayTabsWrapper'>
<div class="searchList" style="margin-top:10px"> <div class="verticalGrayTabs">
<div class='with_padding'>
<a n:attr="id => $mode === 'list' && $isMy ? 'used' : 'ki'" href="/audios{$thisUser->getId()}" n:if="isset($thisUser)">{_my_music}</a> <a n:attr="id => $mode === 'list' && $isMy ? 'used' : 'ki'" href="/audios{$thisUser->getId()}" n:if="isset($thisUser)">{_my_music}</a>
<a href="/player/upload{if $isMyClub}?gid={abs($ownerId)}{/if}" n:if="isset($thisUser)">{_upload_audio}</a> <a href="/player/upload{if $isMyClub}?gid={abs($ownerId)}{/if}" n:if="isset($thisUser)">{_upload_audio}</a>
<a n:attr="id => $mode === 'new' ? 'used' : 'ki'" href="/audios/new">{_audio_new}</a> <a n:attr="id => $mode === 'new' ? 'used' : 'ki'" href="/audios/new">{_audio_new}</a>
<a n:attr="id => $mode === 'popular' ? 'used' : 'ki'" href="/audios/popular">{_audio_popular}</a> <a n:attr="id => $mode === 'popular' ? 'used' : 'ki'" href="/audios/popular">{_audio_popular}</a>
<a href="/search?type=audios" n:if="isset($thisUser)">{_audio_search}</a> <a href="/search?section=audios" n:if="isset($thisUser)">{_audio_search}</a>
<hr n:if="isset($thisUser)"> <hr n:if="isset($thisUser)">
@ -20,10 +21,11 @@
<a n:attr="id => $mode === 'playlists' && $ownerId != $thisUser->getId() ? 'used' : 'ki'" href="/playlists{$ownerId}" n:if="isset($thisUser) && isset($ownerId) && !$isMy">{if $ownerId > 0}{_playlists_user}{else}{_playlists_club}{/if}</a> <a n:attr="id => $mode === 'playlists' && $ownerId != $thisUser->getId() ? 'used' : 'ki'" href="/playlists{$ownerId}" n:if="isset($thisUser) && isset($ownerId) && !$isMy">{if $ownerId > 0}{_playlists_user}{else}{_playlists_club}{/if}</a>
<a href="/audios/newPlaylist{if $isMyClub}?gid={abs($ownerId)}{/if}" n:if="isset($thisUser) && $isMyClub">{_new_playlist}</a> <a href="/audios/newPlaylist{if $isMyClub}?gid={abs($ownerId)}{/if}" n:if="isset($thisUser) && $isMyClub">{_new_playlist}</a>
{/if} {/if}
</div>
{if $friendsAudios} {if $friendsAudios}
<div class="friendsAudiosList"> <div class="friendsAudiosList">
<a href="/audios{$fr->getRealId()}" style="width: 94%;padding-left: 10px;" n:foreach="$friendsAudios as $fr"> <a href="/audios{$fr->getRealId()}" n:foreach="$friendsAudios as $fr">
<div class="elem"> <div class="elem">
<img src="{$fr->getAvatarURL()}" /> <img src="{$fr->getAvatarURL()}" />

View file

@ -1,378 +1,378 @@
{extends "../@layout.xml"} {extends "../@layout.xml"}
{block title} {block title}
{tr("search_for_$type")} {tr("search_for_$section")}
{if $_GET['query']} {if $_REQUEST['q']}
- {$_GET['query']} - {$_REQUEST['q']}
{/if} {/if}
{/block} {/block}
{block header} {block header}
{=OPENVK_ROOT_CONF["openvk"]["appearance"]["name"]} » {tr("search_for_$section")}
{tr("search_for_$type")}
{/block} {/block}
{* BEGIN ELEMENTS DESCRIPTION *} {block wrap}
<div class="wrap2">
{block link|strip|stripHtml} <div class="wrap1">
{if $type != "apps"} <div class="page_wrap">
{$x->getURL()} <div class='summaryBar summaryBarFlex padding'>
{else} <div class='summary'>
/app{$x->getId()} <b>{tr("results", $count)} {tr("showing_x_y", $page, $count)}</b>
{/if}
{/block}
{block preview}
<img src="{$x->getAvatarUrl('miniscule')}" width="75" alt="{_photo}" loading=lazy />
{/block}
{block name}
{if $type != "apps"}
<text style="overflow: hidden;">&nbsp;{$x->getCanonicalName()}
{if $_GET['sort'] == "rating"}({$x->getRating()}%)
{elseif $_GET['sort'] == "id"}(id{$x->getId()}){/if}</text>
<img n:if="$x->isVerified()"
class="name-checkmark"
src="/assets/packages/static/openvk/img/checkmark.png"
/>
{else}
{$x->getName()}
{/if}
{/block}
{block description}
<table class="ugc-table">
<tbody>
{if $type === "users"}
{if !is_null($_GET['status']) && $_GET['status'] != ""}
<tr>
<td><span class="nobold">{_status}:</span></td>
<td>{$x->getStatus()}</td>
</tr>
{/if}
{if !is_null($_GET['city']) && $_GET['city'] != "" && $x->getPrivacySetting("page.info.read") > 1}
<tr>
<td><span class="nobold">{_city}:</span></td>
<td>{$x->getCity()}</td>
</tr>
{/if}
{if !is_null($_GET['city']) && $_GET['hometown'] != "" && $x->getPrivacySetting("page.info.read") > 1}
<tr>
<td><span class="nobold">{_hometown}:</span></td>
<td>{$x->getHometown()}</td>
</tr>
{/if}
{if !is_null($_GET['politViews']) && $_GET['politViews'] != 0 && $x->getPrivacySetting("page.info.read") > 1}
<tr>
<td><span class="nobold">{_politViews}:</span></td>
<td>{tr("politViews_".$x->getPoliticalViews())}</td>
</tr>
{/if}
{if !is_null($_GET['email']) && $_GET['email'] != "" && $x->getPrivacySetting("page.info.read") > 1}
<tr>
<td><span class="nobold">{_email}:</span></td>
<td>{$x->getContactEmail()}</td>
</tr>
{/if}
{if !is_null($_GET['telegram']) && $_GET['telegram'] != "" && $x->getPrivacySetting("page.info.read") > 1}
<tr>
<td><span class="nobold">{_telegram}:</span></td>
<td><a href="tg://resolve?domain={$x->getTelegram()}">@{$x->getTelegram()}</a></td>
</tr>
{/if}
{if !is_null($_GET['site']) && $_GET['site'] != "" && $x->getPrivacySetting("page.info.read") > 1}
<tr>
<td><span class="nobold">{_personal_website}:</span></td>
<td><a href="{$x->getWebsite()}">{$x->getWebsite()}</a></td>
</tr>
{/if}
{if !is_null($_GET['address']) && $_GET['address'] != "" && $x->getPrivacySetting("page.info.read") > 1}
<tr>
<td><span class="nobold">{_address}:</span></td>
<td>{$x->getPhysicalAddress()}</td>
</tr>
{/if}
{if $x->getPrivacySetting("page.info.read") > 1}
<tr>
<td><span class="nobold">{_pronouns}: </span></td>
<td>{$x->isFemale() ? tr("female") : ($x->isNeutral() ? tr("neutral") : tr("male"))}</td>
</tr>
<tr>
<td><span class="nobold">{_relationship}:</span></td>
<td>{$x->getLocalizedMaritalStatus()}</td>
</tr>
<tr>
<td><span class="nobold">{_registration_date}: </span></td>
<td>{$x->getRegistrationTime()}</td>
</tr>
{/if}
{/if}
<tr>
{if !empty($x->getDescription())}
{if $type != "apps"}
<td>
<span class="nobold">{_description}:</span>
</td>
{/if}
<td {if $type == "apps"}style="width:400px"{/if}>
{$x->getDescription() ?? '(' . tr("none") . ')'}
</td>
</tr>
{/if}
{if $type == "groups"}
<td>
<span class="nobold">{_size}:</span>
</td>
<td>
{tr("participants", $x->getFollowersCount())}
</td>
{/if}
</tbody>
</table>
{/block}
{block content}
<style>
.comment, .post-divider
{
border:none;
}
</style>
<div style="margin-top:-7px">
{var $data = is_array($iterator) ? $iterator : iterator_to_array($iterator)}
{include "../components/paginator.xml", conf => (object) [
"page" => $page,
"count" => $count,
"amount" => sizeof($data),
"perPage" => $perPage ?? OPENVK_DEFAULT_PER_PAGE,
"atBottom" => false,
]}
</div> </div>
<p style="margin-left: 15px; margin-top: 0;">
<b>{tr("results", $count)}</b>
</p>
<div>
{include searchOptions}
<div class="container_gray borderup" style="float:left;width:73.3%;"> {include "../components/paginator.xml", conf => $paginatorConf}
{if sizeof($data) > 0} </div>
{if $type == "users" || $type == "groups" || $type == "apps"}
<div class="content" n:foreach="$data as $dat"> <div class='page_wrap_content' id='search_page'>
<div class='page_wrap_content_main'>
{if $count > 0}
{if $section === 'users'}
<div class='search_content def_row_content' n:foreach="$data as $dat">
<table> <table>
<tbody> <tbody>
<tr> <tr>
<td valign="top"> <td valign="top">
<a href="{include link, x => $dat}"> <a href="{$dat->getURL()}">
{include preview, x => $dat} <img src="{$dat->getAvatarUrl('miniscule')}" width="75" alt="{_photo}" loading='lazy' />
</a> </a>
</td> </td>
<td valign="top" style="width: 100%"> <td valign="top" style="width: 100%">
{ifset infotable} <a href="{$dat->getURL()}">
{include infotable, x => $dat}
{else}
<a href="{include link, x => $dat}">
<b> <b>
{include name, x => $dat} <text style="overflow: hidden;">&nbsp;{$dat->getCanonicalName()}
{if $order == "rating"}
({$dat->getProfileCompletenessReport()->total}%)
{/if}
</text>
<img n:if="$dat->isVerified()"
class="name-checkmark"
src="/assets/packages/static/openvk/img/checkmark.png"
/>
</b> </b>
{if $dat->getId() == $thisUser->getId()}
({_s_it_is_you})
{/if}
</a> </a>
<br/>
{include description, x => $dat} <table class="ugc-table">
{/ifset} <tbody>
{if $_REQUEST["order"] == "id"}
<tr>
<td><span class="nobold">ID:</span></td>
<td>{$dat->getId()}</td>
</tr>
{/if}
{if $dat->getPrivacySetting("page.info.read") > 1}
<tr>
<td><span class="nobold">{_pronouns}: </span></td>
<td>{$dat->isFemale() ? tr("female") : ($dat->isNeutral() ? tr("neutral") : tr("male"))}</td>
</tr>
<tr>
<td><span class="nobold">{_relationship}:</span></td>
<td>{$dat->getLocalizedMaritalStatus()}</td>
</tr>
<tr>
<td><span class="nobold">{_registration_date}: </span></td>
<td>{$dat->getRegistrationTime()}</td>
</tr>
{if !empty($dat->getDescription())}
<tr>
<td>
<span class="nobold">{_description}:</span>
</td> </td>
<td n:ifset="actions" valign="top" class="action_links" style="width: 150px;"> <td>
{include actions, x => $dat} {$dat->getDescription() ?? '(' . tr("none") . ')'}
</td>
</tr>
{/if}
{if !empty($_REQUEST["fav_mus"])}
<tr>
<td><span class="nobold">{_favorite_music}:</span></td>
<td>{$dat->getFavoriteMusic()}</td>
</tr>
{/if}
{if !empty($_REQUEST["fav_films"])}
<tr>
<td><span class="nobold">{_favorite_films}:</span></td>
<td>{$dat->getFavoriteFilms()}</td>
</tr>
{/if}
{if !empty($_REQUEST["fav_shows"])}
<tr>
<td><span class="nobold">{_favorite_shows}:</span></td>
<td>{$dat->getFavoriteShows()}</td>
</tr>
{/if}
{if !empty($_REQUEST["fav_books"])}
<tr>
<td><span class="nobold">{_favorite_books}:</span></td>
<td>{$dat->getFavoriteBooks()}</td>
</tr>
{/if}
{/if}
</tbody>
</table>
<br/>
</td> </td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div> </div>
{elseif $type == "posts"} {elseif $section === 'groups'}
<div n:foreach="$data as $dat" class="content"> <div class='search_content def_row_content' n:foreach="$data as $dat">
{if !$dat || $dat->getTargetWall() < 0 && $dat->getWallOwner()->isHideFromGlobalFeedEnabled() || !$dat->canBeViewedBy($thisUser)} <table>
{_closed_group_post}. <tbody>
{else} <tr>
<td valign="top">
<a href="{$dat->getURL()}">
<img src="{$dat->getAvatarUrl('miniscule')}" width="75" alt="{_photo}" loading='lazy' />
</a>
</td>
<td valign="top" style="width: 100%">
<a href="{$dat->getURL()}">
<b>
<text style="overflow: hidden;">&nbsp;{$dat->getCanonicalName()}
{if $order == "id"}
(id{$dat->getId()})
{/if}
</text>
<img n:if="$dat->isVerified()"
class="name-checkmark"
src="/assets/packages/static/openvk/img/checkmark.png"
/>
</b>
</a>
<table class="ugc-table">
<tbody>
{if !empty($dat->getDescription())}
<tr>
<td>
<span class="nobold">{_description}:</span>
</td>
<td>
{$dat->getDescription() ?? '(' . tr("none") . ')'}
</td>
</tr>
{/if}
<td>
<span class="nobold">{_size}:</span>
</td>
<td>
{tr("participants", $dat->getFollowersCount())}
</td>
</tbody>
</table>
<br/>
</td>
</tr>
</tbody>
</table>
</div>
{elseif $section === 'apps'}
<div class='search_content def_row_content' n:foreach="$data as $dat">
<table>
<tbody>
<tr>
<td valign="top">
<a href="/app{$dat->getId()}">
<img src="{$dat->getAvatarUrl('miniscule')}" width="75" alt="{_photo}" loading='lazy' />
</a>
</td>
<td valign="top" style="width: 100%">
<a href="/app{$dat->getId()}">
<b>
<text style="overflow: hidden;">
&nbsp;{$dat->getName()}
</text>
</b>
</a>
<table class="ugc-table">
<tbody>
<tr>
<td>
{$dat->getDescription() ?? '(' . tr("none") . ')'}
</td>
</tr>
</tbody>
</table>
<br/>
</td>
</tr>
</tbody>
</table>
</div>
{elseif $section === 'posts'}
{* шмалим дурь курим шмаль дуем коку пиво пьём *}
<div class='search_content' n:foreach="$data as $dat">
{include "../components/post.xml", post => $dat, commentSection => true, onWallOf => true} {include "../components/post.xml", post => $dat, commentSection => true, onWallOf => true}
{/if}
</div> </div>
{elseif $type == "comments"} {elseif $section === 'comments'}
<div n:foreach="$data as $dat" class="content"> <div class='search_content' n:foreach="$data as $dat">
{if !$dat->getTarget() || $dat->getTarget()->isDeleted()} {include "../components/comment.xml", no_reply_button => true, comment => $dat, correctLink => true}
{_deleted_target_comment}.
{else}
{include "../components/comment.xml", comment => $dat, linkW => true}
{/if}
</div> </div>
{elseif $type == "videos"} {elseif $section === 'videos'}
{foreach $data as $dat} <div class='search_content' n:foreach="$data as $dat">
<div class="content">
{include "../components/video.xml", video => $dat} {include "../components/video.xml", video => $dat}
</div> </div>
{/foreach} {elseif $section === 'audios'}
{elseif $type == "audios"} <div class='search_content' n:foreach="$data as $dat">
{foreach $data as $dat}
{include "../Audio/player.xml", audio => $dat} {include "../Audio/player.xml", audio => $dat}
{/foreach} </div>
{/if} {/if}
{else} {else}
{ifset customErrorMessage} {include "../components/content_error.xml", description => tr("no_results_by_this_query")}
{include customErrorMessage}
{else}
{include "../components/nothing.xml"}
{/ifset}
{/if} {/if}
</div> </div>
<script> <div class='page_wrap_content_options verticalGrayTabsWrapper'>
window.addEventListener("load", (event) => { <div class="page_wrap_content_options_list verticalGrayTabs with_padding">
document.getElementsByClassName("container_gray")[0].style.minHeight = document.getElementsByClassName("searchOptions")[0].clientHeight+"px"; <a n:attr="id => $section === 'users' ? 'used'" href="/search?section=users&q={$query}"> {_s_people}</a>
document.getElementsByClassName("searchOptions")[0].style.minHeight = document.getElementsByClassName("container_gray")[0].clientHeight-3+"px"; <a n:attr="id => $section === 'groups' ? 'used'" href="/search?section=groups&q={$query}"> {_s_groups}</a>
}) <a n:attr="id => $section === 'posts' ? 'used'" href="/search?section=posts&q={$query}"> {_s_posts}</a>
</script> <a n:attr="id => $section === 'comments' ? 'used'" href="/search?section=comments&q={$query}"> {_s_comments}</a>
<a n:attr="id => $section === 'videos' ? 'used'" href="/search?section=videos&q={$query}"> {_s_videos}</a>
<a n:attr="id => $section === 'apps' ? 'used'" href="/search?section=apps&q={$query}"> {_s_apps}</a>
<a n:attr="id => $section === 'audios' ? 'used'" href="/search?section=audios&q={$query}"> {_s_audios}</a>
<a n:attr="id => $section === 'playlists' ? 'used'" href="/search?section=playlists&q={$query}">{_s_audios_playlists}</a>
</div>
<div class='page_search_options'>
{include searchOptions}
</div>
</div>
</div>
<div n:if='$paginatorConf->pageCount > 1' class='page_content_paginator_bottom'>
{include "../components/paginator.xml", conf => $extendedPaginatorConf}
</div>
</div>
</div>
</div>
{/block} {/block}
{block searchOptions} {block searchOptions}
<div class="searchOptions"> <div class="search_option">
<ul class="searchList"> <div class="search_option_name">
<a {if $type === "users"} id="used"{/if} href="/search?type=users{if $_GET['query']}&query={urlencode($_GET['query'])}{/if}&sort=id"> {_s_people} {if $type === "users"} ({$count}){/if}</a> <div class='search_option_name_ico'></div>
<a {if $type === "groups"} id="used"{/if} href="/search?type=groups{if $_GET['query']}&query={urlencode($_GET['query'])}{/if}&sort=id"> {_s_groups} {if $type === "groups"} ({$count}){/if}</a> {_s_order_by}
<a {if $type === "comments"}id="used"{/if} href="/search?type=comments{if $_GET['query']}&query={urlencode($_GET['query'])}{/if}&sort=id">{_s_comments} {if $type === "comments"}({$count}){/if}</a> </div>
<a {if $type === "posts"} id="used"{/if} href="/search?type=posts{if $_GET['query']}&query={urlencode($_GET['query'])}{/if}&sort=id"> {_s_posts} {if $type === "posts"} ({$count}){/if}</a> <div class="search_option_content">
<a {if $type === "videos"} id="used"{/if} href="/search?type=videos{if $_GET['query']}&query={urlencode($_GET['query'])}{/if}&sort=id"> {_s_videos} {if $type === "videos"} ({$count}){/if}</a> <select name="order" form="search_form" data-default='id'>
<a {if $type === "apps"} id="used"{/if} href="/search?type=apps{if $_GET['query']}&query={urlencode($_GET['query'])}{/if}&sort=id"> {_s_apps} {if $type === "apps"} ({$count}){/if}</a> {if $section == "users"}
<a {if $type === "audios"} id="used"{/if} href="/search?type=audios{if $_GET['query']}&query={urlencode($_GET['query'])}{/if}&sort=id"> {_s_audios} {if $type === "audios"} ({$count}){/if}</a> <option value="id" n:attr="selected => $order == 'id'">{_s_order_by_reg_date}</option>
</ul>
<div class="searchOption">
<div class="searchOptionName" id="n_sort" onclick="hideParams('sort')"><img src="/assets/packages/static/openvk/img/hide.png" class="searchHide">{_s_order_by}</div>
<div class="searchOptionBlock" id="s_sort">
<select name="sort" form="searcher" id="sortyor">
<option value="id" {if $_GET["sort"] == "name"}selected{/if}>{_s_order_by_id}</option>
{if $type == "users"}
<option value="name" {if $_GET["sort"] == "name"}selected{/if}>{_s_order_by_name}</option>
{if OPENVK_ROOT_CONF["openvk"]["preferences"]["commerce"]} {if OPENVK_ROOT_CONF["openvk"]["preferences"]["commerce"]}
<option value="rating" {if $_GET["sort"] == "rating"}selected{/if}>{_s_order_by_rating}</option> <option value="rating" n:attr="selected => $order == 'rating'">{_s_order_by_rating}</option>
{/if} {/if}
{elseif $section == "posts"}
<option value="id" n:attr="selected => $order == 'id'">{_s_order_by_publishing_date}</option>
{elseif $section == "audios"}
<option value="id" n:attr="selected => $order == 'id'">{_s_order_by_upload_date}</option>
{else}
<option value="id" n:attr="selected => $order == 'id'">{_s_order_by_creation_date}</option>
{/if} {/if}
{if $type == "audios"} {if $section == "audios"}
<option value="length" n:attr="selected => $_GET['sort'] == 'length'">{_s_order_by_length}</option> <option value="length" n:attr="selected => $order == 'length'">{_s_order_by_length}</option>
<option value="listens" n:attr="selected => $_GET['sort'] == 'listens'">{_s_order_by_listens}</option> <option value="listens" n:attr="selected => $order == 'listens'">{_s_order_by_listens}</option>
{/if} {/if}
</select> </select>
<div id="invertor">
<input type="checkbox" name="invert" value="1" form="searcher" {if !is_null($_GET['invert']) && $_GET['invert'] == "1"}checked{/if}>{_s_order_invert} <label n:if="$order != 'rating'">
</div> <input type="checkbox" name="invert" value="1" form="search_form" n:attr="checked => $_REQUEST['invert'] == '1'">
{_s_order_invert}
</label>
</div> </div>
</div> </div>
{if $type !== "groups" && $type !== "apps"} {* В OpenVK не сохраняется дата создания групп и приложений *} <div n:if="$section == 'users'" class="search_option">
<div class="searchOption"> <div class="search_option_name">
<div class="searchOptionName" id="n_dates" onclick="hideParams('dates')"><img src="/assets/packages/static/openvk/img/hide.png" class="searchHide">{_s_by_date}</div> <div class='search_option_name_ico'></div>
<div class="searchOptionBlock" id="s_dates"> {_main}
{if $type != "users"}
<p id="bydate">{_s_date_before}:<br>
{else}
<p id="bydate">{_s_registered_before}:<br>
{/if}
<input type="date" name="datebefore"
form="searcher"
id="bydate"
style="width:100%"
value="{if !is_null($_GET['datebefore'])}{$_GET['datebefore']}{/if}"
min="2019-11-19"
max={date('Y-m-d')}></p>
{if $type != "users"}
<p id="bydate">{_s_date_after}:<br>
{else}
<p id="bydate">{_s_registered_after}:<br>
{/if}
<input type="date" name="dateafter"
form="searcher"
style="width:100%"
id="bydate"
value="{if !is_null($_GET['dateafter'])}{$_GET['dateafter']}{/if}"
min="2019-11-18"
max={date('Y-m-d')}></p>
</div> </div>
</div> <div class="search_option_content">
{/if} <input type="text" n:attr="value => $_REQUEST['city']" form="search_form" placeholder="{_city}" name="city">
<input type="text" n:attr="value => $_REQUEST['hometown']" form="search_form" placeholder="{_hometown}" name="hometown">
{if $type === "users"} <label>
<div class="searchOption"> <input name="is_online" type="checkbox" n:attr="checked => $_REQUEST['is_online'] == '1'" form="search_form" value="1">
<div class="searchOptionName" id="n_main" onclick="hideParams('main')"><img src="/assets/packages/static/openvk/img/hide.png" class="searchHide">{_main}</div> {_s_now_on_site}
<div class="searchOptionBlock" id="s_main"> </label>
<input type="text" value="{if !is_null($_GET['status'])}{$_GET['status']}{/if}" form="searcher" placeholder="{_status}" name="status">
<input type="text" value="{if !is_null($_GET['city'])}{$_GET['city']}{/if}" form="searcher" placeholder="{_city}" name="city">
<input type="text" value="{if !is_null($_GET['hometown'])}{$_GET['hometown']}{/if}" form="searcher" placeholder="{_hometown}" name="hometown">
<input name="is_online" type="checkbox" {if !is_null($_GET['is_online']) && $_GET['is_online'] == "1"}checked{/if} form="searcher" value="1">{_s_now_on_site}
</div> </div>
</div> </div>
<!-- <div class="searchOption"> <div n:if="$section == 'users'" class="search_option">
<div class="searchOptionName" id="n_gender" onclick="hideParams('gender')"><img src="/assets/packages/static/openvk/img/hide.png" class="searchHide">{_gender}</div> <div class="search_option_name">
<div class="searchOptionBlock" id="s_gender"> <div class='search_option_name_ico'></div>
<p><input type="radio" form="searcher" id="gend" {if $_GET['gender'] == 0}checked{/if} name="gender" value="0">{_male}</p> {_pronouns}
<p><input type="radio" form="searcher" id="gend1"{if $_GET['gender'] == 1}checked{/if} name="gender" value="1">{_female}</p>
<p><input type="radio" form="searcher" id="gend2"{if $_GET['gender'] == 2 || is_null($_GET['gender'])}checked{/if} name="gender" value="2">{_s_any}</p>
</div> </div>
</div> --> <div class="search_option_content">
<label><input type="radio" form="search_form" n:attr="checked => $_REQUEST['gender'] == 0" name="gender" value="0">{_male}</label>
<div class="searchOption"> <label><input type="radio" form="search_form" n:attr="checked => $_REQUEST['gender'] == 1" name="gender" value="1">{_female}</label>
<div class="searchOptionName" id="n_relationship" onclick="hideParams('relationship')"><img src="/assets/packages/static/openvk/img/hide.png" class="searchHide">{ovk_proc_strtr(tr("relationship"), 14)}</div> <label><input type="radio" form="search_form" n:attr="checked => $_REQUEST['gender'] == 2" name="gender" value="2">{_neutral}</label>
<div class="searchOptionBlock" id="s_relationship"> <label><input type="radio" form="search_form" n:attr="checked => is_null($_REQUEST['gender']) || $_REQUEST['gender'] == 3" name="gender" data-default='1' value="3">{_s_any}</label>
<select name="maritalstatus" form="searcher">
<option n:foreach="range(0, 8) as $i" value="{$i}" {if $_GET['maritalstatus'] == $i}selected{/if} form="searcher">
{tr("relationship_".$i)}
</option>
</select>
</div> </div>
</div> </div>
<div n:if="$section == 'users'" n:class="search_option, !isset($_REQUEST['polit_views']) && !isset($_REQUEST['marital_status']) ? search_option_hidden">
<div class="searchOption"> <div class="search_option_name">
<div class="searchOptionName" id="n_politViews" onclick="hideParams('politViews')"><img src="/assets/packages/static/openvk/img/hide.png" class="searchHide">{_politViews}</div> <div class='search_option_name_ico'></div>
<div class="searchOptionBlock" id="s_politViews"> {_s_additional}
<select name="politViews" form="searcher"> </div>
<option n:foreach="range(0, 9) as $i" value="{$i}" {if $_GET['politViews'] == $i}selected{/if} form="searcher"> <div class="search_option_content">
<label>
{_politViews}
<select name="polit_views" form="search_form" data-default='0'>
<option n:foreach="range(0, 9) as $i" value="{$i}" n:attr="selected => $_REQUEST['polit_views'] == $i">
{tr("politViews_".$i)} {tr("politViews_".$i)}
</option> </option>
</select> </select>
</label>
<label>
{_relationship}
<select name="marital_status" form="search_form" data-default='0'>
<option n:foreach="range(0, 8) as $i" value="{$i}" n:attr="selected => $_REQUEST['marital_status'] == $i">
{tr("relationship_".$i)}
</option>
</select>
</label>
</div>
</div>
<div n:if="$section == 'videos'" class="search_option">
<div class="search_option_name">
<div class='search_option_name_ico'></div>
{_s_main}
</div>
<div class="search_option_content">
<label>
<input type="checkbox" value='1' name="only_youtube" n:attr="checked => !empty($_REQUEST['only_youtube'])" form="search_form">{_s_only_youtube}
</label>
</div>
</div>
<div n:if="$section == 'audios'" class="search_option">
<div class="search_option_name">
<div class='search_option_name_ico'></div>
{_s_main}
</div>
<div class="search_option_content">
<label>
<input type="checkbox" name="only_performers" n:attr="checked => !empty($_REQUEST['only_performers'])" form="search_form">{_s_only_performers}
</label>
<label>
<input type="checkbox" name="with_lyrics" n:attr="checked => !empty($_REQUEST['with_lyrics'])" form="search_form">{_s_with_lyrics}
</label>
<label>
{_genre}
<select name='genre' form="search_form">
<option n:attr="selected: empty($_REQUEST['genre'])" value="any">{_s_any_single}</option>
<option n:foreach='\openvk\Web\Models\Entities\Audio::genres as $genre' n:attr="selected: $_REQUEST['genre'] == $genre" value="{$genre}">
{$genre}
</option>
</select>
</label>
</div> </div>
</div> </div>
<div class="searchOption"> <input class="button" id="search_reset" type="button" value="{_reset}">
<div class="searchOptionName" id="n_contacts" onclick="hideParams('contacts')"><img src="/assets/packages/static/openvk/img/hide.png" class="searchHide">{_contacts}</div>
<div class="searchOptionBlock" id="s_contacts">
<input type="text" name="email" value="{if !is_null($_GET['email'])}{$_GET['email']}{/if}" form="searcher" placeholder="{_email}">
<input type="text" name="telegram" value="{if !is_null($_GET['telegram'])}{$_GET['telegram']}{/if}" form="searcher" placeholder="{_telegram}"><br id="contacts">
<input type="text" name="site" value="{if !is_null($_GET['site'])}{$_GET['site']}{/if}" form="searcher" placeholder="{_personal_website}"><br id="contacts">
<input type="text" name="address" value="{if !is_null($_GET['address'])}{$_GET['address']}{/if}" form="searcher" placeholder="{_address}">
</div>
</div>
<div class="searchOption">
<div class="searchOptionName" id="n_interests" onclick="hideParams('interests')"><img src="/assets/packages/static/openvk/img/hide.png" class="searchHide">{_interests}</div>
<div class="searchOptionBlock" id="s_interests">
<input type="text" value="{if !is_null($_GET['interests'])}{$_GET['interests']}{/if}" form="searcher" placeholder="{_interests}" name="interests">
<input type="text" value="{if !is_null($_GET['fav_mus'])}{$_GET['fav_mus']}{/if}" form="searcher" placeholder="{_favorite_music}" name="fav_mus">
<input type="text" value="{if !is_null($_GET['fav_films'])}{$_GET['fav_films']}{/if}" form="searcher" placeholder="{_favorite_films}" name="fav_films">
<input type="text" value="{if !is_null($_GET['fav_shows'])}{$_GET['fav_shows']}{/if}" form="searcher" placeholder="{_favorite_shows}" name="fav_shows">
<input type="text" value="{if !is_null($_GET['fav_books'])}{$_GET['fav_books']}{/if}" form="searcher" placeholder="{_favorite_books}" name="fav_books">
<input type="text" value="{if !is_null($_GET['fav_quote'])}{$_GET['fav_quote']}{/if}" form="searcher" placeholder="{_favorite_quotes}" name="fav_quote">
</div>
</div>
{/if}
{if $type == "audios"}
<div class="searchOption">
<div class="searchOptionName" id="n_main_audio" onclick="hideParams('main_audio')"><img src="/assets/packages/static/openvk/img/hide.png" class="searchHide">{_s_main}</div>
<div class="searchOptionBlock" id="s_main_audio">
<label><input type="checkbox" name="only_performers" n:attr="checked => !empty($_GET['only_performers'])" form="searcher">{_s_only_performers}</label><br>
<label><input type="checkbox" name="with_lyrics" n:attr="checked => !empty($_GET['with_lyrics'])" form="searcher">{_s_with_lyrics}</label>
</div>
</div>
{/if}
<input class="button" type="button" id="dnt" value="{_reset}" onclick="resetSearch()">
</div>
{/block} {/block}

View file

@ -467,11 +467,11 @@
</tr> </tr>
<tr n:if="!is_null($user->getHometown())"> <tr n:if="!is_null($user->getHometown())">
<td class="label"><span class="nobold">{_hometown}:</span></td> <td class="label"><span class="nobold">{_hometown}:</span></td>
<td class="data"><a href="/search?type=users&query=&hometown={urlencode($user->getHometown())}">{$user->getHometown()}</a></td> <td class="data"><a href="/search?section=users&q=&hometown={urlencode($user->getHometown())}">{$user->getHometown()}</a></td>
</tr> </tr>
<tr> <tr>
<td class="label"><span class="nobold">{_politViews}:</span></td> <td class="label"><span class="nobold">{_politViews}:</span></td>
<td class="data"><a {if $user->getPoliticalViews() != 0}href="/search?type=users&query=&politViews={$user->getPoliticalViews()}"{/if}>{var $pviews = $user->getPoliticalViews()}{_"politViews_$pviews"}</a></td> <td class="data">{var $pviews = $user->getPoliticalViews()}{_"politViews_$pviews"}</td>
</tr> </tr>
<tr n:if="!is_null($user->getBirthday())"> <tr n:if="!is_null($user->getBirthday())">
<td class="label"><span class="nobold">{_birth_date}:</span></td> <td class="label"><span class="nobold">{_birth_date}:</span></td>
@ -517,7 +517,7 @@
</tr> </tr>
<tr n:if="!is_null($user->getCity())"> <tr n:if="!is_null($user->getCity())">
<td class="label"><span class="nobold">{_city}:</span></td> <td class="label"><span class="nobold">{_city}:</span></td>
<td class="data"><a href="/search?type=users&query=&city={$user->getCity()}">{$user->getCity()}</a></td> <td class="data"><a href="/search?type=section&q=&city={$user->getCity()}">{$user->getCity()}</a></td>
</tr> </tr>
<tr n:if="!is_null($user->getPhysicalAddress())"> <tr n:if="!is_null($user->getPhysicalAddress())">
<td class="label"><span class="nobold">{_address}:</span></td> <td class="label"><span class="nobold">{_address}:</span></td>
@ -535,7 +535,7 @@
{var $interests = explode(", ", $user->getInterests())} {var $interests = explode(", ", $user->getInterests())}
{foreach $interests as $interest} {foreach $interests as $interest}
<a href="/search?type=users&query=&interests={urlencode($interest)}">{$interest}</a>{if $interest != end($interests)},{/if} <span>{$interest}</span>{if $interest != end($interests)},{/if}
{/foreach} {/foreach}
</td> </td>
</tr> </tr>
@ -546,7 +546,7 @@
{var $musics = explode(", ", $user->getFavoriteMusic())} {var $musics = explode(", ", $user->getFavoriteMusic())}
{foreach $musics as $music} {foreach $musics as $music}
<a href="/search?type=audios&query={urlencode($music)}">{$music}</a>{if $music != end($musics)},{/if} <a href="/search?section=audios&q={urlencode($music)}">{$music}</a>{if $music != end($musics)},{/if}
{/foreach} {/foreach}
</td> </td>
</tr> </tr>
@ -556,7 +556,7 @@
{var $films = explode(", ", $user->getFavoriteFilms())} {var $films = explode(", ", $user->getFavoriteFilms())}
{foreach $films as $film} {foreach $films as $film}
<a href="/search?type=users&query=&fav_films={urlencode($film)}">{$film}</a>{if $film != end($films)},{/if} <a href="/search?section=users&q=&fav_films={urlencode($film)}">{$film}</a>{if $film != end($films)},{/if}
{/foreach} {/foreach}
</td> </td>
</tr> </tr>
@ -566,7 +566,7 @@
{var $shows = explode(", ", $user->getFavoriteShows())} {var $shows = explode(", ", $user->getFavoriteShows())}
{foreach $shows as $show} {foreach $shows as $show}
<a href="/search?type=users&query=&fav_shows={urlencode($show)}">{$show}</a>{if $show != end($shows)},{/if} <a href="/search?section=users&q=&fav_shows={urlencode($show)}">{$show}</a>{if $show != end($shows)},{/if}
{/foreach} {/foreach}
</td> </td>
</tr> </tr>
@ -576,7 +576,7 @@
{var $books = explode(", ", $user->getFavoriteBooks())} {var $books = explode(", ", $user->getFavoriteBooks())}
{foreach $books as $book} {foreach $books as $book}
<a href="/search?type=users&query=&fav_books={urlencode($book)}">{$book}</a>{if $book != end($books)},{/if} <a href="/search?section=users&q=&fav_books={urlencode($book)}">{$book}</a>{if $book != end($books)},{/if}
{/foreach} {/foreach}
</td> </td>
</tr> </tr>

View file

@ -36,7 +36,7 @@
</div> </div>
</div> </div>
<div n:if="isset($thisUser) &&! ($compact ?? false)" class="post-menu"> <div n:if="isset($thisUser) &&! ($compact ?? false)" class="post-menu">
<a href="#_comment{$comment->getId()}" class="date">{$comment->getPublicationTime()} <a href="{if $correctLink}{$comment->getTargetURL()}{/if}#_comment{$comment->getId()}" class="date">{$comment->getPublicationTime()}
<span n:if="$comment->getEditTime()" class="edited editedMark">({_edited_short})</span> <span n:if="$comment->getEditTime()" class="edited editedMark">({_edited_short})</span>
</a> </a>
{if !$timeOnly} {if !$timeOnly}
@ -47,7 +47,9 @@
{if $comment->canBeEditedBy($thisUser)} {if $comment->canBeEditedBy($thisUser)}
<a id="editPost" data-id="{$comment->getId()}">{_edit}</a>&nbsp;| <a id="editPost" data-id="{$comment->getId()}">{_edit}</a>&nbsp;|
{/if} {/if}
{if !$no_reply_button}
<a class="comment-reply">{_reply}</a> <a class="comment-reply">{_reply}</a>
{/if}
{if $thisUser->getId() != $comment->getOwner()->getId()} {if $thisUser->getId() != $comment->getOwner()->getId()}
{var $canReport = true} {var $canReport = true}
| <a href="javascript:reportComment()">{_report}</a> | <a href="javascript:reportComment()">{_report}</a>
@ -59,29 +61,11 @@
</a> </a>
</div> </div>
{/if} {/if}
{var $target = "wall"}
{if get_class($comment->getTarget()) == "openvk\Web\Models\Entities\Note"}
{php $target = "note"}
{elseif get_class($comment->getTarget()) == "openvk\Web\Models\Entities\Post"}
{php $target = "wall"}
{elseif get_class($comment->getTarget()) == "openvk\Web\Models\Entities\Photo"}
{php $target = "photo"}
{elseif get_class($comment->getTarget()) == "openvk\Web\Models\Entities\Video"}
{php $target = "video"}
{elseif get_class($comment->getTarget()) == "openvk\Web\Models\Entities\Topic"}
{php $target = "topic"}
{/if}
<span n:if="$compact ?? false"> <span n:if="$compact ?? false">
|&nbsp;<a |&nbsp;<a
{if is_null($linkW)}
href="#_comment{$comment->getId()}" href="#_comment{$comment->getId()}"
{else}
href="{$target}{!is_null($comment->getTarget()) ? $comment->getTarget()->getPrettyId() : $comment->getOwner()->getId()}#_comment{$comment->getId()}"
{/if}
class="date" class="date"
>{$comment->getPublicationTime()}</a> >{$comment->getPublicationTime()}</a>

View file

@ -0,0 +1,6 @@
<div class='content_page_error'>
<span>
<b n:if="!empty($title)">{$title}<br><br></b>
{$description}
</span>
</div>

View file

@ -1,8 +1,8 @@
{var $space = 3} {var $space = $conf->space ?? 3}
{var $pageCount = ceil($conf->count / $conf->perPage)} {var $pageCount = ceil($conf->count / $conf->perPage)}
<div n:if="!($conf->page === 1 && $conf->count <= $conf->perPage)" style="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"> <div n:class="paginator, ($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

@ -162,7 +162,7 @@ class Makima
$result->tiles = [ $result->tiles = [
new ThumbTile(1, 3, $wCover, $maxHeight), new ThumbTile(1, 1, $w, $h0), new ThumbTile(1, 3, $wCover, $maxHeight), new ThumbTile(1, 1, $w, $h0),
new ThumbTile(1, 1, $w, $h1), new ThumbTile(1, 1, $w, $h1),
new ThumbTile(1, 1, $w, $h1), new ThumbTile(1, 1, $w, $h2),
]; ];
} }
break; break;

View file

@ -4,6 +4,10 @@
white-space: nowrap; white-space: nowrap;
} }
.audiosPaddingContainer {
padding: 8px;
}
.overflowedName { .overflowedName {
position: absolute; position: absolute;
z-index: 99; z-index: 99;
@ -31,7 +35,9 @@
height: 46px; height: 46px;
border-bottom: 1px solid #d8d8d8; border-bottom: 1px solid #d8d8d8;
box-shadow: 1px 0px 8px 0px rgba(34, 60, 80, 0.2); box-shadow: 1px 0px 8px 0px rgba(34, 60, 80, 0.2);
position: relative; position: sticky;
top: 0px;
z-index: 1;
} }
.bigPlayer.floating { .bigPlayer.floating {
@ -517,8 +523,14 @@
padding-bottom: 3px; padding-bottom: 3px;
} }
.audiosDiv {
width: 103.1%;
display: flex;
margin: 0px 0px -10px -12px;
}
/* <center> 🤣🤣🤣🤣🤣🤣🤣🤣🤣🤣*/ /* <center> 🤣🤣🤣🤣🤣🤣🤣🤣🤣🤣*/
.audiosDiv center span { .audiosDiv center span, .error_full_wrapper center span {
color: #707070; color: #707070;
margin: 120px 0px !important; margin: 120px 0px !important;
display: block; display: block;
@ -583,10 +595,13 @@
} }
.friendsAudiosList { .friendsAudiosList {
margin-left: -7px;
margin-top: 8px; margin-top: 8px;
} }
.friendsAudiosList > a {
padding-left: 8px;
}
.friendsAudiosList .elem { .friendsAudiosList .elem {
display: flex; display: flex;
padding: 1px 1px; padding: 1px 1px;

View file

@ -97,16 +97,15 @@ h1 {
display: inline-block; display: inline-block;
height: 29px; height: 29px;
padding: 11px 4px 0 7px; padding: 11px 4px 0 7px;
}
.header_navigation .link, .header_navigation .header_divider_stick {
background: url('../img/divider.png') no-repeat; background: url('../img/divider.png') no-repeat;
background-size: 1.5px 41px; background-size: 1.5px 41px;
} }
.header_navigation .nodivider { .page_header.search_expanded .header_navigation .header_divider_stick {
display: inline-block; background: unset;
height: 29px;
padding: 11px 4px 0 7px;
background: none;
background-size: 1.5px 41px;
} }
.header_navigation .link a { .header_navigation .link a {
@ -1852,6 +1851,10 @@ body.scrolled .toTop:hover {
margin-top: -1px; margin-top: -1px;
} }
.paginator.tidy {
float: unset;
}
.paginator-at-bottom { .paginator-at-bottom {
margin-top: -6px; margin-top: -6px;
} }
@ -1995,6 +1998,18 @@ body.scrolled .toTop:hover {
line-height: normal; line-height: normal;
} }
.summaryBar.summaryBarFlex {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.summaryBar.padding {
padding-top: 10px;
padding-bottom: 8px;
height: 23px;
}
.summaryBar .summary { .summaryBar .summary {
color: #45688E; color: #45688E;
font-weight: bold; font-weight: bold;
@ -2498,159 +2513,320 @@ a.poll-retract-vote {
display: none; display: none;
} }
.searchOptions { /* Da search */
overflow: hidden;
width:25.5%; /* Header part */
border-top:1px solid #E5E7E6;
float:right; .header_navigation #search_box {
scrollbar-width: none; display: inline-block;
font-size:12px; height: 29px;
background-color:#f7f7f7; padding: 11px 4px 0 7px;
margin-right: -7px;
} }
.searchBtn { .header_navigation #search_box input[type='search'] {
height: 20px;
background: url('/assets/packages/static/openvk/img/search_icon.png') no-repeat 3px 4px;
background-color: #fff;
padding-left: 18px;
width: 120px;
}
.header_navigation #search_box input[type='search']::-webkit-search-cancel-button {
display: none;
}
.header_navigation #search_box #search_box_fr form, .header_navigation #search_box #search_box_fr #search_and_one_more_wrapper {
display: flex;
}
.header_navigation #search_box #searchBoxFastTips {
display: none;
position: absolute;
background: #fff;
border: 1px solid #d8d8d8;
border-top: unset;
margin-top: -1px;
box-shadow: 2px 3px 4px -1px rgba(34, 60, 80, 0.2);
}
.header_navigation #search_box #searchBoxFastTips a {
display: flex;
flex-direction: row;
gap: 6px;
padding: 5px;
cursor: pointer;
}
.header_navigation #search_box #searchBoxFastTips a b, .header_navigation #search_box #searchBoxFastTips a span {
display: block;
text-transform: initial;
line-height: 12px;
}
.header_navigation #search_box #searchBoxFastTips a:hover {
background: #f3f3f3;
}
.header_navigation #search_box #searchBoxFastTips a .search_tip_info_block {
display: flex;
justify-content: center;
flex-direction: column;
align-items: baseline;
gap: 4px;
}
.header_navigation #search_box #searchBoxFastTips a img {
width: 33px;
height: 33px;
object-fit: cover;
}
.page_header.search_expanded .header_navigation #search_box #searchBoxFastTips.shown {
display: flex;
flex-direction: column;
z-index: 1;
}
.page_header.search_expanded .link {
display: none;
}
.page_header.search_expanded #search_and_one_more_wrapper {
width: 627px;
position: relative;
}
/* не говновёрстка, а пиксель-пёрфект) */
.page_header.search_expanded.search_expanded_at_all #search_and_one_more_wrapper {
width: 547px;
}
.page_header.search_expanded #search_box input[type='search'] {
width: 100%;
}
.header_navigation #search_box select[name='section'], .header_navigation #search_box .search_box_button {
display: none;
}
.page_header.search_expanded select[name='section'] {
display: inline-block !important;
}
.page_header.search_expanded_at_all .search_box_button {
display: inline-block !important;
}
.page_header select[name='section'] {
width: auto;
height: 20px;
position: absolute;
padding: 0px 0px;
right: 0;
text-align: right;
border-left: 0px;
}
.header_navigation #search_box .search_box_button {
border: solid 1px #575757; border: solid 1px #575757;
background-color: #696969; background-color: #696969;
color:white; color: #ffffff;
margin-left: -11px; padding: 1px 0px 1px 0px;
padding-bottom:2px;
width: 80px; width: 80px;
cursor: pointer; cursor: pointer;
box-shadow: 0px 2px 0px 0px rgba(255, 255, 255, 0.18) inset; box-shadow: 0px 2px 0px 0px rgba(255, 255, 255, 0.18) inset;
margin-top: 1px;
} }
.searchBtn:active { .header_navigation #search_box .search_box_button span {
color: white;
font-weight: 600;
font-size: 12px;
}
.header_navigation #search_box .search_box_button:active {
border: solid 1px #666666; border: solid 1px #666666;
background-color: #696969; background-color: #696969;
color:white; color:white;
box-shadow: 0px -2px 0px 0px rgba(255, 255, 255, 0.18) inset; box-shadow: 0px -2px 0px 0px rgba(255, 255, 255, 0.18) inset;
} }
.searchList {
list-style: none;
user-select: none;
padding-left:0px;
}
.searchList #used {
margin-left:0px;
color: white !important;
padding:2px;
padding-top:5px;
padding-bottom:5px;
border: solid 0.125rem #4F4F4F;
background: #606060;
margin-bottom:2px;
padding-left:9px;
width:87%;
}
.searchList #used a {
color: white;
}
.sr:focus {
outline:none;
}
.searchHide { .searchHide {
padding-right: 5px; padding-right: 5px;
} }
.searchList li, .searchList a /* Search layout */
{ #search_page {
display: block; display: flex;
flex-direction: row;
justify-content: space-between;
}
.page_content_paginator_bottom {
background: #f7f7f7;
border-top: 1px solid #d8d8d8;
padding: 8px 8px;
display: flex;
justify-content: right;
}
.page_wrap_content_main {
padding: 3px 3px;
width: 74%;
}
.page_wrap_content_main .def_row_content {
border-bottom: #ECECEC solid 1px;
padding: 3px 1px;
}
.page_wrap_content_main .def_row_content:first-of-type {
padding: 0px 1px 3px 1px;
}
.page_wrap_content_main .search_content:first-of-type .post {
border-top: unset;
padding-top: unset;
}
.page_wrap_content_main .search_content:last-of-type .post, .page_wrap_content_main .def_row_content:last-of-type {
border-bottom: unset;
padding-bottom: unset;
}
.verticalGrayTabsWrapper {
width: 25.5%;
border-top: 1px solid #E5E7E6;
border-left: 1px solid #d8d8d8;
scrollbar-width: none;
font-size: 12px;
background-color:#f7f7f7;
}
.searchList, .verticalGrayTabs {
list-style: none;
user-select: none;
padding-left: 0px;
display: flex;
flex-direction: column;
gap: 1px;
}
.searchList hr, .verticalGrayTabs hr {
width: 153px;
margin-left: 0px; margin-left: 0px;
margin-top: 6px;
}
.verticalGrayTabs.with_padding, .verticalGrayTabs > .with_padding {
padding: 4px 4px 4px 4px;
}
.searchList #used, .verticalGrayTabs #used {
color: #ffffff !important;
padding: 5px 9px 5px 9px;
border: solid 0.125rem #4F4F4F;
background: #606060;
}
.searchList #used a, .verticalGrayTabs #used a {
color: white;
}
.searchList li, .searchList a, .verticalGrayTabs a {
display: block;
font-size: 12px;
color: #2B587A !important; color: #2B587A !important;
cursor: pointer; cursor: pointer;
padding:2px; padding: 5px 9px 5px 9px;
padding-top:5px;
padding-bottom:5px;
margin-bottom:2px;
padding-left:9px;
} }
.searchList li a { .searchList a:hover, .verticalGrayTabs a:hover {
min-width:100%;
}
.searchList a {
min-width: 88%;
}
.searchList a:hover {
margin-left: 0px; margin-left: 0px;
color: #2B587A !important; color: #2B587A !important;
background: #ebebeb; background: #ebebeb;
padding: 2px;
padding-top: 5px;
padding-bottom: 5px;
margin-bottom: 2px;
padding-left: 9px;
width: 89.9%;
} }
.whatFind { /* Options */
color:rgb(128, 128, 128);
background:none; .page_wrap_content .page_search_options {
border:none; padding: 0px 4px 4px 4px;
position:absolute;
width:150px;
cursor:pointer;
right:80px;
text-align:right;
margin-top: 0.5px;
} }
.searchOptionName { .page_wrap_content .page_search_options .search_option {
cursor:pointer;
background-color: #EAEAEA;
padding-left:5px;
padding-top:5px;
padding-bottom:5px;
width: 90%;
font-weight: 600;
color: #585858;
border-bottom: 2px solid #E4E4E4;
}
.searchOption {
user-select: none; user-select: none;
} }
.searchOptionBlock .page_wrap_content .page_search_options .search_option .search_option_name_ico {
{ width: 9px;
height: 8px;
display: inline-block;
background-repeat: no-repeat;
background: url('/assets/packages/static/openvk/img/arrows.png');
}
.page_wrap_content .page_search_options .search_option.search_option_hidden .search_option_name_ico {
background-position: -9px 0px;
}
.page_wrap_content .page_search_options .search_option.search_option_hidden .search_option_content {
display: none;
}
.page_wrap_content .page_search_options .search_option .search_option_name {
cursor: pointer;
background-color: #EAEAEA;
padding: 5px 5px 5px 5px;
font-weight: 600;
color: #585858;
border-bottom: 2px solid #E4E4E4;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.page_wrap_content .page_search_options .search_option .search_option_content {
margin-top: -5px; margin-top: -5px;
padding-top: 10px; padding-top: 10px;
max-width:92%;
padding-bottom: 6px; padding-bottom: 6px;
} }
.searchOptionBlock select .page_wrap_content .page_search_options .search_option .search_option_content label {
{ display: block;
padding-left:7px;
padding-top:3px;
padding-bottom:3px;
cursor:pointer;
} }
.searchOptionBlock input[type=text], input[type=date] .page_wrap_content .page_search_options .search_option .search_option_content select {
{ padding-left: 3px;
padding-top: 3px;
padding-bottom: 3px;
width: 100%;
}
.page_wrap_content .page_search_options #search_reset {
margin-top: 5px;
}
.page_wrap_content .page_search_options .search_option .search_option_content input[type=text], .page_wrap_content .page_search_options .search_option .search_option_content input[type=date] {
margin-bottom: 5px; margin-bottom: 5px;
} }
.borderup .content_page_error {
{ background: white;
border-top:1px solid #E5E7E6; border: #DEDEDE solid 1px;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
} }
#searchInput .content_page_error span {
{ color: #707070;
transition: .3s linear; display: block;
} }
/* Da search end. */
#standaloneCommentBox { #standaloneCommentBox {
position: sticky; position: sticky;
top: 0; top: 0;
@ -2668,52 +2844,6 @@ a.poll-retract-vote {
width: 100%; width: 100%;
} }
.searchTips
{
position: absolute;
background: white;
padding-left: 6px;
padding-right: 6px;
padding-bottom: 6px;
border: 1px solid #C0CAD5;
border-top: 0px;
width: fit-content;
z-index: 666666;
margin-top: -2px;
}
.searchTips td
{
color: black;
padding: 3px;
font-weight: lighter;
position:relative;
}
.searchTips td .desq
{
margin-top: -9px;
}
.restip td a:hover
{
color: black;
font-weight: lighter;
text-decoration: none;
}
.searchTips .restip
{
padding-right: 10px;
cursor: pointer;
user-select: none;
}
.searchTips .restip:hover
{
background: rgb(236, 235, 235);
}
.attachment_note_icon { .attachment_note_icon {
max-width: 9px; max-width: 9px;
} }
@ -3045,26 +3175,12 @@ body.article .floating_sidebar, body.article .page_content {
background: #E9F0F1 !important; background: #E9F0F1 !important;
} }
.searchOptions.newer {
padding-left: 6px;
border-top: unset !important;
height: unset !important;
border-left: 1px solid #d8d8d8;
width: 26% !important;
}
hr { hr {
background-color: #d8d8d8; background-color: #d8d8d8;
border: none; border: none;
height: 1px; height: 1px;
} }
.searchList hr {
width: 153px;
margin-left: 0px;
margin-top: 6px;
}
.showMore, .showMoreAudiosPlaylist { .showMore, .showMoreAudiosPlaylist {
width: 100%; width: 100%;
text-align: center; text-align: center;

BIN
Web/static/img/arrows.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 219 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 184 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 169 B

View file

@ -313,10 +313,14 @@ class bigPlayer {
}) })
u(".bigPlayer .trackInfo b").on("click", (e) => { u(".bigPlayer .trackInfo b").on("click", (e) => {
window.location.assign(`/search?query=${e.currentTarget.innerHTML}&type=audios&only_performers=on`) window.location.assign(`/search?q=${e.currentTarget.innerHTML}&section=audios&only_performers=on`)
}) })
u(document).on("keydown", (e) => { u(document).on("keydown", (e) => {
if(document.activeElement.closest('.page_header')) {
return
}
if(["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", " "].includes(e.key)) { if(["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", " "].includes(e.key)) {
if(document.querySelector(".ovk-diag-cont") != null) if(document.querySelector(".ovk-diag-cont") != null)
return return
@ -644,29 +648,6 @@ document.addEventListener("DOMContentLoaded", function() {
let type = context.dataset.type let type = context.dataset.type
let entity = context.dataset.entity let entity = context.dataset.entity
window.player = new bigPlayer(type, entity, context.dataset.page) window.player = new bigPlayer(type, entity, context.dataset.page)
let bigplayer = document.querySelector('.bigPlayerDetector')
let bigPlayerObserver = new IntersectionObserver(entries => {
entries.forEach(x => {
if(x.isIntersecting) {
document.querySelector('.bigPlayer').classList.remove("floating")
//document.querySelector('.searchOptions .searchList').classList.remove("floating")
document.querySelector('.bigPlayerDetector').style.marginTop = "0px"
} else {
//document.querySelector('.searchOptions .searchList').classList.add("floating")
document.querySelector('.bigPlayer').classList.add("floating")
document.querySelector('.bigPlayerDetector').style.marginTop = "46px"
}
});
}, {
root: null,
rootMargin: "0px",
threshold: 0
});
if(bigplayer != null)
bigPlayerObserver.observe(bigplayer);
} }
$(document).on("mouseover mouseleave", `.audioEntry .mediaInfo`, (e) => { $(document).on("mouseover mouseleave", `.audioEntry .mediaInfo`, (e) => {
@ -795,6 +776,10 @@ function initPlayer(id, keys, url, length) {
try { try {
nextPlayer = thisPlayer.closest(".audio").nextElementSibling.querySelector(".audioEmbed") nextPlayer = thisPlayer.closest(".audio").nextElementSibling.querySelector(".audioEmbed")
} catch(e) {return} } catch(e) {return}
} else if(thisPlayer.closest(".search_content") != null) {
try {
nextPlayer = thisPlayer.closest(".search_content").nextElementSibling.querySelector(".audioEmbed")
} catch(e) {return}
} else { } else {
nextPlayer = thisPlayer.nextElementSibling nextPlayer = thisPlayer.nextElementSibling
} }
@ -899,7 +884,7 @@ $(document).on("click", ".musicIcon.edit-icon", (e) => {
if(response.success) { if(response.success) {
let perf = player.querySelector(".performer a") let perf = player.querySelector(".performer a")
perf.innerHTML = escapeHtml(response.new_info.performer) perf.innerHTML = escapeHtml(response.new_info.performer)
perf.setAttribute("href", "/search?query=&type=audios&sort=id&only_performers=on&query="+response.new_info.performer) perf.setAttribute("href", "/search?q=&section=audios&order=listens&only_performers=on&q="+response.new_info.performer)
e.target.setAttribute("data-performer", escapeHtml(response.new_info.performer)) e.target.setAttribute("data-performer", escapeHtml(response.new_info.performer))

View file

@ -0,0 +1,141 @@
u(`#search_box form input[type="search"]`).on('focus', (e) => {
u('.page_header').addClass('search_expanded')
})
u(`#search_box form input[type="search"]`).on('blur', (e) => {
if(window.openvk.at_search) {
return
}
setTimeout(() => {
if(document.activeElement.closest('.page_header')) {
return
}
u('.page_header').removeClass('search_expanded')
}, 4000)
})
u(document).on('click', '.search_option_name', (e) => {
const target = e.target.closest('.search_option')
// 🤪
$(target.querySelector('.search_option_content')).slideToggle(250, "swing");
setTimeout(() => {
u(target).toggleClass('search_option_hidden')
}, 250)
})
u(document).on('click', '#search_reset', (e) => {
u(`.page_search_options input[type='text']`).nodes.forEach(inp => {
inp.value = ''
})
u(`.page_search_options input[type='checkbox']`).nodes.forEach(chk => {
chk.checked = false
})
u(`.page_search_options input[type='radio']`).nodes.forEach(rad => {
if(rad.dataset.default) {
rad.checked = true
return
}
rad.checked = false
})
u(`.page_search_options select`).nodes.forEach(sel => {
sel.value = sel.dataset.default
})
})
u(`#search_box input[type='search']`).on('input', async (e) => {
if(window.openvk.at_search) {
return
}
const query = u(`#search_box input[type='search']`).nodes[0].value
await new Promise(r => setTimeout(r, 1000));
const current_query = u(`#search_box input[type='search']`).nodes[0].value
const section = u(`#search_box select[name='section']`).nodes[0].value
let results = null
if(/*query.length < 2 || */query != current_query || ['users', 'groups', 'videos'].indexOf(section) == -1) {
return
}
console.info('Ok, getting tips.')
switch(section) {
case 'users':
results = await fetch(`/method/users.search?auth_mechanism=roaming&q=${query}&count=10&sort=4&fields=photo_50,status,nickname`)
break
case 'groups':
results = await fetch(`/method/groups.search?auth_mechanism=roaming&q=${query}&count=10&sort=4&fields=photo_50,description`)
break
case 'videos':
results = await fetch(`/method/video.search?auth_mechanism=roaming&q=${query}&count=10&sort=4&extended=1`)
break
}
json_result = await results.json()
if(!json_result || json_result.error) {
console.error(json_result.error)
return
}
json_result = json_result.response
if(json_result.count < 1) {
console.info('No tips available.')
return
}
switch(section) {
case 'users':
json_result['items'].forEach(item => {
item['name'] = `${item['first_name']}${item['nickname'] ? ` (${item['nickname']})` : ''} ${item['last_name']}`
item['description'] = item['status']
item['url'] = '/id' + item['id']
item['preview'] = item['photo_50']
})
break
case 'groups':
json_result['items'].forEach(item => {
item['url'] = '/club' + item['id']
item['preview'] = item['photo_50']
})
break
case 'videos':
const profiles = json_result['profiles']
const groups = json_result['groups']
json_result['items'].forEach(item => {
item['name'] = item['title']
item['url'] = `/video${item['owner_id']}_${item['id']}`
item['preview'] = item['image'][0]['url']
if(item['owner_id'] > 0) {
const profile = profiles.find(prof => prof.id == item['owner_id'])
if(!profile) { return }
item['description'] = profile['first_name'] + ' ' + profile['last_name']
} else {
const group = groups.find(grou => grou.id == Math.abs(item['owner_id']))
if(!group) { return }
item['description'] = group['name']
}
})
break
}
u('#searchBoxFastTips').addClass('shown')
u('#searchBoxFastTips').html('')
console.log(json_result)
json_result.items.forEach(item => {
u('#searchBoxFastTips').append(`
<a href='${item['url']}'>
<img src='${item['preview']}' class='search_tip_preview_block'>
<div class='search_tip_info_block'>
<b>${ovk_proc_strtr(item['name'].escapeHtml(), 50)}</b>
<span>${ovk_proc_strtr((item['description'] ?? '').escapeHtml(), 60)}</span>
</div>
</a>
`)
})
})

View file

@ -342,6 +342,8 @@ function OpenMiniature(e, photo, post, photo_id, type = "post") {
let data = new FormData() let data = new FormData()
data.append('parentType', type); data.append('parentType', type);
if(type) {
ky.post("/iapi/getPhotosFromPost/" + (type == "post" ? post : "1_"+post), { ky.post("/iapi/getPhotosFromPost/" + (type == "post" ? post : "1_"+post), {
hooks: { hooks: {
afterResponse: [ afterResponse: [
@ -367,6 +369,11 @@ function OpenMiniature(e, photo, post, photo_id, type = "post") {
}, },
body: data body: data
}); });
} else {
imagesCount = 1
__reloadTitleBar()
__loadDetails(photo_id, imagesIndex)
}
return u(".ovk-photo-view-dimmer"); return u(".ovk-photo-view-dimmer");
} }

View file

@ -500,116 +500,22 @@ function escapeHtml(text) {
return text.replace(/[&<>"']/g, function(m) { return map[m]; }); return text.replace(/[&<>"']/g, function(m) { return map[m]; });
} }
function expandSearch() function highlightText(selector, searchText) {
{ const container = u(selector)
// console.log("search expanded") let innerHTML = container.html()
let els = document.querySelectorAll("div.dec") const index = innerHTML.indexOf(searchText)
for(const element of els)
{
element.style.display = "none"
}
document.querySelector(".whatFind").style.display = "block"; if(index >= 0) {
document.querySelector(".whatFind").style.marginRight = "-80px"; innerHTML = innerHTML.substring(0, index) + "<span class='highlight'>" + innerHTML.substring(index, index + searchText.length) + "</span>" + innerHTML.substring(index + searchText.length)
document.getElementById("searchInput").style.width = "627px"; container.html(innerHTML)
document.getElementById("searchInput").style.background = "none";
document.getElementById("searchInput").style.backgroundColor = "#fff";
document.getElementById("searchInput").style.paddingLeft = "6px";
srch.classList.add("nodivider")
}
async function decreaseSearch()
{
// чтобы люди успели выбрать что искать и поиск не скрывался сразу
await new Promise(r => setTimeout(r, 4000));
// console.log("search decreased")
if(document.activeElement !== searchInput && document.activeElement !== typer)
{
srcht.setAttribute("hidden", "hidden")
document.getElementById("searchInput").style.background = "url('/assets/packages/static/openvk/img/search_icon.png') no-repeat 3px 4px";
document.getElementById("searchInput").style.backgroundColor = "#fff";
document.getElementById("searchInput").style.paddingLeft = "18px";
document.getElementById("searchInput").style.width = "120px";
document.querySelector(".whatFind").style.display = "none";
await new Promise(r => setTimeout(r, 300));
srch.classList.remove("nodivider")
let els = document.querySelectorAll("div.dec")
for(const element of els)
{
element.style.display = "inline-block"
}
}
}
function hideParams(name)
{
$("#s_"+name).slideToggle(250, "swing");
if($(`#n_${name} img`).attr("src") == "/assets/packages/static/openvk/img/hide.png")
{
$("#n_"+name+" img").attr("src", "/assets/packages/static/openvk/img/show.png");
} else {
$("#n_"+name+" img").attr("src", "/assets/packages/static/openvk/img/hide.png");
} }
} }
function resetSearch() String.prototype.escapeHtml = function() {
{
let inputs = document.querySelectorAll("input")
let selects = document.querySelectorAll("select")
for(const input of inputs)
{
if(input != dnt && input != gend && input != gend1 && input != gend2) {
input.value = ""
}
}
for(const select of selects)
{
if(select != sortyor && select != document.querySelector(".whatFind")) {
select.value = 0
}
}
}
async function checkSearchTips()
{
let query = searchInput.value;
await new Promise(r => setTimeout(r, 1000));
let type = typer.value;
let smt = type == "users" || type == "groups" || type == "videos";
if(query.length > 3 && query == searchInput.value && smt) {
srcht.removeAttribute("hidden")
let etype = type
try { try {
let results = await API.Search.fastSearch(escapeHtml(query), etype) return escapeHtml(this)
} catch(e) {
srchrr.innerHTML = "" return ''
for(const el of results["items"]) {
srchrr.insertAdjacentHTML("beforeend", `
<tr class="restip" onmouseup="if (event.which === 2) { window.open('${el.url}', '_blank'); } else {location.href='${el.url}'}">
<td>
<img src="${el.avatar}" width="30">
</td>
<td valign="top">
<p class="nameq" style="margin-top: -2px;text-transform:none;">${escapeHtml(el.name)}</p>
<p class="desq" style="text-transform:none;">${escapeHtml(el.description)}</p>
</td>
</tr>
`)
}
} catch(rejection) {
srchrr.innerHTML = tr("no_results")
}
} }
} }

View file

@ -1981,22 +1981,21 @@
"s_people" = "People"; "s_people" = "People";
"s_groups" = "Clubs"; "s_groups" = "Clubs";
"s_events" = "Events";
"s_apps" = "Applications"; "s_apps" = "Applications";
"s_questions" = "Questions";
"s_notes" = "Notes";
"s_themes" = "Themes";
"s_posts" = "Posts"; "s_posts" = "Posts";
"s_comments" = "Comments"; "s_comments" = "Comments";
"s_videos" = "Videos"; "s_videos" = "Videos";
"s_audios" = "Music"; "s_audios" = "Music";
"s_audios_playlists" = "Playlists";
"s_by_people" = "for people"; "s_by_people" = "for people";
"s_by_groups" = "for groups"; "s_by_groups" = "for groups";
"s_by_posts" = "for posts"; "s_by_posts" = "for posts";
"s_by_comments" = "for comments"; "s_by_comments" = "for comments";
"s_by_videos" = "for videos"; "s_by_videos" = "for videos";
"s_by_apps" = "for apps"; "s_by_apps" = "for apps";
"s_by_audios" = "for musics"; "s_by_audios" = "for audios";
"s_by_audios_playlists" = "for playlists";
"s_order_by" = "Order by..."; "s_order_by" = "Order by...";
@ -2007,6 +2006,10 @@
"s_order_by_length" = "By length"; "s_order_by_length" = "By length";
"s_order_by_listens" = "By listens count"; "s_order_by_listens" = "By listens count";
"s_order_invert" = "Invert"; "s_order_invert" = "Invert";
"s_order_by_reg_date" = "By reg date";
"s_order_by_creation_date" = "By creation date";
"s_order_by_publishing_date" = "By publication date;
"s_order_by_upload_date" = "By upload date";
"s_by_date" = "By date"; "s_by_date" = "By date";
"s_registered_before" = "Registered before"; "s_registered_before" = "Registered before";
@ -2019,17 +2022,24 @@
"s_now_on_site" = "now on site"; "s_now_on_site" = "now on site";
"s_with_photo" = "with photo"; "s_with_photo" = "with photo";
"s_only_in_names" = "only in names"; "s_only_in_names" = "only in names";
"s_only_youtube" = "only from YouTube";
"s_any" = "any"; "s_any" = "any";
"s_any_single" = "any";
"reset" = "Reset"; "reset" = "Reset";
"closed_group_post" = "This post was published in a private group"; "closed_group_post" = "This post was published in a private group";
"deleted_target_comment" = "This comment belongs to deleted post"; "deleted_target_comment" = "This comment belongs to deleted post";
"no_results" = "No results"; "no_results" = "No results";
"s_only_performers" = "Performers only"; "s_only_performers" = "By performers";
"s_with_lyrics" = "With lyrics"; "s_with_lyrics" = "With lyrics";
"showing_x_y" = "(showing $1—$2)";
"no_results_by_this_query" = "Nothing was found by this query.";
"s_additional" = "Additional";
"s_it_is_you" = "it is you";
/* BadBrowser */ /* BadBrowser */
"deprecated_browser" = "Deprecated Browser"; "deprecated_browser" = "Deprecated Browser";

View file

@ -1405,7 +1405,7 @@
"no_video_desc" = "Выберите файл или укажите ссылку."; "no_video_desc" = "Выберите файл или укажите ссылку.";
"error_occured" = "Произошла ошибка"; "error_occured" = "Произошла ошибка";
"error_video_damaged_file" = "Файл повреждён или не содержит видео."; "error_video_damaged_file" = "Файл повреждён или не содержит видео.";
"error_video_incorrect_link" = "Возможно, ссылка некорректна."; "error_video_incorrect_link" = "Возможно, ссылка некорректна";
"error_video_no_title" = "Видео не может быть опубликовано без названия."; "error_video_no_title" = "Видео не может быть опубликовано без названия.";
"new_data_video" = "Обновлённое описание появится на странице с видео."; "new_data_video" = "Обновлённое описание появится на странице с видео.";
@ -1871,22 +1871,21 @@
"s_people" = "Люди"; "s_people" = "Люди";
"s_groups" = "Группы"; "s_groups" = "Группы";
"s_events" = "События";
"s_apps" = "Приложения"; "s_apps" = "Приложения";
"s_questions" = "Вопросы";
"s_notes" = "Заметки";
"s_themes" = "Темы";
"s_posts" = "Записи"; "s_posts" = "Записи";
"s_comments" = "Комментарии"; "s_comments" = "Комментарии";
"s_videos" = "Видео"; "s_videos" = "Видео";
"s_audios" = "Аудио"; "s_audios" = "Аудио";
"s_audios_playlists" = "Плейлисты";
"s_by_people" = "по людям"; "s_by_people" = "по людям";
"s_by_groups" = "по группам"; "s_by_groups" = "по группам";
"s_by_posts" = "по записям"; "s_by_posts" = "по записям";
"s_by_comments" = "по комментариям"; "s_by_comments" = "по комментариям";
"s_by_videos" = "по видео"; "s_by_videos" = "по видео";
"s_by_apps" = "по приложениям"; "s_by_apps" = "по приложениям";
"s_by_audios" = "по музыке"; "s_by_audios" = "по аудиозаписям";
"s_by_audios_playlists" = "по плейлистам";
"s_order_by" = "Порядок"; "s_order_by" = "Порядок";
@ -1897,6 +1896,10 @@
"s_order_by_length" = "По длине"; "s_order_by_length" = "По длине";
"s_order_by_listens" = "По числу прослушиваний"; "s_order_by_listens" = "По числу прослушиваний";
"s_order_invert" = "Инвертировать"; "s_order_invert" = "Инвертировать";
"s_order_by_reg_date" = "По дате регистрации";
"s_order_by_creation_date" = "По дате создания";
"s_order_by_publishing_date" = "По дате публикации";
"s_order_by_upload_date" = "По дате загрузки";
"s_by_date" = "По дате"; "s_by_date" = "По дате";
"s_registered_before" = "Зарегистрирован до"; "s_registered_before" = "Зарегистрирован до";
@ -1909,17 +1912,24 @@
"s_now_on_site" = "cейчас на сайте"; "s_now_on_site" = "cейчас на сайте";
"s_with_photo" = "с фото"; "s_with_photo" = "с фото";
"s_only_in_names" = "только в именах"; "s_only_in_names" = "только в именах";
"s_only_youtube" = "только с YouTube";
"s_any" = "любой"; "s_any" = "любые";
"s_any_single" = "любой";
"reset" = "Сброс"; "reset" = "Сброс";
"closed_group_post" = "Эта запись из закрытой группы"; "closed_group_post" = "Эта запись из закрытой группы";
"deleted_target_comment" = "Этот комментарий принадлежит к удалённой записи"; "deleted_target_comment" = "Этот комментарий принадлежит к удалённой записи";
"no_results" = "Результатов нет"; "no_results" = "Результатов нет";
"s_only_performers" = "Только исполнители"; "s_only_performers" = "По исполнителям";
"s_with_lyrics" = "С текстом"; "s_with_lyrics" = "С текстом";
"showing_x_y" = "(показывается $1—$2)";
"no_results_by_this_query" = "По данному запросу ничего не найдено.";
"s_additional" = "Дополнительно";
"s_it_is_you" = "это вы";
/* BadBrowser */ /* BadBrowser */
"deprecated_browser" = "Устаревший браузер"; "deprecated_browser" = "Устаревший браузер";
@ -1997,7 +2007,7 @@
"error_video" = "Произошла ошибка"; "error_video" = "Произошла ошибка";
"file_corrupted" = "Файл повреждён или не содержит видео."; "file_corrupted" = "Файл повреждён или не содержит видео.";
"link_incorrect" = "Возможно, ссылка некорректна."; "link_incorrect" = "Возможно, ссылка некорректна (попробуй убрать параметры по типу &t= или &si=)";
"no_name_error" = "Видео не может быть опубликовано без названия"; "no_name_error" = "Видео не может быть опубликовано без названия";
"access_denied_error" = "Ошибка доступа"; "access_denied_error" = "Ошибка доступа";

View file

@ -1758,11 +1758,7 @@
"s_people" = "Люди"; "s_people" = "Люди";
"s_groups" = "Спільноти"; "s_groups" = "Спільноти";
"s_events" = "Події";
"s_apps" = "Застосунки"; "s_apps" = "Застосунки";
"s_questions" = "Запитання";
"s_notes" = "Нотатки";
"s_themes" = "Теми";
"s_posts" = "Дописи"; "s_posts" = "Дописи";
"s_comments" = "Коментарі"; "s_comments" = "Коментарі";
"s_videos" = "Відео"; "s_videos" = "Відео";

View file

@ -24,8 +24,8 @@ body {
text-shadow: none; text-shadow: none;
} }
.header_navigation .link { .header_navigation .link, .header_navigation .header_divider_stick {
background: unset; background: unset !important;
} }
.header_navigation .link a:hover { .header_navigation .link a:hover {
@ -252,87 +252,30 @@ ul {
background-color:#3c3c3c background-color:#3c3c3c
} }
.searchOptions .search_box_button {
{
overflow-y: hidden;
overflow-x:hidden;
width:25.5%;
border-top:1px solid #2B2B2B;
float:right;
scrollbar-width: none;
font-size:12px;
background-color:#F6F6F6;
margin-right: -7px;
}
.searchBtn
{
border: none;
background-color: #555555;
color: #ffffff;
margin-left: -3px;
padding-bottom: 2px;
width: 80px;
cursor: pointer;
box-shadow: none; box-shadow: none;
} }
.searchBtn:active .search_box_button:active {
{
border: none;
background-color: rgb(77, 77, 77);
color: white;
box-shadow: none; box-shadow: none;
} }
.searchList #used { .verticalGrayTabs #used {
background: #3c3c3c !important; background: #3c3c3c !important;
border: unset !important; border: 1px solid #3c3c3c;
} }
.searchList #used a .verticalGrayTabs #used a {
{
color: white; color: white;
} }
.searchHide .search_option_name {
{
padding-right: 5px;
}
.searchList li:hover
{
margin-left: 0px;
color: #2B587A !important;
background: #eeeeee;
padding: 2px;
padding-top: 5px;
padding-bottom: 5px;
margin-bottom: 2px;
padding-left: 5px;
width: 91%;
}
.searchOptionName
{
cursor: pointer;
background-color: #a4a4a4; background-color: #a4a4a4;
padding-left: 5px; border-bottom: unset;
padding-top: 5px;
padding-bottom: 5px;
width: 90%;
font-weight: 600;
color: #fff;
} }
.searchOptionName img .verticalGrayTabsWrapper {
{ border-top: unset;
display: none;
}
.borderup
{
border-top: 1px solid #2f2f2f;
} }
.sugglist { .sugglist {
@ -371,3 +314,8 @@ ul {
.musicIcon.lagged { .musicIcon.lagged {
opacity: 50%; opacity: 50%;
} }
.bigPlayer {
position: sticky;
top: 42px;
}