allow to change attachments when editin post

This commit is contained in:
mrilyew 2024-11-09 23:35:17 +03:00
parent e5c114c6cf
commit 55bc872046
14 changed files with 361 additions and 154 deletions

View file

@ -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,30 +949,10 @@ 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();
$post = (new PostsRepo)->getPostById($owner_id, $post_id);
if(!$post || $post->isDeleted())
$this->fail(102, "Invalid post");
if(!$post->canBeEditedBy($this->getUser()))
$this->fail(7, "Access to editing denied");
if(!empty($message))
$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) {
@ -975,7 +962,47 @@ final class Wall extends VKAPIRequestHandler
}
}
if(sizeof($final_attachments) > 0) {
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())
$this->fail(102, "Invalid post");
if(!$post->canBeEditedBy($this->getUser()))
$this->fail(7, "Access to editing denied");
if(!empty($message) || (empty($message) && sizeof($final_attachments) > 0))
$post->setContent($message);
$post->setEdited(time());
if(!is_null($copyright) && !empty($copyright)) {
if($copyright == 'remove') {
$post->resetSource();
} else {
try {
$post->setSource($copyright);
} catch(\Throwable) {}
}
}
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) {

View file

@ -103,6 +103,11 @@ class Post extends Postable
$this->stateChanges("source", $source);
}
function resetSource()
{
$this->stateChanges("source", NULL);
}
function getVkApiCopyright(): object
{
return (object)[

View file

@ -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('');
}
}
}

View file

@ -44,6 +44,7 @@
{elseif $attachment instanceof \openvk\Web\Models\Entities\Poll}
{presenter "openvk!Poll->view", $attachment->getId()}
{elseif $attachment instanceof \openvk\Web\Models\Entities\Note}
<div data-att_type='note' data-att_id="{$attachment->getPrettyId()}">
<div class="attachment_note">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 8 10"><polygon points="0 0 0 10 8 10 8 4 4 4 4 0 0 0"/><polygon points="5 0 5 3 8 3 5 0"/></svg>
@ -52,6 +53,7 @@
<span class="attachment_note_name"><a href="javascript:void(showArticle({$attachment->getId()}));">{ovk_proc_strtr($attachment->getName(), 66)}</a></span>
</div>
</div>
</div>
{elseif $attachment instanceof \openvk\Web\Models\Entities\Post}
{php $GLOBALS["_nesAttGloCou"] = (isset($GLOBALS["_nesAttGloCou"]) ? $GLOBALS["_nesAttGloCou"] : 0) + 1}
{if $GLOBALS["_nesAttGloCou"] > 2}
@ -60,7 +62,7 @@
{include "post.xml", post => $attachment, compact => true}
{/if}
{elseif $attachment instanceof \openvk\Web\Models\Entities\Audio}
<div style="width:100%;">
<div style="width:100%;" data-att_type='audio' data-att_id="{$attachment->getPrettyId()}">
{include "../Audio/player.xml", audio => $attachment}
</div>
{else}

View file

@ -5,7 +5,7 @@
{var $postId = $target instanceof \openvk\Web\Models\Entities\Post ? $target->getId() : NULL}
<a name="cid={$comment->getId()}"></a>
<table border="0" style="font-size: 11px;" class="post comment" id="_comment{$comment->getId()}" data-comment-id="{$comment->getId()}" data-owner-id="{$author->getId()}" data-from-group="{$author instanceof $Club}" n:attr="data-post-id => $postId">
<table data-id="1_{$comment->getId()}" border="0" style="font-size: 11px;" class="post comment" id="_comment{$comment->getId()}" data-comment-id="{$comment->getId()}" data-owner-id="{$author->getId()}" data-from-group="{$author instanceof $Club}" n:attr="data-post-id => $postId">
<tbody>
<tr>
<td width="30" valign="top">
@ -22,7 +22,7 @@
</div>
<div class="post-content" id="{$comment->getId()}">
<div class="text" id="text{$comment->getId()}">
<span data-text="{$comment->getText(false)}" class="really_text">{$comment->getText()|noescape}</span>
<span class="really_text">{$comment->getText()|noescape}</span>
{var $attachmentsLayout = $comment->getChildrenWithLayout(288)}
<div n:ifcontent class="attachments attachments_b" style="height: {$attachmentsLayout->height|noescape}; width: {$attachmentsLayout->width|noescape};">
@ -77,6 +77,7 @@
</span>
</div>
</div>
<div class='post-edit'></div>
</td>
</tr>
</tbody>

View file

@ -18,7 +18,7 @@
{var $commentTextAreaId = $post === NULL ? rand(1,300) : $post->getId()}
<table border="0" style="font-size: 11px;" n:class="post, !$compact ? post-divider, $post->isExplicit() ? post-nsfw">
<table border="0" style="font-size: 11px;" data-id="{$post->getPrettyId()}" n:class="post, !$compact ? post-divider, $post->isExplicit() ? post-nsfw">
<tbody>
<tr>
<td width="54" valign="top">
@ -68,15 +68,12 @@
{/if}
{if $post->canBeEditedBy($thisUser) && !($forceNoEditLink ?? false) && $compact == false}
<a class="edit" id="editPost"
data-id="{$post->getId()}"
data-nsfw="{(int)$post->isExplicit()}"
{if $post->getTargetWall() < 0 && $wallOwner->canBeModifiedBy($thisUser)}data-fromgroup="{(int)$post->isPostedOnBehalfOfGroup()}"{/if}></a>
<a class="edit" id="editPost"></a>
{/if}
</div>
<div class="post-content" id="{$post->getPrettyId()}" data-localized-nsfw-text="{_nsfw_warning}">
<div class="text" id="text{$post->getPrettyId()}">
<span data-text="{$post->getText(false)}" class="really_text">{$post->getText()|noescape}</span>
<span class="really_text">{$post->getText()|noescape}</span>
{var $width = ($GLOBALS["_bigWall"] ?? false) ? 550 : 320}
{if isset($GLOBALS["_nesAttGloCou"])}
@ -112,6 +109,7 @@
</span>
</div>
</div>
<div class='post-edit'></div>
<div class="post-menu" n:if="$compact == false">
<a href="{if !$suggestion}/wall{$post->getPrettyId()}{else}javascript:void(0){/if}" class="date">{$post->getPublicationTime()}
<span n:if="$post->getEditTime()" class="edited editedMark">({_edited_short})</span>

View file

@ -15,7 +15,7 @@
<table border="0" style="font-size: 11px;" n:class="post, $post->isExplicit() ? post-nsfw">
<table border="0" style="font-size: 11px;" data-id="{$post->getPrettyId()}" n:class="post, $post->isExplicit() ? post-nsfw">
<tbody>
<tr>
<td width="54" valign="top">
@ -71,7 +71,7 @@
<div class="text" id="text{$post->getPrettyId()}">
{var $owner = $author->getId()}
<span data-text="{$post->getText(false)}" class="really_text">{$post->getText()|noescape}</span>
<span class="really_text">{$post->getText()|noescape}</span>
{var $width = ($GLOBALS["_bigWall"] ?? false) ? 550 : 320}
{if isset($GLOBALS["_nesAttGloCou"])}
@ -119,9 +119,7 @@
{if !($forceNoEditLink ?? false) && $post->canBeEditedBy($thisUser)}
<a id="editPost"
data-id="{$post->getId()}"
data-nsfw="{(int)$post->isExplicit()}"
{if $post->getTargetWall() < 0 && $wallOwner->canBeModifiedBy($thisUser)}data-fromgroup="{(int)$post->isPostedOnBehalfOfGroup()}"{/if}>{_edit}</a> &nbsp;|&nbsp;
data-id="{$post->getPrettyId()}">{_edit}</a> &nbsp;|&nbsp;
{/if}
{if !($forceNoDeleteLink ?? false) && $canBeDeleted}

View file

@ -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}"

View file

@ -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 {

View file

@ -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()

View file

@ -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 += "<br/>"+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", `
<div class="editMenu">
<div id="wall-post-input999">
<textarea id="new_content">${text.dataset.text}</textarea>
<input type="button" class="button" value="${tr("save")}" id="endEditing">
<input type="button" class="button" value="${tr("cancel")}" id="cancelEditing">
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(`
<div class='edit_menu'>
<form id="write">
<textarea placeholder="${tr('edit')}" name="text" style="width: 100%;resize: none;" class="expanded-textarea small-textarea">${escapeHtml(api_post.text)}</textarea>
<div class='post-buttons'>
<div class="post-horizontal"></div>
<div class="post-vertical"></div>
<div class="post-source"></div>
<div class='post-opts'>
${type == 'post' ? `<label>
<input type="checkbox" name="nsfw" ${api_post.is_explicit ? 'checked' : ''} /> ${tr('contains_nsfw')}
</label>` : ''}
${api_post.owner_id < 0 && api_post.can_pin ? `<label>
<input type="checkbox" name="as_group" ${api_post.from_id < 0 ? 'checked' : ''} /> ${tr('post_as_group')}
</label>` : ''}
</div>
${e.currentTarget.dataset.nsfw != null ? `
<div class="postOptions">
<label><input type="checkbox" id="nswfw" ${e.currentTarget.dataset.nsfw == 1 ? `checked` : ``}>${tr("contains_nsfw")}</label>
<input type="hidden" id="source" name="source" value="none" />
<div class='edit_menu_buttons'>
<input class='button' type='button' id='__edit_save' value='${tr('save')}'>
<input class='button' type='button' id='__edit_cancel' value='${tr('cancel')}'>
<div style="float: right; display: flex; flex-direction: column;">
<a class='menu_toggler'>
${tr('attach')}
</a>
<div id="wallAttachmentMenu" class="hidden">
<a class="header menu_toggler">
${tr('attach')}
</a>
<a id="__photoAttachment">
<img src="/assets/packages/static/openvk/img/oxygen-icons/16x16/mimetypes/application-x-egon.png" />
${tr('photo')}
</a>
<a id="__videoAttachment">
<img src="/assets/packages/static/openvk/img/oxygen-icons/16x16/mimetypes/application-vnd.rn-realmedia.png" />
${tr('video')}
</a>
<a id="__audioAttachment">
<img src="/assets/packages/static/openvk/img/oxygen-icons/16x16/mimetypes/audio-ac3.png" />
${tr('audio')}
</a>
${type == 'post' ? `<a id="__notesAttachment">
<img src="/assets/packages/static/openvk/img/oxygen-icons/16x16/mimetypes/application-x-srt.png" />
${tr('note')}
</a>
<a id='__sourceAttacher'>
<img src="/assets/packages/static/openvk/img/oxygen-icons/16x16/actions/insert-link.png" />
${tr('source')}
</a>` : ''}
</div>
` : ``}
${e.currentTarget.dataset.fromgroup != null ? `
<div class="postOptions">
<label><input type="checkbox" id="fromgroup" ${e.currentTarget.dataset.fromgroup == 1 ? `checked` : ``}>${tr("post_as_group")}</label>
</div>
` : ``}
</div>
</div>
</form>
</div>`)
if(api_post.copyright) {
edit_place.find('.post-source').html(`
<span>${tr('source')}: <a>${escapeHtml(api_post.copyright.link)}</a></span>
<div id='remove_source_button'></div>
`)
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(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", `
<span class="edited editedMark">(${tr("edited_short")})</span>
`)
}
if(e.currentTarget.dataset.nsfw != null) {
e.currentTarget.setAttribute("data-nsfw", result.nsfw)
if(result.nsfw == 0) {
post.classList.remove("post-nsfw")
if(type == 'photo') {
preview = att[type].sizes[1].url
} else {
post.classList.add("post-nsfw")
}
preview = att[type].image[0].url
}
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)
__appendToTextarea({
'type': type,
'preview': preview,
'id': aid
}, edit_place)
} else {
MessageBox(tr("error"), result.error, [tr("ok")], [Function.noop])
post.querySelector("#editPost").click()
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)
}
}
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))
})
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(`
<div class="vertical-attachment upload-item" draggable="true" data-type='${attachment_obj.type}' data-id="${attachment_obj.id}">
<div class='vertical-attachment-content' draggable="false">
${attachment_obj.html}
</div>
<div class='vertical-attachment-remove'>
<div id='small_remove_button'></div>
</div>
</div>
`)
return
}
indicator.append(`
<a draggable="true" href='/${attachment_obj.type}${attachment_obj.id}' class="upload-item" data-type='${attachment_obj.type}' data-id="${attachment_obj.id}">
<span class="upload-delete">×</span>
@ -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) => {
<div class='attachment_note_content'>
<span class="attachment_note_text">${tr('note')}</span>
<span class="attachment_note_name">${ovk_proc_strtr(dataset.name, 66)}</span>
<span class="attachment_note_name">${ovk_proc_strtr(escapeHtml(dataset.name), 66)}</span>
</div>
</div>
</div>

View file

@ -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)
}

View file

@ -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";

View file

@ -1468,7 +1468,7 @@
"error_adding_source_regex" = "Ошибка добавления источника: некорректная ссылка.";
"error_adding_source_long" = "Ошибка добавления источника: слишком длинная ссылка.";
"error_adding_source_sus" = "Ошибка добавления источника: подозрительная ссылка.";
"error_adding_source_sus" = "Ошибка добавления источника: гиперссылка заблокирована.";
/* Admin actions */