Search with parameters

This commit is contained in:
lalka2016 2023-05-24 10:51:08 +03:00
parent 4d996fddac
commit 81da6e1518
18 changed files with 892 additions and 76 deletions

View file

@ -66,4 +66,12 @@ class Applications
{
return sizeof($this->appRels->where("user", $user->getId()));
}
function find(string $query, array $pars = [], string $sort = "id"): Util\EntityStream
{
$query = "%$query%";
$result = $this->apps->where("CONCAT_WS(' ', name, description) LIKE ?", $query)->where("enabled", 1);
return new Util\EntityStream("Application", $result->order("$sort"));
}
}

View file

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

View file

@ -59,4 +59,27 @@ class Comments
"deleted" => false,
]));
}
function find(string $query = "", array $pars = [], string $sort = "id"): Util\EntityStream
{
$query = "%$query%";
$notNullParams = [];
foreach($pars 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) {
!is_null($notNullParams["before"]) ? $result->where("created < ?", $notNullParams["before"]) : NULL;
!is_null($notNullParams["after"]) ? $result->where("created > ?", $notNullParams["after"]) : NULL;
}
return new Util\EntityStream("Comment", $result->order("$sort"));
}
}

View file

@ -99,7 +99,30 @@ class Posts
return NULL;
}
function find(string $query = "", array $pars = [], string $sort = "id"): Util\EntityStream
{
$query = "%$query%";
$notNullParams = [];
foreach($pars as $paramName => $paramValue) {
if($paramName != "before" && $paramName != "after")
$paramValue != NULL ? $notNullParams+=["$paramName" => "%$paramValue%"] : NULL;
else
$paramValue != NULL ? $notNullParams+=["$paramName" => "$paramValue"] : NULL;
}
$result = $this->posts->where("content LIKE ?", $query)->where("deleted", 0);
$nnparamsCount = sizeof($notNullParams);
if($nnparamsCount > 0) {
!is_null($notNullParams["before"]) ? $result->where("created < ?", $notNullParams["before"]) : NULL;
!is_null($notNullParams["after"]) ? $result->where("created > ?", $notNullParams["after"]) : NULL;
}
return new Util\EntityStream("Post", $result->order("$sort"));
}
function getPostCountOnUserWall(int $user): int
{
return sizeof($this->posts->where(["wall" => $user, "deleted" => 0]));

View file

@ -49,12 +49,46 @@ class Users
return $this->toUser($this->users->where("user", $user->getId())->fetch());
}
function find(string $query): Util\EntityStream
function find(string $query, array $pars = [], string $sort = "id DESC"): Util\EntityStream
{
$query = "%$query%";
$result = $this->users->where("CONCAT_WS(' ', first_name, last_name, pseudo, shortcode) LIKE ?", $query)->where("deleted", 0);
return new Util\EntityStream("User", $result);
$notNullParams = [];
$nnparamsCount = 0;
foreach($pars as $paramName => $paramValue) {
if($paramName != "before" && $paramName != "after" && $paramName != "gender")
$paramValue != NULL ? $notNullParams += ["$paramName" => "%$paramValue%"] : NULL;
else
$paramValue != NULL ? $notNullParams += ["$paramName" => "$paramValue"] : NULL;
}
$nnparamsCount = sizeof($notNullParams);
if($nnparamsCount > 0) {
!is_null($notNullParams["hometown"]) ? $result->where("hometown LIKE ?", $notNullParams["hometown"]) : NULL;
!is_null($notNullParams["city"]) ? $result->where("city LIKE ?", $notNullParams["city"]) : NULL;
!is_null($notNullParams["maritalstatus"]) ? $result->where("marital_status LIKE ?", $notNullParams["maritalstatus"]) : NULL;
!is_null($notNullParams["status"]) ? $result->where("status LIKE ?", $notNullParams["status"]) : NULL;
!is_null($notNullParams["politViews"]) ? $result->where("polit_views LIKE ?", $notNullParams["politViews"]) : NULL;
!is_null($notNullParams["email"]) ? $result->where("email_contact LIKE ?", $notNullParams["email"]) : NULL;
!is_null($notNullParams["telegram"]) ? $result->where("telegram LIKE ?", $notNullParams["telegram"]) : NULL;
!is_null($notNullParams["site"]) ? $result->where("website LIKE ?", $notNullParams["site"]) : NULL;
!is_null($notNullParams["address"]) ? $result->where("address LIKE ?", $notNullParams["address"]) : NULL;
!is_null($notNullParams["is_online"]) ? $result->where("online >= ?", time() - 900) : NULL;
!is_null($notNullParams["interests"]) ? $result->where("interests LIKE ?", $notNullParams["interests"]) : NULL;
!is_null($notNullParams["fav_mus"]) ? $result->where("fav_music LIKE ?", $notNullParams["fav_mus"]) : NULL;
!is_null($notNullParams["fav_films"]) ? $result->where("fav_films LIKE ?", $notNullParams["fav_films"]) : NULL;
!is_null($notNullParams["fav_shows"]) ? $result->where("fav_shows LIKE ?", $notNullParams["fav_shows"]) : NULL;
!is_null($notNullParams["fav_books"]) ? $result->where("fav_books LIKE ?", $notNullParams["fav_books"]) : NULL;
!is_null($notNullParams["fav_quote"]) ? $result->where("fav_quote LIKE ?", $notNullParams["fav_quote"]) : NULL;
!is_null($notNullParams["before"]) ? $result->where("UNIX_TIMESTAMP(since) < ?", $notNullParams["before"]) : NULL;
!is_null($notNullParams["after"]) ? $result->where("UNIX_TIMESTAMP(since) > ?", $notNullParams["after"]) : NULL;
!is_null($notNullParams["gender"]) ? $result->where("sex ?", $notNullParams["gender"]) : NULL;
# !is_null($notNullParams["has_avatar"]) ? $result->related(): NULL;
}
return new Util\EntityStream("User", $result->order($sort));
}
function getStatistics(): object

View file

@ -45,4 +45,27 @@ class Videos
{
return sizeof($this->videos->where("owner", $user->getId())->where(["deleted" => 0, "unlisted" => 0]));
}
function find(string $query = "", array $pars = [], string $sort = "id"): Util\EntityStream
{
$query = "%$query%";
$notNullParams = [];
foreach($pars 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("name OR description LIKE ?", $query)->where("deleted", 0);
$nnparamsCount = sizeof($notNullParams);
if($nnparamsCount > 0) {
!is_null($notNullParams["before"]) ? $result->where("created < ?", $notNullParams["before"]) : NULL;
!is_null($notNullParams["after"]) ? $result->where("created > ?", $notNullParams["after"]) : NULL;
}
return new Util\EntityStream("Video", $result->order("$sort"));
}
}

View file

@ -1,18 +1,28 @@
<?php declare(strict_types=1);
namespace openvk\Web\Presenters;
use openvk\Web\Models\Entities\{User, Club};
use openvk\Web\Models\Repositories\{Users, Clubs};
use openvk\Web\Models\Repositories\{Users, Clubs, Posts, Comments, Videos, Applications, Notes};
use Chandler\Database\DatabaseConnection;
final class SearchPresenter extends OpenVKPresenter
{
private $users;
private $clubs;
private $posts;
private $comments;
private $videos;
private $apps;
private $notes;
function __construct(Users $users, Clubs $clubs)
{
$this->users = $users;
$this->clubs = $clubs;
$this->users = $users;
$this->clubs = $clubs;
$this->posts = new Posts;
$this->comments = new Comments;
$this->videos = new Videos;
$this->apps = new Applications;
$this->notes = new Notes;
parent::__construct();
}
@ -21,6 +31,8 @@ final class SearchPresenter extends OpenVKPresenter
{
$query = $this->queryParam("query") ?? "";
$type = $this->queryParam("type") ?? "users";
$sorter = $this->queryParam("sort") ?? "id";
$invert = $this->queryParam("invert") == 1 ? "ASC" : "DESC";
$page = (int) ($this->queryParam("p") ?? 1);
$this->willExecuteWriteAction();
@ -28,11 +40,61 @@ final class SearchPresenter extends OpenVKPresenter
$this->assertUserLoggedIn();
# https://youtu.be/pSAWM5YuXx8
$repos = [ "groups" => "clubs", "users" => "users" ];
$repos = [
"groups" => "clubs",
"users" => "users",
"posts" => "posts",
"comments" => "comments",
"videos" => "videos",
"audios" => "posts",
"apps" => "apps",
"notes" => "notes"
];
switch($sorter) {
default:
case "id":
$sort = "id " . $invert;
break;
case "random":
$sort = "RAND()";
break;
case "name":
$sort = "first_name " . $invert;
break;
case "rating":
$sort = "rating " . $invert;
break;
}
$parameters = [
"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
];
$repo = $repos[$type] or $this->throwError(400, "Bad Request", "Invalid search entity $type.");
$results = $this->{$repo}->find($query);
$results = $this->{$repo}->find($query, $parameters, $sort);
$iterator = $results->page($page);
$count = $results->size();

View file

@ -70,28 +70,60 @@
<a href="/logout?hash={urlencode($csrfToken)}">{_header_log_out}</a>
</div>
{else}
<div class="link">
<div class="link dec">
<a href="/">{_header_home}</a>
</div>
<div class="link">
<div class="link dec">
<a href="/search?type=groups">{_header_groups}</a>
</div>
<div class="link">
<div class="link dec">
<a href="/search">{_header_search}</a>
</div>
<div class="link">
<div class="link dec">
<a href="/invite">{_header_invite}</a>
</div>
<div class="link">
<div class="link dec">
<a href="/support">{_header_help} <b n:if="$ticketAnsweredCount > 0">({$ticketAnsweredCount})</b></a>
</div>
<div class="link">
<div class="link dec">
<a href="/logout?hash={urlencode($csrfToken)}">{_header_log_out}</a>
</div>
<div class="link">
<form action="/search" method="get">
<input 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" />
</form>
{var $atSearch = str_contains($_SERVER['REQUEST_URI'], "/search")}
{if !$atSearch}
<form action="/search" method="get" id="searcher">
<input id="searchInput" 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="type" class="whatFind" style="display:none;">
<option value="users">{_s_by_people}</option>
<option value="groups">{_s_by_groups}</option>
<option value="posts">{_s_by_posts}</option>
<option value="comments">{_s_by_comments}</option>
<option value="videos">{_s_by_videos}</option>
<option value="apps">{_s_by_apps}</option>
</select>
</form>
{else}
<form action="/search" method="get" id="searcher">
<input id="searchInput" value="{$_GET['query'] ?? ''}" type="search" class="sr" 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: 548px;" title="{_header_search} [Alt+Shift+F]" accesskey="f" />
<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>
</select>
<button class="searchBtn">{_search_button}</button>
</form>
<script>
let els = document.querySelectorAll("div.dec")
for(const element of els)
{
element.style.display = "none"
}
</script>
{/if}
</div>
{/if}
{else}

View file

@ -1,11 +1,7 @@
{extends "../@listView.xml"}
{extends "../@layout.xml"}
{block title}
{if $type === "users"}
{tr("search_for_people")}
{else}
{tr("search_for_groups")}
{/if}
{tr("search_for_$type")}
{if $_GET['query']}
- {$_GET['query']}
{/if}
@ -13,41 +9,17 @@
{block header}
{=OPENVK_ROOT_CONF["openvk"]["appearance"]["name"]} »
{if $type === "users"}
{tr("search_for_people")}
{else}
{tr("search_for_groups")}
{/if}
{tr("search_for_$type")}
{/block}
{* BEGIN ELEMENTS DESCRIPTION *}
{block tabs}
<div {if $type === "users"}id="activetabs"{/if} class="tab">
<a {if $type === "users"}id="act_tab_a"{/if} href="/search?type=users{if $_GET['query']}&query={urlencode($_GET['query'])}{/if}">
{_users}
</a>
</div>
<div {if $type === "groups"}id="activetabs"{/if} class="tab">
<a {if $type === "groups"}id="act_tab_a"{/if} href="/search?type=groups{if $_GET['query']}&query={urlencode($_GET['query'])}{/if}">
{_groups}
</a>
</div>
</div>
<form class="header_search_inputbt">
<input name="type" type="hidden" value="{$type ?? 'users'}" />
<input name="query" class="header_search_input" placeholder="{_search_placeholder}" value="{$_GET['query'] ?? ''}" />
<button class="button_search">{_search_button}</button>
</form>
<p style="margin-left: 15px; margin-top: 0;">
<b>{tr("results", $count)}</b>
</p>
<div>
{/block}
{block link|strip|stripHtml}
{$x->getURL()}
{if $type != "apps"}
{$x->getURL()}
{else}
/app{$x->getId()}
{/if}
{/block}
{block preview}
@ -55,17 +27,72 @@
{/block}
{block name}
<text style="overflow: hidden;">&nbsp;{$x->getCanonicalName()}</text>
<img n:if="$x->isVerified()"
class="name-checkmark"
src="/assets/packages/static/openvk/img/checkmark.png"
/>
{if $type != "apps"}
<text style="overflow: hidden;">&nbsp;{$x->getCanonicalName()}
{if $_GET['sort'] == "rating"}({$x->getRating()}%)
{elseif $_GET['sort'] == "id" || $_GET['sort'] == "random"}(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><a href="{$x->getPhysicalAddress()}">{$x->getPhysicalAddress()}</a></td>
</tr>
{/if}
{if $x->getPrivacySetting("page.info.read") > 1}
<tr>
<td><span class="nobold">{_gender}: </span></td>
<td>{$x->isFemale() ? tr("female") : tr("male")}</td>
@ -78,11 +105,14 @@
<td><span class="nobold">{_registration_date}: </span></td>
<td>{$x->getRegistrationTime()}</td>
</tr>
{/if}
{/if}
<tr>
{if $type != "apps"}
<td>
<span class="nobold">{_description}:</span>
</td>
{/if}
<td>
{$x->getDescription() ?? '(' . tr("none") . ')'}
</td>
@ -90,3 +120,220 @@
</tbody>
</table>
{/block}
{block content}
<div style="margin-top:-7px">
{include "../components/paginator.xml", conf => (object) [
"page" => $page,
"count" => $count,
"amount" => sizeof($data),
"perPage" => $perPage ?? OPENVK_DEFAULT_PER_PAGE,
"atBottom" => false,
]}
</div>
<p style="margin-left: 15px; margin-top: 0;">
<b>{tr("results", $count)}</b>
</p>
<div>
{include searchOptions}
{var $data = is_array($iterator) ? $iterator : iterator_to_array($iterator)}
<div class="container_gray" style="float:left;width:68%;border-top:1px solid #E5E7E6">
{if sizeof($data) > 0}
{if $type == "users" || $type == "groups" || $type == "apps"}
<div class="content" n:foreach="$data as $dat">
<table>
<tbody>
<tr>
<td valign="top">
<a href="{include link, x => $dat}">
{include preview, x => $dat}
</a>
</td>
<td valign="top" style="width: 100%">
{ifset infotable}
{include infotable, x => $dat}
{else}
<a href="{include link, x => $dat}">
<b>
{include name, x => $dat}
</b>
</a>
<br/>
{include description, x => $dat}
{/ifset}
</td>
<td n:ifset="actions" valign="top" class="action_links" style="width: 150px;">
{include actions, x => $dat}
</td>
</tr>
</tbody>
</table>
</div>
{elseif $type == "posts"}
{foreach $data as $dat}
{if $dat->getTargetWall() < 0 && $dat->getWallOwner()->isHideFromGlobalFeedEnabled()}
{php continue;}
{* костыль но я по-другому не придумал *}
{else}
<div class="content">
{include "../components/post.xml", post => $dat, commentSection => true, onWallOf => true}
</div>
{/if}
{/foreach}
{elseif $type == "comments"}
<div n:foreach="$data as $dat" class="content">
{include "../components/comment.xml", comment => $dat, linkW => true}
</div>
{elseif $type == "videos"}
{foreach $data as $dat}
{if $dat->getOwner()->isDeleted()}
{php continue;}
{else}
<div class="content">
{include "../components/video.xml", video => $dat}
</div>
{/if}
{/foreach}
{elseif $type == "audios"}
хуй
{/if}
{else}
{ifset customErrorMessage}
{include customErrorMessage}
{else}
{include "../components/nothing.xml"}
{/ifset}
{/if}
</div>
<script>
window.addEventListener("load", (event) => {
document.getElementsByClassName("container_gray")[0].style.minHeight = document.getElementsByClassName("searchOptions")[0].clientHeight+"px";
document.getElementsByClassName("searchOptions")[0].style.minHeight = document.getElementsByClassName("container_gray")[0].clientHeight-3+"px";
})
</script>
{/block}
{block searchOptions}
<div class="searchOptions">
<ul class="searchList">
<li {if $type === "users"} id="used"{/if}><a href="/search?type=users{if $_GET['query']}&query={urlencode($_GET['query'])}{/if}&sort=id"> {_s_people} {if $type === "users"} ({$count}){/if}</a></li>
<li {if $type === "groups"} id="used"{/if}><a href="/search?type=groups{if $_GET['query']}&query={urlencode($_GET['query'])}{/if}&sort=id"> {_s_groups} {if $type === "groups"} ({$count}){/if}</a></li>
<li {if $type === "comments"}id="used"{/if}><a href="/search?type=comments{if $_GET['query']}&query={urlencode($_GET['query'])}{/if}&sort=id">{_s_comments} {if $type === "comments"}({$count}){/if}</a></li>
<li {if $type === "posts"} id="used"{/if}><a href="/search?type=posts{if $_GET['query']}&query={urlencode($_GET['query'])}{/if}&sort=id"> {_s_posts} {if $type === "posts"} ({$count}){/if}</a></li>
<li {if $type === "videos"} id="used"{/if}><a href="/search?type=videos{if $_GET['query']}&query={urlencode($_GET['query'])}{/if}&sort=id"> {_s_videos} {if $type === "videos"} ({$count}){/if}</a></li>
<!--<li {if $type === "audios"}id="used"{/if}><a href="/search?type=audios{if $_GET['query']}&query={urlencode($_GET['query'])}{/if}&sort=id">{_s_audios} {if $type === "audios"} ({$count}){/if}</a></li>-->
<li {if $type === "apps"} id="used"{/if}><a href="/search?type=apps{if $_GET['query']}&query={urlencode($_GET['query'])}{/if}&sort=id"> {_s_apps} {if $type === "apps"} ({$count}){/if}</a></li>
<!--<li {if $type === "notes"}id="used"{/if}><a href="/search?type=notes{if $_GET['query']}&query={urlencode($_GET['query'])}{/if}&sort=id">{_s_notes} {if $type === "notes"}({$count}){/if}</a></li>-->
</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">
<option value="id" {if $_GET["sort"] == "name"}selected{/if}>{_s_order_by_id}</option>
<option value="random" {if $_GET["sort"] == "random"}selected{/if}>{_s_order_by_random}</option>
{if $type == "users"}
<option value="name" {if $_GET["sort"] == "name"}selected{/if}>{_s_order_by_name}</option>
{if OPENVK_ROOT_CONF["preferences"]["commerce"] != "false"}
<option value="rating" {if $_GET["sort"] == "rating"}selected{/if}>{_s_order_by_rating}</option>
{/if}
{/if}
</select>
<input type="checkbox" name="invert" value="1" form="searcher" {if !is_null($_GET['invert']) && $_GET['invert'] == "1"}checked{/if}>{_s_order_invert}
</div>
</div>
{if $type !== "groups" && $type !== "apps"} {*В OpenVK не сохраняется дата создания группы*}
<div class="searchOption">
<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="searchOptionBlock" id="s_dates">
<p id="bydate">{_s_date_before}:<br>
<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>
<p id="bydate">{_s_date_after}:<br>
<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>
{/if}
{if $type === "users"}
<div class="searchOption">
<div class="searchOptionName" id="n_main" onclick="hideParams('main')"><img src="/assets/packages/static/openvk/img/hide.png" class="searchHide">{_main}</div>
<div class="searchOptionBlock" id="s_main">
<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['native_city'])}{$_GET['native_city']}{/if}" form="searcher" placeholder="{_s_native_city}" name="native_city">
</div>
</div>
<div class="searchOption">
<div class="searchOptionName" id="n_gender" onclick="hideParams('gender')"><img src="/assets/packages/static/openvk/img/hide.png" class="searchHide">{_gender}</div>
<div class="searchOptionBlock" id="s_gender">
<p><input type="radio" form="searcher" {if $_GET['gender'] == 0}checked{/if} name="gender" value="0">{_male}</p>
<p><input type="radio" form="searcher" {if $_GET['gender'] == 1}checked{/if} name="gender" value="1">{_female}</p>
<p><input type="radio" form="searcher" {if $_GET['gender'] == 2 || is_null($_GET['gender'])}checked{/if} name="gender" value="2">{_s_any}</p>
</div>
</div>
<div class="searchOption">
<div class="searchOptionName" id="n_relationship" onclick="hideParams('relationship')"><img src="/assets/packages/static/openvk/img/hide.png" class="searchHide">{_relationship}</div>
<div class="searchOptionBlock" id="s_relationship">
<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 class="searchOption">
<div class="searchOptionName" id="n_politViews" onclick="hideParams('politViews')"><img src="/assets/packages/static/openvk/img/hide.png" class="searchHide">{_politViews}</div>
<div class="searchOptionBlock" id="s_politViews">
<select name="politViews" form="searcher">
<option n:foreach="range(0, 9) as $i" value="{$i}" {if $_GET['politViews'] == $i}selected{/if} form="searcher">
{tr("politViews_".$i)}
</option>
</select>
</div>
</div>
<div class="searchOption">
<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>
<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}
<!--<input name="with_photo" type="checkbox" {if !is_null($_GET['with_photo']) && $_GET['with_photo'] == "on"}checked{/if} form="searcher">{_s_with_photo}-->
{/if}
</div>
{/block}

View file

@ -420,11 +420,11 @@
</tr>
<tr n:if="!is_null($user->getHometown())">
<td class="label"><span class="nobold">{_hometown}:</span></td>
<td class="data">{$user->getHometown()}</td>
<td class="data"><a href="/search?type=users&query=&hometown={urlencode($user->getHometown())}">{$user->getHometown()}</a></td>
</tr>
<tr>
<td class="label"><span class="nobold">{_politViews}:</span></td>
<td class="data">{var $pviews = $user->getPoliticalViews()}{_"politViews_$pviews"}</td>
<td class="data"><a href="/search?type=users&query=&politViews={$user->getPoliticalViews()}">{var $pviews = $user->getPoliticalViews()}{_"politViews_$pviews"}</a></td>
</tr>
<tr n:if="!is_null($user->getBirthday())">
<td class="label"><span class="nobold">{_birth_date}:</span></td>
@ -470,7 +470,7 @@
</tr>
<tr n:if="!is_null($user->getCity())">
<td class="label"><span class="nobold">{_city}:</span></td>
<td class="data">{$user->getCity()}</td>
<td class="data"><a href="/search?type=users&query=&city={$user->getCity()}">{$user->getCity()}</a></td>
</tr>
<tr n:if="!is_null($user->getPhysicalAddress())">
<td class="label"><span class="nobold">{_address}:</span></td>
@ -484,23 +484,45 @@
<tbody n:ifcontent>
<tr n:if="!is_null($user->getInterests())">
<td class="label"><span class="nobold">{_interests}: </span></td>
<td class="data">{$user->getInterests()}</td>
<td class="data">
{var $interests = explode(", ", $user->getInterests())}
{foreach $interests as $interest}
<a href="/search?type=users&query=&interests={urlencode($interest)}">{$interest}</a>{if $interest != end($interests)},{/if}
{/foreach}
</td>
</tr>
<tr n:if="!is_null($user->getFavoriteMusic())">
<td class="label"><span class="nobold">{_favorite_music}: </span></td>
<td class="data">{$user->getFavoriteMusic()}</td>
<td class="data">
{var $musics = explode(", ", $user->getFavoriteMusic())}
{foreach $musics as $music}
<a href="/search?type=users&query=&fav_mus={urlencode($music)}">{$music}</a>{if $music != end($musics)},{/if}
{/foreach}</td>
</tr>
<tr n:if="!is_null($user->getFavoriteFilms())">
<td class="label"><span class="nobold">{_favorite_films}: </span></td>
<td class="data">{$user->getFavoriteFilms()}</td>
<td class="data">
{var $films = explode(", ", $user->getFavoriteFilms())}
{foreach $films as $film}
<a href="/search?type=users&query=&fav_films={urlencode($film)}">{$film}</a>{if $film != end($films)},{/if}
{/foreach}</td>
</tr>
<tr n:if="!is_null($user->getFavoriteShows())">
<td class="label"><span class="nobold">{_favorite_shows}: </span></td>
<td class="data">{$user->getFavoriteShows()}</td>
<td class="data">
{var $shows = explode(", ", $user->getFavoriteShows())}
{foreach $shows as $show}
<a href="/search?type=users&query=&fav_shows={urlencode($show)}">{$show}</a>{if $show != end($shows)},{/if}
{/foreach}</td>
</tr>
<tr n:if="!is_null($user->getFavoriteBooks())">
<td class="label"><span class="nobold">{_favorite_books}: </span></td>
<td class="data">{$user->getFavoriteBooks()}</td>
<td class="data">
{var $books = explode(", ", $user->getFavoriteBooks())}
{foreach $books as $book}
<a href="/search?type=users&query=&fav_books={urlencode($book)}">{$book}</a>{if $book != end($books)},{/if}
{/foreach}</td>
</tr>
<tr n:if="!is_null($user->getFavoriteQuote())">
<td class="label"><span class="nobold">{_favorite_quotes}: </span></td>
@ -710,4 +732,4 @@
{else} {* isBanned() *}
{include "banned.xml"}
{/if}
{/block}
{/block}

View file

@ -29,11 +29,12 @@
</div>
</div>
<div n:if="isset($thisUser) &&! ($compact ?? false)" class="post-menu">
<a href="#_comment{$comment->getId()}" class="date">{$comment->getPublicationTime()}</a>&nbsp;|
<a {if is_null($linkW)}href="#_comment{$comment->getId()}"{else}href="wall{!is_null($comment->getTarget()) ? $comment->getTarget()->getPrettyId() : $comment->getOwner()->getId()}#_comment{$comment->getId()}"{/if} class="date">{$comment->getPublicationTime()}</a>&nbsp;|
{if $comment->canBeDeletedBy($thisUser)}
<a href="/comment{$comment->getId()}/delete">{_delete}</a>&nbsp;|
<a href="/comment{$comment->getId()}/delete">{_delete}</a>
{/if}
<a class="comment-reply">{_reply}</a>
{if is_null($linkW)}&nbsp;|
<a class="comment-reply">{_reply}</a>{/if}
<div style="float: right; font-size: .7rem;">
<a class="post-like-button" href="/comment{$comment->getId()}/like?hash={rawurlencode($csrfToken)}">
<div class="heart" style="{if $comment->hasLikeFrom($thisUser)}opacity: 1;{else}opacity: 0.4;{/if}"></div>

View file

@ -0,0 +1,35 @@
<table>
<tbody>
<tr>
<td valign="top">
<div class="video-preview">
<a href="/video{$video->getPrettyId()}">
<img src="{$video->getThumbnailURL()}"
style="max-width: 170px; max-height: 127px; margin: auto;" >
</a>
</div>
</td>
<td valign="top" style="width: 100%">
{ifset infotable}
{include infotable, x => $dat}
{else}
<a href="/video{$video->getPrettyId()}">
<b>
{$video->getName()}
</b>
</a>
<br/>
<p>
<span>{$video->getDescription() ?? ""}</span>
</p>
<span style="color: grey;">{_video_uploaded} {$video->getPublicationTime()}</span><br/>
<p>
<a href="/video{$video->getPrettyId()}">{_view_video}</a>
{if $video->getCommentsCount() > 0}| <a href="/video{$video->getPrettyId()}#comments">{_comments} ({$video->getCommentsCount()})</a>{/if}
</p>
{/ifset}
</td>
</tr>
</tbody>
</table>

View file

@ -2300,3 +2300,153 @@ a.poll-retract-vote {
background-image: url(/assets/packages/static/openvk/img/videoico.png);
display: none;
}
.searchOptions
{
overflow-y: hidden;
background:#F7F7F7;
overflow-x:hidden;
width:29.2%;
border-top:1px solid #E5E7E6;
float:right;
padding-left:9.6px;
scrollbar-width: none;
font-size:12px;
background-color:#f7f7f7;
margin-right: -7px;
}
.searchBtn
{
border: solid 1px #575757;
background-color: #696969;
color:white;
margin-left: -3px;
padding-bottom:2px;
width:80px;
cursor: pointer;
box-shadow: 0px 2px 0px 0px rgba(255, 255, 255, 0.18) inset;
}
.searchBtn:active
{
border: solid 1px #666666;
background-color: #696969;
color:white;
box-shadow: 0px -2px 0px 0px rgba(255, 255, 255, 0.18) inset;
}
.searchList
{
list-style: none;
padding-left:0px;
}
.searchList #used
{
margin-left:0px;
color: white;
padding:2px;
padding-top:5px;
padding-bottom:5px;
border: solid 0.125rem #696969;
background:linear-gradient(#888888,#858585);
margin-bottom:2px;
padding-left:5px;
width:90%;
}
.searchList #used a
{
color: white;
}
.sr:focus
{
outline:none;
}
.searchHide
{
padding-right: 5px;
}
.searchList li
{
margin-left:0px;
color: #2B587A !important;
cursor:pointer;
padding:2px;
padding-top:5px;
padding-bottom:5px;
margin-bottom:2px;
padding-left:5px;
}
.searchList li a
{
min-width:100%;
}
.searchList li:hover
{
margin-left:0px;
color: #2B587A !important;
background:#ebebeb;
padding:2px;
padding-top:5px;
padding-bottom:5px;
margin-bottom:2px;
padding-left:5px;
width:91%;
}
.whatFind
{
color:rgb(128, 128, 128);
background:none;
border:none;
position:absolute;
width:150px;
right:95px;
top:12px;
text-align:right;
}
.searchOptionName
{
cursor:pointer;
background-color: #EAEAEA;
padding-left:5px;
padding-top:5px;
padding-bottom:5px;
width: 90%;
font-weight: 600;
color: #585858;
}
.searchOption
{
user-select: none;
}
.searchOptionBlock
{
margin-top: -5px;
padding-top:10px;
max-width:92%;
padding-bottom:6px;
}
.searchOptionBlock select
{
padding-left:7px;
padding-top:3px;
padding-bottom:3px;
cursor:pointer;
}
.searchOptionBlock input[type=text], input[type=date]
{
margin-bottom:5px;
}

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 B

View file

@ -568,6 +568,50 @@ function deleteAvatar(avatar)
]);
}
function expandSearch()
{
// console.log("search expanded")
let els = document.querySelectorAll("div.dec")
for(const element of els)
{
element.style.display = "none"
}
document.querySelector(".whatFind").style.display = "block";
document.querySelector(".whatFind").style.marginRight = "-80px";
document.getElementById("searchInput").style.width = "650px";
}
async function decreaseSearch()
{
// чтобы люди успели выбрать что искать и поиск не скрывался сразу
await new Promise(r => setTimeout(r, 4000));
// console.log("search decreased")
if(document.activeElement !== searchInput)
{
let els = document.querySelectorAll("div.dec")
for(const element of els)
{
element.style.display = "inline-block"
}
document.querySelector(".whatFind").style.display = "none";
document.getElementById("searchInput").style.width = "120px";
}
}
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");
}
}
$(document).on("scroll", () => {
if($(document).scrollTop() > $(".sidebar").height() + 50) {
$(".floating_sidebar")[0].classList.add("show");

View file

@ -91,6 +91,7 @@
"no_information_provided" = "No information provided.";
"deceased_person" = "Deceased person";
"none" = "none";
"desc_none" = "no description";
"send" = "Send";
"years_zero" = "0 year old";
@ -478,7 +479,12 @@
"apply_style_for_this_device" = "Apply style only for this device";
"search_for_groups" = "Search for groups";
"search_for_people" = "Search for people";
"search_for_users" = "Search for people";
"search_for_posts" = "Search for posts";
"search_for_comments" = "Search for comments";
"search_for_videos" = "Search for videos";
"search_for_apps" = "Search for apps";
"search_for_notes" = "Search for notes";
"search_button" = "Find";
"search_placeholder" = "Start typing any name, title or word";
"results_zero" = "No results";
@ -1450,3 +1456,53 @@
"tour_section_14_bottom_text_1" = "Screenshots";
"tour_section_14_bottom_text_2" = "This concludes the tour of the site. If you want to try our mobile app, create your own group here, invite your friends or find new ones, or just have some fun in general, you can do it right now with a small <a href='/reg'>registration</a>";
"tour_section_14_bottom_text_3" = "This concludes the tour of the site";
/* Search */
"s_people" = "People";
"s_groups" = "Clubs";
"s_events" = "Events";
"s_apps" = "Applications";
"s_questions" = "Questions";
"s_notes" = "Notes";
"s_themes" = "Themes";
"s_posts" = "Posts";
"s_comments" = "Comments";
"s_videos" = "Videos";
"s_audios" = "Music";
"s_by_people" = "for people";
"s_by_groups" = "for groups";
"s_by_posts" = "for posts";
"s_by_comments" = "for comments";
"s_by_videos" = "for videos";
"s_by_apps" = "for apps";
"s_by_audios" = "for musics";
"s_order_by" = "Order by...";
"s_order_by_id" = "By id";
"s_order_by_name" = "By name";
"s_order_by_random" = "By random";
"s_order_by_rating" = "By rating";
"s_order_invert" = "Invert";
"s_by_date" = "By date";
"s_date_before" = "Before";
"s_date_after" = "After";
"s_region" = "Region";
"s_city" = "City";
"s_native_city" = "Hometown";
"s_main" = "Main";
"s_age" = "Age";
"s_sex" = "Sex";
"s_wemen" = "Woman";
"s_man" = "Man";
"s_relationship" = "Relationship";
"s_now_on_site" = "now on site";
"s_with_photo" = "with photo";
"s_only_in_names" = "only in names";
"s_any" = "any";

View file

@ -80,6 +80,7 @@
"no_information_provided" = "Информация отсутствует.";
"deceased_person" = "Страница покойного человека";
"none" = "отсутствует";
"desc_none" = "описание отсутствует";
"send" = "Отправить";
"years_zero" = "0 лет";
"years_one" = "1 год";
@ -452,7 +453,12 @@
"round_avatars" = "Круглые";
"apply_style_for_this_device" = "Применить стиль только для этого устройства";
"search_for_groups" = "Поиск групп";
"search_for_people" = "Поиск людей";
"search_for_users" = "Поиск людей";
"search_for_posts" = "Поиск записей";
"search_for_comments" = "Поиск комментариев";
"search_for_videos" = "Поиск видео";
"search_for_apps" = "Поиск приложений";
"search_for_notes" = "Поиск записок";
"search_button" = "Найти";
"search_placeholder" = "Начните вводить любое имя, название или слово";
"results_zero" = "Ни одного результата";
@ -1343,4 +1349,54 @@
"tour_section_14_bottom_text_1" = "Скриншоты приложения";
"tour_section_14_bottom_text_2" = "На этом экскурсия по сайту завершена. Если вы хотите попробовать наше мобильное приложение, создать здесь свою группу, позвать своих друзей или найти новых, или вообще просто как-нибудь поразвлекаться, то это можно сделать прямо сейчас, пройдя небольшую <a href='/reg'>регистрацию</a>";
"tour_section_14_bottom_text_3" = "На этом экскурсия по сайту завершена."
"tour_section_14_bottom_text_3" = "На этом экскурсия по сайту завершена.";
/* Search */
"s_people" = "Люди";
"s_groups" = "Группы";
"s_events" = "События";
"s_apps" = "Приложения";
"s_questions" = "Вопросы";
"s_notes" = "Заметки";
"s_themes" = "Темы";
"s_posts" = "Записи";
"s_comments" = "Комментарии";
"s_videos" = "Видео";
"s_audios" = "Аудио";
"s_by_people" = "по людям";
"s_by_groups" = "по группам";
"s_by_posts" = "по записям";
"s_by_comments" = "по комментариям";
"s_by_videos" = "по видео";
"s_by_apps" = "по приложениям";
"s_by_audios" = "по музыке";
"s_order_by" = "Порядок";
"s_order_by_id" = "По id";
"s_order_by_name" = "По имени";
"s_order_by_random" = "По случайности";
"s_order_by_rating" = "По рейтингу";
"s_order_invert" = "Инвертировать";
"s_by_date" = "По дате";
"s_date_before" = "До";
"s_date_after" = "После";
"s_region" = "Регион";
"s_city" = "Город";
"s_native_city" = "Родной город";
"s_main" = "Основное";
"s_age" = "Возраст";
"s_sex" = "Пол";
"s_wemen" = "Женский";
"s_man" = "Мужской";
"s_relationship" = "Семейное положение";
"s_now_on_site" = "cейчас на сайте";
"s_with_photo" = "с фото";
"s_only_in_names" = "только в именах";
"s_any" = "любой";