diff --git a/VKAPI/Handlers/Wall.php b/VKAPI/Handlers/Wall.php index 5b6b8d9f..f7c6a9b1 100644 --- a/VKAPI/Handlers/Wall.php +++ b/VKAPI/Handlers/Wall.php @@ -794,6 +794,13 @@ final class Wall extends VKAPIRequestHandler foreach($comment->getChildren() as $attachment) { if($attachment instanceof \openvk\Web\Models\Entities\Photo) { $attachments[] = $this->getApiPhoto($attachment); + } elseif($attachment instanceof \openvk\Web\Models\Entities\Video) { + $attachments[] = $attachment->getApiStructure(); + } elseif($attachment instanceof \openvk\Web\Models\Entities\Note) { + $attachments[] = [ + 'type' => 'note', + 'note' => $attachment->toVkApiStruct() + ]; } elseif($attachment instanceof \openvk\Web\Models\Entities\Audio) { $attachments[] = [ "type" => "audio", @@ -942,10 +949,23 @@ final class Wall extends VKAPIRequestHandler } } - function edit(int $owner_id, int $post_id, string $message = "", string $attachments = "", string $copyright = NULL) { + function edit(int $owner_id, int $post_id, string $message = "", string $attachments = "", string $copyright = NULL, int $explicit = -1, int $from_group = 0, int $signed = 0) { $this->requireUser(); $this->willExecuteWriteAction(); + $parsed_attachments = parseAttachments($attachments, ['photo', 'video', 'note', 'audio']); + $final_attachments = []; + foreach($parsed_attachments as $attachment) { + if($attachment && !$attachment->isDeleted() && $attachment->canBeViewedBy($this->getUser()) && + !(method_exists($attachment, 'getVoters') && $attachment->getOwner()->getId() != $this->getUser()->getId())) { + $final_attachments[] = $attachment; + } + } + + if(empty($message) && sizeof($final_attachments) < 1) { + $this->fail(-66, "Post will be empty, don't saving."); + } + $post = (new PostsRepo)->getPostById($owner_id, $post_id); if(!$post || $post->isDeleted()) @@ -954,28 +974,35 @@ final class Wall extends VKAPIRequestHandler if(!$post->canBeEditedBy($this->getUser())) $this->fail(7, "Access to editing denied"); - if(!empty($message)) + if(!empty($message) || (empty($message) && sizeof($final_attachments) > 0)) $post->setContent($message); $post->setEdited(time()); if(!is_null($copyright) && !empty($copyright)) { - try { - $post->setSource($copyright); - } catch(\Throwable) {} - } - - $post->save(true); - - $parsed_attachments = parseAttachments($attachments, ['photo', 'video', 'note', 'audio']); - $final_attachments = []; - foreach($parsed_attachments as $attachment) { - if($attachment && !$attachment->isDeleted() && $attachment->canBeViewedBy($this->getUser()) && - !(method_exists($attachment, 'getVoters') && $attachment->getOwner()->getId() != $this->getUser()->getId())) { - $final_attachments[] = $attachment; + if($copyright == 'remove') { + $post->resetSource(); + } else { + try { + $post->setSource($copyright); + } catch(\Throwable) {} } } - if(sizeof($final_attachments) > 0) { + if($explicit != -1) { + $post->setNsfw($explicit == 1); + } + + $wallOwner = ($owner_id > 0 ? (new UsersRepo)->get($owner_id) : (new ClubsRepo)->get($owner_id * -1)); + $flags = 0; + if($from_group == 1 && $wallOwner instanceof Club && $wallOwner->canBeModifiedBy($this->getUser())) + $flags |= 0b10000000; + /*if($signed == 1) + $flags |= 0b01000000;*/ + + $post->setFlags($flags); + $post->save(true); + + if($attachments == 'remove' || sizeof($final_attachments) > 0) { $post->unwire(); foreach($final_attachments as $attachment) { $post->attach($attachment); @@ -990,6 +1017,14 @@ final class Wall extends VKAPIRequestHandler $this->willExecuteWriteAction(); $comment = (new CommentsRepo)->get($comment_id); + $parsed_attachments = parseAttachments($attachments, ['photo', 'video', 'note', 'audio']); + $final_attachments = []; + foreach($parsed_attachments as $attachment) { + if($attachment && !$attachment->isDeleted() && $attachment->canBeViewedBy($this->getUser()) && + !(method_exists($attachment, 'getVoters') && $attachment->getOwner()->getId() != $this->getUser()->getId())) { + $final_attachments[] = $attachment; + } + } if(empty($message) && empty($attachments)) $this->fail(100, "Required parameter 'message' missing."); @@ -1000,21 +1035,12 @@ final class Wall extends VKAPIRequestHandler if(!$comment->canBeEditedBy($this->getUser())) $this->fail(15, "Access to editing comment denied"); - if(!empty($message)) + if(!empty($message) || (empty($message) && sizeof($final_attachments) > 0)) $comment->setContent($message); $comment->setEdited(time()); $comment->save(true); - $parsed_attachments = parseAttachments($attachments, ['photo', 'video', 'note', 'audio']); - $final_attachments = []; - foreach($parsed_attachments as $attachment) { - if($attachment && !$attachment->isDeleted() && $attachment->canBeViewedBy($this->getUser()) && - !(method_exists($attachment, 'getVoters') && $attachment->getOwner()->getId() != $this->getUser()->getId())) { - $final_attachments[] = $attachment; - } - } - if(sizeof($final_attachments) > 0) { $comment->unwire(); foreach($final_attachments as $attachment) { diff --git a/Web/Models/Entities/Post.php b/Web/Models/Entities/Post.php index 5d5469d4..6aa09889 100644 --- a/Web/Models/Entities/Post.php +++ b/Web/Models/Entities/Post.php @@ -103,6 +103,11 @@ class Post extends Postable $this->stateChanges("source", $source); } + function resetSource() + { + $this->stateChanges("source", NULL); + } + function getVkApiCopyright(): object { return (object)[ diff --git a/Web/Presenters/InternalAPIPresenter.php b/Web/Presenters/InternalAPIPresenter.php index 901d8d0b..efca2807 100644 --- a/Web/Presenters/InternalAPIPresenter.php +++ b/Web/Presenters/InternalAPIPresenter.php @@ -133,4 +133,33 @@ final class InternalAPIPresenter extends OpenVKPresenter ]); } } + + function renderGetPostTemplate(int $owner_id, int $post_id) { + if($_SERVER["REQUEST_METHOD"] !== "POST") { + header("HTTP/1.1 405 Method Not Allowed"); + exit("ты‍ не по адресу"); + } + + $type = $this->queryParam("type", false); + if($type == "post") { + $post = (new Posts)->getPostById($owner_id, $post_id, true); + } else { + $post = (new Comments)->get($post_id); + } + + if(!$post || !$post->canBeEditedBy($this->user->identity)) { + exit(''); + } + + if($type == 'post') { + $this->template->_template = 'components/post.xml'; + $this->template->post = $post; + $this->template->commentSection = false; + } elseif($type == 'comment') { + $this->template->_template = 'components/comment.xml'; + $this->template->comment = $post; + } else { + exit(''); + } + } } diff --git a/Web/Presenters/templates/components/attachment.xml b/Web/Presenters/templates/components/attachment.xml index 19d63a6b..59925f27 100644 --- a/Web/Presenters/templates/components/attachment.xml +++ b/Web/Presenters/templates/components/attachment.xml @@ -44,12 +44,14 @@ {elseif $attachment instanceof \openvk\Web\Models\Entities\Poll} {presenter "openvk!Poll->view", $attachment->getId()} {elseif $attachment instanceof \openvk\Web\Models\Entities\Note} -
- - -
- {_note} - {ovk_proc_strtr($attachment->getName(), 66)} +
+
{elseif $attachment instanceof \openvk\Web\Models\Entities\Post} @@ -60,7 +62,7 @@ {include "post.xml", post => $attachment, compact => true} {/if} {elseif $attachment instanceof \openvk\Web\Models\Entities\Audio} -
+
{include "../Audio/player.xml", audio => $attachment}
{else} diff --git a/Web/Presenters/templates/components/comment.xml b/Web/Presenters/templates/components/comment.xml index 31e47071..ea39fe34 100644 --- a/Web/Presenters/templates/components/comment.xml +++ b/Web/Presenters/templates/components/comment.xml @@ -5,7 +5,7 @@ {var $postId = $target instanceof \openvk\Web\Models\Entities\Post ? $target->getId() : NULL} - +
diff --git a/Web/Presenters/templates/components/post/microblogpost.xml b/Web/Presenters/templates/components/post/microblogpost.xml index 1c42c073..1facc560 100644 --- a/Web/Presenters/templates/components/post/microblogpost.xml +++ b/Web/Presenters/templates/components/post/microblogpost.xml @@ -18,7 +18,7 @@ {var $commentTextAreaId = $post === NULL ? rand(1,300) : $post->getId()} -
@@ -22,7 +22,7 @@
- {$comment->getText()|noescape} + {$comment->getText()|noescape} {var $attachmentsLayout = $comment->getChildrenWithLayout(288)}
@@ -77,6 +77,7 @@
+
+
@@ -68,15 +68,12 @@ {/if} {if $post->canBeEditedBy($thisUser) && !($forceNoEditLink ?? false) && $compact == false} - getTargetWall() < 0 && $wallOwner->canBeModifiedBy($thisUser)}data-fromgroup="{(int)$post->isPostedOnBehalfOfGroup()}"{/if}> + {/if}
- {$post->getText()|noescape} + {$post->getText()|noescape} {var $width = ($GLOBALS["_bigWall"] ?? false) ? 550 : 320} {if isset($GLOBALS["_nesAttGloCou"])} @@ -112,6 +109,7 @@
+
{$post->getPublicationTime()} ({_edited_short}) diff --git a/Web/Presenters/templates/components/post/oldpost.xml b/Web/Presenters/templates/components/post/oldpost.xml index ff4ec03d..23c44e1d 100644 --- a/Web/Presenters/templates/components/post/oldpost.xml +++ b/Web/Presenters/templates/components/post/oldpost.xml @@ -15,7 +15,7 @@ - +
@@ -71,7 +71,7 @@
{var $owner = $author->getId()} - {$post->getText()|noescape} + {$post->getText()|noescape} {var $width = ($GLOBALS["_bigWall"] ?? false) ? 550 : 320} {if isset($GLOBALS["_nesAttGloCou"])} @@ -119,9 +119,7 @@ {if !($forceNoEditLink ?? false) && $post->canBeEditedBy($thisUser)} getTargetWall() < 0 && $wallOwner->canBeModifiedBy($thisUser)}data-fromgroup="{(int)$post->isPostedOnBehalfOfGroup()}"{/if}>{_edit}  |  + data-id="{$post->getPrettyId()}">{_edit}  |  {/if} {if !($forceNoDeleteLink ?? false) && $canBeDeleted} diff --git a/Web/routes.yml b/Web/routes.yml index 97064d4c..1c1ef075 100644 --- a/Web/routes.yml +++ b/Web/routes.yml @@ -129,8 +129,6 @@ routes: handler: "Wall->rss" - url: "/wall{num}/makePost" handler: "Wall->makePost" - - url: "/wall/edit" - handler: "Wall->edit" - url: "/wall{num}_{num}" handler: "Wall->post" - url: "/wall{num}_{num}/like" @@ -405,6 +403,8 @@ routes: handler: "About->dev" - url: "/iapi/getPhotosFromPost/{num}_{num}" handler: "InternalAPI->getPhotosFromPost" + - url: "/iapi/getPostTemplate/{num}_{num}" + handler: "InternalAPI->getPostTemplate" - url: "/tour" handler: "About->tour" - url: "/{?shortCode}" diff --git a/Web/static/css/main.css b/Web/static/css/main.css index 8d517c6e..656c40da 100644 --- a/Web/static/css/main.css +++ b/Web/static/css/main.css @@ -798,6 +798,14 @@ h4 { font-size: 9px; } +.editing .post-content, .post-edit { + display: none; +} + +.editing .post-edit { + display: block; +} + .post-content .text { padding: 4px; font-size: 11px; @@ -2521,10 +2529,18 @@ a.poll-retract-vote { min-height: 18px; } +.post-vertical .vertical-attachment .audioEntry:hover { + background: unset !important; +} + .post-vertical .vertical-attachment .audioEntry .playerButton { padding: 0px 3px 0px 0px; } +.post-vertical .vertical-attachment .audioEntry .buttons { + display: none; +} + .post-vertical .vertical-attachment .audioEntry .status { margin-top: 1px; margin-left: 2px; @@ -3389,16 +3405,20 @@ body.article .floating_sidebar, body.article .page_content { user-select: none; } -.editMenu.loading { +.edit_menu.loading { filter: opacity(0.5); cursor: progress; user-select: none; } -.editMenu.loading * { +.edit_menu.loading * { pointer-events: none; } +.edit_menu .edit_menu_buttons { + margin-top: 10px; +} + .lagged *, .lagged { pointer-events: none; } @@ -3568,6 +3588,8 @@ hr { width: 100%; position: relative; + margin-left: -2px; + margin-top: -2px; } .compact_video .video-length { diff --git a/Web/static/js/al_api.js b/Web/static/js/al_api.js index d5791ed0..6422ebbd 100644 --- a/Web/static/js/al_api.js +++ b/Web/static/js/al_api.js @@ -42,7 +42,7 @@ window.OVKAPI = new class { return } - const url = `/method/${method}?auth_mechanism=roaming&${new URLSearchParams(params).toString()}` + const url = `/method/${method}?auth_mechanism=roaming&${new URLSearchParams(params).toString()}&v=5.200` const res = await fetch(url) const json_response = await res.json() diff --git a/Web/static/js/al_wall.js b/Web/static/js/al_wall.js index a4b14bfe..7d414931 100644 --- a/Web/static/js/al_wall.js +++ b/Web/static/js/al_wall.js @@ -459,11 +459,16 @@ u(document).on('click', '#videoOpen', (e) => { } }) -u("#write > form").on("keydown", function(event) { +u(document).on("keydown", "#write > form", function(event) { if(event.ctrlKey && event.keyCode === 13) this.submit(); }); +u(document).on('keydown', '.edit_menu #write', (e) => { + if(e.ctrlKey && e.keyCode === 13) + e.target.closest('.edit_menu').querySelector('#__edit_save').click() +}) + function reportPhoto(photo_id) { uReportMsgTxt = tr("going_to_report_photo"); uReportMsgTxt += "
"+tr("report_question_text"); @@ -587,112 +592,199 @@ async function showArticle(note_id) { u("body").addClass("article"); } -$(document).on("click", "#editPost", (e) => { - let post = e.currentTarget.closest("table") - let content = post.querySelector(".text") - let text = content.querySelector(".really_text") +u(document).on("click", "#editPost", async (e) => { + const target = u(e.target) + const post = target.closest("table") + const content = post.find(".post-content") + const edit_place = post.find('.post-edit') + const id = post.attr('data-id').split('_') - if(content.querySelector("textarea") == null) { - content.insertAdjacentHTML("afterbegin", ` -
-
- - - -
- ${e.currentTarget.dataset.nsfw != null ? ` -
- + let type = 'post' + if(post.hasClass('comment')) { + type = 'comment' + } + + if(post.hasClass('editing')) { + post.removeClass('editing') + return + } + + if(edit_place.html() == '') { + target.addClass('lagged') + const params = {} + if(type == 'post') { + params['posts'] = post.attr('data-id') + } else { + params['owner_id'] = 1 + params['comment_id'] = id[1] + } + + const api_req = await window.OVKAPI.call(`wall.${type == 'post' ? 'getById' : 'getComment'}`, params) + const api_post = api_req.items[0] + + edit_place.html(` +
+
+ + +
+
+
+
+ +
+ ${type == 'post' ? `` : ''} + + ${api_post.owner_id < 0 && api_post.can_pin ? `` : ''} +
+ + + +
- ` : ``} - ${e.currentTarget.dataset.fromgroup != null ? ` -
- -
- ` : ``} -
- `) + +
`) - u(content.querySelector("#cancelEditing")).on("click", () => {post.querySelector("#editPost").click()}) - u(content.querySelector("#endEditing")).on("click", () => { - let nwcntnt = content.querySelector("#new_content").value - let type = "post" + if(api_post.copyright) { + edit_place.find('.post-source').html(` + ${tr('source')}: ${escapeHtml(api_post.copyright.link)} +
+ `) - if(post.classList.contains("comment")) { - type = "comment" - } + edit_place.find('.post-source #remove_source_button').on('click', (e) => { + edit_place.find('.post-source').html('') + edit_place.find(`input[name='source']`).attr('value', 'remove') + }) + } + // horizontal attachments + api_post.attachments.forEach(att => { + const type = att.type + const aid = att[type].owner_id + '_' + att[type].id - let xhr = new XMLHttpRequest() - xhr.open("POST", "/wall/edit") + if(type == 'video' || type == 'photo') { + let preview = '' - xhr.onloadstart = () => { - content.querySelector(".editMenu").classList.add("loading") - } - - xhr.onerror = () => { - MessageBox(tr("error"), "unknown error occured", [tr("ok")], [() => {Function.noop}]) - } - - xhr.ontimeout = () => { - MessageBox(tr("error"), "Try to refresh page", [tr("ok")], [() => {Function.noop}]) - } - - xhr.onload = () => { - let result = JSON.parse(xhr.responseText) - - if(result.error == "no") { - post.querySelector("#editPost").click() - content.querySelector(".really_text").innerHTML = result.new_content - - if(post.querySelector(".editedMark") == null) { - post.querySelector(".date").insertAdjacentHTML("beforeend", ` - (${tr("edited_short")}) - `) - } - - if(e.currentTarget.dataset.nsfw != null) { - e.currentTarget.setAttribute("data-nsfw", result.nsfw) - - if(result.nsfw == 0) { - post.classList.remove("post-nsfw") - } else { - post.classList.add("post-nsfw") - } - } - - if(e.currentTarget.dataset.fromgroup != null) { - e.currentTarget.setAttribute("data-fromgroup", result.from_group) - } - - post.querySelector(".post-avatar").setAttribute("src", result.author.avatar) - post.querySelector(".post-author-name").innerHTML = result.author.name.escapeHtml() - post.querySelector(".really_text").setAttribute("data-text", result.new_text) + if(type == 'photo') { + preview = att[type].sizes[1].url } else { - MessageBox(tr("error"), result.error, [tr("ok")], [Function.noop]) - post.querySelector("#editPost").click() + preview = att[type].image[0].url } - } - xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); - xhr.send("postid="+e.currentTarget.dataset.id+ - "&newContent="+nwcntnt+ - "&hash="+encodeURIComponent(u("meta[name=csrf]").attr("value"))+ - "&type="+type+ - "&nsfw="+(content.querySelector("#nswfw") != null ? content.querySelector("#nswfw").checked : 0)+ - "&fromgroup="+(content.querySelector("#fromgroup") != null ? content.querySelector("#fromgroup").checked : 0)) + __appendToTextarea({ + 'type': type, + 'preview': preview, + 'id': aid + }, edit_place) + } else { + const found_block = post.find(`div[data-att_type='${type}'][data-att_id='${aid}']`) + __appendToTextarea({ + 'type': type, + 'alignment': 'vertical', + 'html': found_block.html(), + 'id': aid, + }, edit_place) + } }) - u(".editMenu").on("keydown", (e) => { - if(e.ctrlKey && e.keyCode === 13) - content.querySelector("#endEditing").click() - }); + target.removeClass('lagged') - text.style.display = "none" - setupWallPostInputHandlers(999) - } else { - u(content.querySelector(".editMenu")).remove() - text.style.display = "block" + edit_place.find('.edit_menu #__edit_save').on('click', async (e) => { + const text_node = edit_place.find('.edit_menu textarea') + const nsfw_mark = edit_place.find(`.edit_menu input[name='nsfw']`) + const as_group = edit_place.find(`.edit_menu input[name='as_group']`) + const copyright = edit_place.find(`.edit_menu input[name='source']`) + const collected_attachments = collect_attachments(edit_place.find('.post-buttons')).join(',') + const params = {} + + params['owner_id'] = id[0] + params['post_id'] = id[1] + params['message'] = text_node.nodes[0].value + + if(nsfw_mark.length > 0) { + params['explicit'] = Number(nsfw_mark.nodes[0].checked) + } + + params['attachments'] = collected_attachments + if(collected_attachments.length < 1) { + params['attachments'] = 'remove' + } + + if(as_group.length > 0 && as_group.nodes[0].checked) { + params['from_group'] = 1 + } + + if(copyright.nodes[0].value != 'none') { + params['copyright'] = copyright.nodes[0].value + } + + u(e.target).addClass('lagged') + // больше двух запросов ! + try { + if(type == 'post') { + await window.OVKAPI.call('wall.edit', params) + } else { + params['comment_id'] = id[1] + await window.OVKAPI.call('wall.editComment', params) + } + } catch(e) { + fastError(e.message) + u(e.target).removeClass('lagged') + return + } + + const new_post_html = await (await fetch(`/iapi/getPostTemplate/${id[0]}_${id[1]}?type=${type}`, { + 'method': 'POST' + })).text() + u(e.target).removeClass('lagged') + post.removeClass('editing') + post.nodes[0].outerHTML = new_post_html + }) + + edit_place.find('.edit_menu #__edit_cancel').on('click', (e) => { + post.removeClass('editing') + }) } + + post.addClass('editing') }) async function __uploadToTextarea(file, textareaNode) { @@ -758,6 +850,21 @@ async function __appendToTextarea(attachment_obj, textareaNode) { const form = textareaNode.find('.post-buttons') const indicator = textareaNode.find('.post-horizontal') + if(attachment_obj.alignment == 'vertical') { + textareaNode.find('.post-vertical').append(` +
+
+ ${attachment_obj.html} +
+
+
+
+
+ `) + + return + } + indicator.append(` × @@ -767,28 +874,30 @@ async function __appendToTextarea(attachment_obj, textareaNode) { `) } -// ajax не буде работать - -u('#write .small-textarea').on('paste', (e) => { +u(document).on('paste', '#write .small-textarea', (e) => { if(e.clipboardData.files.length === 1) { __uploadToTextarea(e.clipboardData.files[0], u(e.target).closest('#write')) return; } }) -u('#write').on('dragstart', '.post-horizontal .upload-item, .post-vertical .upload-item', (e) => { +u(document).on('dragstart', '#write .post-horizontal .upload-item, .post-vertical .upload-item', (e) => { //e.preventDefault() //console.log(e) u(e.target).closest('.upload-item').addClass('currently_dragging') return }) -u('#write').on('dragover', '.post-horizontal .upload-item, .post-vertical .upload-item', (e) => { +u(document).on('dragover', '#write .post-horizontal .upload-item, .post-vertical .upload-item', (e) => { e.preventDefault() const target = u(e.target).closest('.upload-item') const current = u('.upload-item.currently_dragging') + if(current.length < 1) { + return + } + if(target.nodes[0].dataset.id != current.nodes[0].dataset.id) { target.addClass('dragged') } @@ -796,13 +905,13 @@ u('#write').on('dragover', '.post-horizontal .upload-item, .post-vertical .uploa return }) -u('#write').on('dragleave dragend', '.post-horizontal .upload-item, .post-vertical .upload-item', (e) => { +u(document).on('#write dragleave dragend', '.post-horizontal .upload-item, .post-vertical .upload-item', (e) => { //console.log(e) u(e.target).closest('.upload-item').removeClass('dragged') return }) -u('#write').on("drop", function(e) { +u(document).on("drop", '#write', function(e) { const current = u('.upload-item.currently_dragging') //console.log(e) if(e.dataTransfer.types.includes('Files')) { @@ -1250,7 +1359,7 @@ u(document).on('click', '#__notesAttachment', async (e) => {
${tr('note')} - ${ovk_proc_strtr(dataset.name, 66)} + ${ovk_proc_strtr(escapeHtml(dataset.name), 66)}
diff --git a/Web/static/js/utils.js b/Web/static/js/utils.js index 93c5c5b2..010ebf18 100644 --- a/Web/static/js/utils.js +++ b/Web/static/js/utils.js @@ -157,3 +157,19 @@ function find_author(id, profiles, groups) return null } + +function collect_attachments(target) { + const horizontal_array = [] + const horizontal_attachments = target.find(`.post-horizontal > a`) + horizontal_attachments.nodes.forEach(_node => { + horizontal_array.push(`${_node.dataset.type}${_node.dataset.id}`) + }) + + const vertical_array = [] + const vertical_attachments = target.find(`.post-vertical > .vertical-attachment`) + vertical_attachments.nodes.forEach(_node => { + vertical_array.push(`${_node.dataset.type}${_node.dataset.id}`) + }) + + return horizontal_array.concat(vertical_array) +} diff --git a/locales/en.strings b/locales/en.strings index eae93644..93482b44 100644 --- a/locales/en.strings +++ b/locales/en.strings @@ -505,6 +505,7 @@ "click_to_go_to_album" = "Click here to go to album."; "error_uploading_photo" = "Error when uploading photo"; "too_many_pictures" = "No more than 10 pictures"; +"too_many_attachments" = "Too many attachments."; "drag_files_here" = "Drag files here"; "only_images_accepted" = "File \"$1\" is not an image"; diff --git a/locales/ru.strings b/locales/ru.strings index 4ed85015..4ddc7a91 100644 --- a/locales/ru.strings +++ b/locales/ru.strings @@ -1468,7 +1468,7 @@ "error_adding_source_regex" = "Ошибка добавления источника: некорректная ссылка."; "error_adding_source_long" = "Ошибка добавления источника: слишком длинная ссылка."; -"error_adding_source_sus" = "Ошибка добавления источника: подозрительная ссылка."; +"error_adding_source_sus" = "Ошибка добавления источника: гиперссылка заблокирована."; /* Admin actions */