mirror of
https://github.com/openvk/openvk
synced 2025-01-09 01:09:46 +03:00
optimize likes and foto piker & add photo drag
This commit is contained in:
parent
4cb88f94dc
commit
88d3057cf3
19 changed files with 418 additions and 1058 deletions
|
@ -1,92 +0,0 @@
|
|||
<?php declare(strict_types=1);
|
||||
namespace openvk\ServiceAPI;
|
||||
use openvk\Web\Models\Entities\User;
|
||||
use openvk\Web\Models\Repositories\{Photos as PhotosRepo, Albums, Clubs};
|
||||
|
||||
class Photos implements Handler
|
||||
{
|
||||
protected $user;
|
||||
protected $photos;
|
||||
|
||||
function __construct(?User $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->photos = new PhotosRepo;
|
||||
}
|
||||
|
||||
function getPhotos(int $page = 1, int $album = 0, callable $resolve, callable $reject)
|
||||
{
|
||||
if($album == 0) {
|
||||
$photos = $this->photos->getEveryUserPhoto($this->user, $page, 24);
|
||||
$count = $this->photos->getUserPhotosCount($this->user);
|
||||
} else {
|
||||
$album = (new Albums)->get($album);
|
||||
|
||||
if(!$album || $album->isDeleted())
|
||||
$reject(55, "Invalid .");
|
||||
|
||||
if($album->getOwner() instanceof User) {
|
||||
if($album->getOwner()->getId() != $this->user->getId())
|
||||
$reject(555, "Access to album denied");
|
||||
} else {
|
||||
if(!$album->getOwner()->canBeModifiedBy($this->user))
|
||||
$reject(555, "Access to album denied");
|
||||
}
|
||||
|
||||
$photos = $album->getPhotos($page, 24);
|
||||
$count = $album->size();
|
||||
}
|
||||
|
||||
$arr = [
|
||||
"count" => $count,
|
||||
"items" => [],
|
||||
];
|
||||
|
||||
foreach($photos as $photo) {
|
||||
$res = json_decode(json_encode($photo->toVkApiStruct()), true);
|
||||
|
||||
$arr["items"][] = $res;
|
||||
}
|
||||
|
||||
$resolve($arr);
|
||||
}
|
||||
|
||||
function getAlbums(int $club, callable $resolve, callable $reject)
|
||||
{
|
||||
$albumsRepo = (new Albums);
|
||||
|
||||
$count = $albumsRepo->getUserAlbumsCount($this->user);
|
||||
$albums = $albumsRepo->getUserAlbums($this->user, 1, $count);
|
||||
|
||||
$arr = [
|
||||
"count" => $count,
|
||||
"items" => [],
|
||||
];
|
||||
|
||||
foreach($albums as $album) {
|
||||
$res = ["id" => $album->getId(), "name" => $album->getName()];
|
||||
|
||||
$arr["items"][] = $res;
|
||||
}
|
||||
|
||||
if($club > 0) {
|
||||
$cluber = (new Clubs)->get($club);
|
||||
|
||||
if(!$cluber || !$cluber->canBeModifiedBy($this->user))
|
||||
$reject(1337, "Invalid (club), or you can't modify him");
|
||||
|
||||
$clubCount = (new Albums)->getClubAlbumsCount($cluber);
|
||||
$clubAlbums = (new Albums)->getClubAlbums($cluber, 1, $clubCount);
|
||||
|
||||
foreach($clubAlbums as $albumr) {
|
||||
$res = ["id" => $albumr->getId(), "name" => $albumr->getName()];
|
||||
|
||||
$arr["items"][] = $res;
|
||||
}
|
||||
|
||||
$arr["count"] = $arr["count"] + $clubCount;
|
||||
}
|
||||
|
||||
$resolve($arr);
|
||||
}
|
||||
}
|
|
@ -11,6 +11,12 @@ final class Groups extends VKAPIRequestHandler
|
|||
{
|
||||
$this->requireUser();
|
||||
|
||||
# InfoApp fix
|
||||
if($filter == "admin" && ($user_id != 0 && $user_id != $this->getUser()->getId())) {
|
||||
$this->fail(15, 'Access denied: filter admin is available only for current user');
|
||||
}
|
||||
|
||||
$clbs = [];
|
||||
if($user_id == 0) {
|
||||
foreach($this->getUser()->getClubs($offset, $filter == "admin", $count, true) as $club)
|
||||
$clbs[] = $club;
|
||||
|
|
|
@ -427,7 +427,7 @@ final class Photos extends VKAPIRequestHandler
|
|||
$this->fail(15, "Access denied");
|
||||
|
||||
$photos = array_slice(iterator_to_array($album->getPhotos(1, $count + $offset)), $offset);
|
||||
$res["count"] = sizeof($photos);
|
||||
$res["count"] = $album->size();
|
||||
|
||||
foreach($photos as $photo) {
|
||||
if(!$photo || $photo->isDeleted()) continue;
|
||||
|
@ -638,15 +638,15 @@ final class Photos extends VKAPIRequestHandler
|
|||
$this->fail(4, "This method doesn't works with clubs");
|
||||
|
||||
$user = (new UsersRepo)->get($owner_id);
|
||||
|
||||
if(!$user)
|
||||
$this->fail(4, "Invalid user");
|
||||
|
||||
if(!$user->getPrivacyPermission('photos.read', $this->getUser()))
|
||||
$this->fail(21, "This user chose to hide his albums.");
|
||||
|
||||
$photos = array_slice(iterator_to_array((new PhotosRepo)->getEveryUserPhoto($user, 1, $count + $offset)), $offset);
|
||||
$photos = (new PhotosRepo)->getEveryUserPhoto($user, $offset, $count);
|
||||
$res = [
|
||||
"count" => (new PhotosRepo)->getUserPhotosCount($user),
|
||||
"items" => [],
|
||||
];
|
||||
|
||||
|
|
|
@ -87,6 +87,7 @@ class Album extends MediaCollection
|
|||
$res = (object) [];
|
||||
|
||||
$res->id = $this->getPrettyId();
|
||||
$res->vid = $this->getId();
|
||||
$res->thumb_id = !is_null($this->getCoverPhoto()) ? $this->getCoverPhoto()->getPrettyId() : 0;
|
||||
$res->owner_id = $this->getOwner()->getId();
|
||||
$res->title = $this->getName();
|
||||
|
|
|
@ -308,7 +308,7 @@ class Photo extends Media
|
|||
$res->date = $res->created = $this->getPublicationTime()->timestamp();
|
||||
|
||||
if($photo_sizes) {
|
||||
$res->sizes = $this->getVkApiSizes();
|
||||
$res->sizes = array_values($this->getVkApiSizes());
|
||||
$res->src_small = $res->photo_75 = $this->getURLBySizeId("miniscule");
|
||||
$res->src = $res->photo_130 = $this->getURLBySizeId("tiny");
|
||||
$res->src_big = $res->photo_604 = $this->getURLBySizeId("normal");
|
||||
|
|
|
@ -33,7 +33,7 @@ class Photos
|
|||
return new Photo($photo);
|
||||
}
|
||||
|
||||
function getEveryUserPhoto(User $user, int $page = 1, ?int $perPage = NULL): \Traversable
|
||||
function getEveryUserPhoto(User $user, int $offset = 0, int $limit = 10): \Traversable
|
||||
{
|
||||
$perPage = $perPage ?? OPENVK_DEFAULT_PER_PAGE;
|
||||
$photos = $this->photos->where([
|
||||
|
@ -41,7 +41,7 @@ class Photos
|
|||
"deleted" => 0
|
||||
])->order("id DESC");
|
||||
|
||||
foreach($photos->page($page, $perPage) as $photo) {
|
||||
foreach($photos->limit($limit, $offset) as $photo) {
|
||||
yield new Photo($photo);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ final class AudioPresenter extends OpenVKPresenter
|
|||
|
||||
function renderList(?int $owner = NULL, ?string $mode = "list"): void
|
||||
{
|
||||
$this->assertUserLoggedIn();
|
||||
$this->template->_template = "Audio/List.xml";
|
||||
$page = (int)($this->queryParam("p") ?? 1);
|
||||
$audios = [];
|
||||
|
@ -501,6 +502,7 @@ final class AudioPresenter extends OpenVKPresenter
|
|||
|
||||
function renderPlaylist(int $owner_id, int $virtual_id): void
|
||||
{
|
||||
$this->assertUserLoggedIn();
|
||||
$playlist = $this->audios->getPlaylistByOwnerAndVID($owner_id, $virtual_id);
|
||||
$page = (int)($this->queryParam("p") ?? 1);
|
||||
if (!$playlist || $playlist->isDeleted())
|
||||
|
|
|
@ -27,7 +27,12 @@ final class CommentPresenter extends OpenVKPresenter
|
|||
$this->flashFail("err", tr("error"), tr("forbidden"));
|
||||
|
||||
if(!is_null($this->user)) $comment->toggleLike($this->user->identity);
|
||||
|
||||
if($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||
$this->returnJson([
|
||||
'success' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
$this->redirect($_SERVER["HTTP_REFERER"]);
|
||||
}
|
||||
|
||||
|
@ -108,7 +113,7 @@ final class CommentPresenter extends OpenVKPresenter
|
|||
continue;
|
||||
}
|
||||
|
||||
$post->attach($horizontal_attachment);
|
||||
$comment->attach($horizontal_attachment);
|
||||
}
|
||||
|
||||
foreach($vertical_attachments as $vertical_attachment) {
|
||||
|
@ -116,7 +121,7 @@ final class CommentPresenter extends OpenVKPresenter
|
|||
continue;
|
||||
}
|
||||
|
||||
$post->attach($vertical_attachment);
|
||||
$comment->attach($vertical_attachment);
|
||||
}
|
||||
|
||||
if($entity->getOwner()->getId() !== $this->user->identity->getId())
|
||||
|
|
|
@ -287,7 +287,8 @@ final class PhotosPresenter extends OpenVKPresenter
|
|||
"id" => $photo->getId(),
|
||||
"vid" => $photo->getVirtualId(),
|
||||
"owner" => $photo->getOwner()->getId(),
|
||||
"link" => $photo->getURL()
|
||||
"link" => $photo->getURL(),
|
||||
"pretty_id" => $photo->getPrettyId(),
|
||||
];
|
||||
} catch(ISE $ex) {
|
||||
$name = $album->getName();
|
||||
|
|
|
@ -412,6 +412,12 @@ final class WallPresenter extends OpenVKPresenter
|
|||
if(!is_null($this->user)) {
|
||||
$post->toggleLike($this->user->identity);
|
||||
}
|
||||
|
||||
if($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||
$this->returnJson([
|
||||
'success' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
$this->redirect("$_SERVER[HTTP_REFERER]#postGarter=" . $post->getId());
|
||||
}
|
||||
|
|
|
@ -427,6 +427,9 @@
|
|||
window.openvk = {
|
||||
"audio_genres": {\openvk\Web\Models\Entities\Audio::genres},
|
||||
"at_search": {$atSearch ?? false},
|
||||
"max_attachments": {\OPENVK_ROOT_CONF["openvk"]["preferences"]["wall"]["postSizes"]["maxAttachments"]},
|
||||
"max_filesize_mb": 5,
|
||||
"current_id": {$thisUser ? $thisUser->getId() : 0},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -148,7 +148,7 @@
|
|||
|
|
||||
{/if}
|
||||
|
||||
<a n:if="!($forceNoShareLink ?? false)" id="reposts{$post->getPrettyId()}" class="post-share-button" {ifset $thisUser} href="javascript:repostPost('{$post->getPrettyId()}', '{rawurlencode($csrfToken)}')"{/ifset}>
|
||||
<a n:if="!($forceNoShareLink ?? false)" id="reposts{$post->getPrettyId()}" class="post-share-button" {ifset $thisUser} href="javascript:repost('{$post->getPrettyId()}', 'post')"{/ifset}>
|
||||
{_share}
|
||||
{if $repostsCount > 0}
|
||||
(<b id="repostsCount{$post->getPrettyId()}">{$repostsCount}</b>)
|
||||
|
|
|
@ -2,26 +2,18 @@
|
|||
{var $textAreaId = ($post ?? NULL) === NULL ? (++$GLOBALS["textAreaCtr"]) : $post->getId()}
|
||||
{var $textAreaId = ($custom_id ?? NULL) === NULL ? $textAreaId : $custom_id}
|
||||
|
||||
<div id="write" style="padding: 5px 0;" onfocusin="expand_wall_textarea({$textAreaId});">
|
||||
<div id="write" class='model_content_textarea' style="padding: 5px 0;" onfocusin="expand_wall_textarea({$textAreaId});">
|
||||
<form action="{$route}" method="post" enctype="multipart/form-data" style="margin:0;">
|
||||
<textarea id="wall-post-input{$textAreaId}" placeholder="{_write}" name="text" style="width: 100%;resize: none;" class="small-textarea"></textarea>
|
||||
<div>
|
||||
<!-- padding to fix <br/> bug -->
|
||||
</div>
|
||||
<div id="post-buttons{$textAreaId}" style="display: none;">
|
||||
<div class="upload">
|
||||
|
||||
</div>
|
||||
<div class="post-upload">
|
||||
<span style="color: inherit;"></span>
|
||||
</div>
|
||||
<div id="post-buttons{$textAreaId}" class='post-buttons' style="display: none;">
|
||||
<div class="post-horizontal"></div>
|
||||
<div class="post-vertical"></div>
|
||||
<div class="post-has-poll">
|
||||
{_poll}
|
||||
</div>
|
||||
<div class="post-has-note"></div>
|
||||
|
||||
<div class="post-has-videos"></div>
|
||||
<div class="post-has-audios"></div>
|
||||
<div class="post-source"></div>
|
||||
|
||||
<div n:if="$postOpts ?? true" class="post-opts">
|
||||
|
@ -71,15 +63,15 @@
|
|||
<br/>
|
||||
<input type="submit" value="{_write}" class="button" />
|
||||
<div style="float: right; display: flex; flex-direction: column;">
|
||||
<a href="javascript:toggleMenu({$textAreaId});">
|
||||
<a class='menu_toggler'>
|
||||
{_attach}
|
||||
</a>
|
||||
|
||||
<div id="wallAttachmentMenu" class="hidden">
|
||||
<a class="header" href="javascript:toggleMenu({$textAreaId});">
|
||||
<a class="header menu_toggler">
|
||||
{_attach}
|
||||
</a>
|
||||
<a id="photosAttachments" {if !is_null($club ?? NULL) && $club->canBeModifiedBy($thisUser)}data-club="{$club->getId()}"{/if}>
|
||||
<a id="__photoAttachment" {if !is_null($club ?? NULL) && $club->canBeModifiedBy($thisUser)}data-club="{$club->getId()}"{/if}>
|
||||
<img src="/assets/packages/static/openvk/img/oxygen-icons/16x16/mimetypes/application-x-egon.png" />
|
||||
{_photo}
|
||||
</a>
|
||||
|
@ -91,11 +83,11 @@
|
|||
<img src="/assets/packages/static/openvk/img/oxygen-icons/16x16/mimetypes/audio-ac3.png" />
|
||||
{_audio}
|
||||
</a>
|
||||
<a n:if="$graffiti ?? false" href="javascript:initGraffiti({$textAreaId});">
|
||||
<a n:if="$graffiti ?? false" onclick="initGraffiti(event);">
|
||||
<img src="/assets/packages/static/openvk/img/oxygen-icons/16x16/actions/draw-brush.png" />
|
||||
{_graffiti}
|
||||
</a>
|
||||
<a n:if="$polls ?? false" href="javascript:initPoll({$textAreaId})">
|
||||
<a n:if="$polls ?? false" onclick="initPoll(event);">
|
||||
<img src="/assets/packages/static/openvk/img/oxygen-icons/16x16/actions/office-chart-bar-stacked.png" />
|
||||
{_poll}
|
||||
</a>
|
||||
|
@ -110,10 +102,6 @@
|
|||
</div>
|
||||
|
||||
<script>
|
||||
$(document).ready(() => {
|
||||
setupWallPostInputHandlers({$textAreaId});
|
||||
});
|
||||
|
||||
u("#post-buttons{$textAreaId} input[name='horizontal_attachments']")["nodes"].at(0).value = ""
|
||||
u("#post-buttons{$textAreaId} input[name='vertical_attachments']")["nodes"].at(0).value = ""
|
||||
</script>
|
||||
|
|
|
@ -50,6 +50,11 @@ h1 {
|
|||
flex-direction: column;
|
||||
}
|
||||
|
||||
.display_flex_row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.layout {
|
||||
width: 791px;
|
||||
margin: 0 auto;
|
||||
|
@ -264,7 +269,7 @@ h1 {
|
|||
}
|
||||
|
||||
.upLeftErrors {
|
||||
position: absolute;
|
||||
position: fixed;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
z-index: 1025;
|
||||
|
@ -1747,12 +1752,14 @@ body.scrolled .toTop:hover {
|
|||
|
||||
#wallAttachmentMenu {
|
||||
position: absolute;
|
||||
min-width: 94px;
|
||||
border: 1px solid darkgrey;
|
||||
background-color: white;
|
||||
z-index: 32;
|
||||
margin-top: -7px;
|
||||
margin-left: -16px;
|
||||
box-shadow: 0 1px 3px -1px;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
#wallAttachmentMenu>a {
|
||||
|
@ -2406,16 +2413,27 @@ a.poll-retract-vote {
|
|||
}
|
||||
}
|
||||
|
||||
.upload {
|
||||
.post-horizontal {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.upload .upload-item {
|
||||
width: 75px;
|
||||
height: 60px;
|
||||
.post-horizontal {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
gap: 3px;
|
||||
}
|
||||
|
||||
.post-horizontal .upload-item {
|
||||
/*width: 75px;
|
||||
height: 60px;*/
|
||||
overflow: hidden;
|
||||
display: inline-block;
|
||||
margin-right: 3px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.post-horizontal .upload-item.dragged {
|
||||
filter: contrast(0.5);
|
||||
}
|
||||
|
||||
.upload-item .upload-delete {
|
||||
|
@ -2425,7 +2443,7 @@ a.poll-retract-vote {
|
|||
text-decoration: none;
|
||||
color: #fff;
|
||||
font-size: 11px;
|
||||
margin-left: 57px; /* мне лень переделывать :DDDD */
|
||||
right: 0px;
|
||||
opacity: 0;
|
||||
transition: 0.25s;
|
||||
}
|
||||
|
@ -3141,10 +3159,61 @@ body.article .floating_sidebar, body.article .page_content {
|
|||
font-size: 11px;
|
||||
}
|
||||
|
||||
.topGrayBlock {
|
||||
.attachment_selector .topGrayBlock {
|
||||
background: #F0F0F0;
|
||||
height: 37px;
|
||||
border-bottom: 1px solid #C7C7C7;
|
||||
padding: 3px 10px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.attachment_selector .topGrayBlock #albumSelect {
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
.attachment_selector #attachment_insert {
|
||||
padding: 5px;
|
||||
height: 281px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.attachment_selector #attachment_insert #attachment_insert_count {
|
||||
position: fixed;
|
||||
z-index: 1007;
|
||||
width: 92%;
|
||||
background: white;
|
||||
margin-top: -5px;
|
||||
padding-top: 6px;
|
||||
}
|
||||
|
||||
#show_more {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
background: #f0f0f0;
|
||||
height: 22px;
|
||||
padding-top: 9px;
|
||||
cursor: pointer;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
#show_more:hover {
|
||||
background: #f2f2f2;
|
||||
}
|
||||
|
||||
.attachment_selector #attachment_insert .photosList {
|
||||
margin-top: 20px;
|
||||
gap: 3px 6px;
|
||||
}
|
||||
|
||||
.attachment_selector #attachment_insert .photosList .album-photo.selected img {
|
||||
background-color: #646464;
|
||||
}
|
||||
|
||||
.attachment_selector #attachment_insert .photosList .album-photo {
|
||||
width: 15.8%;
|
||||
margin: unset;
|
||||
}
|
||||
|
||||
.edited {
|
||||
|
|
|
@ -64,8 +64,9 @@ function pollRadioPressed(radio) {
|
|||
form.submit();
|
||||
}
|
||||
|
||||
function initPoll(id) {
|
||||
let form = $(`#wall-post-input${id}`).parent();
|
||||
function initPoll(event) {
|
||||
let form = $(event.target.closest('.post-buttons')).parent();
|
||||
const id = random_int(0, 100)
|
||||
|
||||
let mBody = `
|
||||
<div id="poll_editor${id}">
|
||||
|
@ -87,9 +88,9 @@ function initPoll(id) {
|
|||
</div>
|
||||
`;
|
||||
|
||||
MessageBox(tr("create_poll"), mBody, [tr("attach"), tr("cancel")], [
|
||||
const msg = MessageBox(tr("create_poll"), mBody, [tr("attach"), tr("cancel")], [
|
||||
function() {
|
||||
let dialog = $(this.$dialog().nodes[0]);
|
||||
let dialog = $(msg.getNode().nodes[0]);
|
||||
$("input", dialog).unbind();
|
||||
|
||||
let title = $("input[name=title]", dialog).val();
|
||||
|
@ -117,9 +118,9 @@ function initPoll(id) {
|
|||
$(".post-has-poll", form).show();
|
||||
},
|
||||
function() {
|
||||
$("input", $(this.$dialog().nodes[0])).unbind();
|
||||
$("input", $(msg.getNode())).unbind();
|
||||
}
|
||||
]);
|
||||
], true);
|
||||
|
||||
let editor = $(`#poll_editor${id}`);
|
||||
$("input[name=newOption]", editor).bind("focus", function() {
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -46,16 +46,6 @@ function parseAjaxResponse(responseString) {
|
|||
}
|
||||
}
|
||||
|
||||
function toggleMenu(id) {
|
||||
if($(`#post-buttons${id} #wallAttachmentMenu`).is('.hidden')) {
|
||||
$(`#post-buttons${id} #wallAttachmentMenu`).css({ opacity: 0 });
|
||||
$(`#post-buttons${id} #wallAttachmentMenu`).toggleClass('hidden').fadeTo(250, 1);
|
||||
} else {
|
||||
$(`#post-buttons${id} #wallAttachmentMenu`).fadeTo(250, 0, function () {
|
||||
$(this).toggleClass('hidden');
|
||||
});
|
||||
}
|
||||
}
|
||||
document.addEventListener("DOMContentLoaded", function() { //BEGIN
|
||||
|
||||
$(document).on("click", "#_photoDelete", function(e) {
|
||||
|
|
|
@ -107,8 +107,12 @@ function random_int(min, max) {
|
|||
return Math.round(Math.random() * (max - min) + min)
|
||||
}
|
||||
|
||||
function makeError(text, color = 'Red', timeout = 10000) {
|
||||
const rand_id = random_int(0, 10000)
|
||||
function makeError(text, color = 'Red', timeout = 10000, uid = 0) {
|
||||
const rand_id = uid != 0 ? uid : random_int(0, 10000)
|
||||
|
||||
if(uid != 0 && u(`.upLeftErrors .upLeftError[data-id='${uid}']`).length > 0) {
|
||||
return
|
||||
}
|
||||
|
||||
u('.upLeftErrors').append(`
|
||||
<div class='upLeftError upLeftError${color}' data-id='${rand_id}'>${escapeHtml(text)}</div>
|
||||
|
|
|
@ -488,9 +488,10 @@
|
|||
"click_to_go_to_album" = "Нажмите, чтобы перейти к альбому.";
|
||||
"error_uploading_photo" = "Не удалось загрузить фотографию";
|
||||
"too_many_pictures" = "Не больше 10 фотографий";
|
||||
"too_many_attachments" = "Слишком много вложений.";
|
||||
|
||||
"drag_files_here" = "Перетащите файлы сюда";
|
||||
"only_images_accepted" = "Файл \"$1\" не является изображением";
|
||||
"only_images_accepted" = "Файл \"$1\" не является изображением или видео.";
|
||||
"max_filesize" = "Максимальный размер файла — $1 мегабайт";
|
||||
|
||||
"uploading_photos_from_computer" = "Загрузка фотографий с Вашего компьютера";
|
||||
|
|
Loading…
Reference in a new issue