Add editing posts

This commit is contained in:
lalka2016 2023-09-06 22:49:20 +03:00
parent 245f8690c6
commit 1518e424ca
14 changed files with 184 additions and 19 deletions

View file

@ -90,4 +90,12 @@ class Comment extends Post
{
return "/wall" . $this->getTarget()->getPrettyId() . "#_comment" . $this->getId();
}
function canBeEditedBy(?User $user = NULL): bool
{
if(!$user)
return false;
return $user->getId() == $this->getOwner(false)->getId();
}
}

View file

@ -245,6 +245,17 @@ class Post extends Postable
$this->unwire();
$this->save();
}
function canBeEditedBy(?User $user = NULL): bool
{
if(!$user)
return false;
if($this->isDeactivationMessage() || $this->isUpdateAvatarMessage())
return false;
return $user->getId() == $this->getOwner(false)->getId();
}
use Traits\TRichText;
}

View file

@ -3,7 +3,7 @@ namespace openvk\Web\Presenters;
use openvk\Web\Models\Exceptions\TooMuchOptionsException;
use openvk\Web\Models\Entities\{Poll, Post, Photo, Video, Club, User};
use openvk\Web\Models\Entities\Notifications\{MentionNotification, RepostNotification, WallPostNotification};
use openvk\Web\Models\Repositories\{Posts, Users, Clubs, Albums, Notes};
use openvk\Web\Models\Repositories\{Posts, Users, Clubs, Albums, Notes, Comments};
use Chandler\Database\DatabaseConnection;
use Nette\InvalidStateException as ISE;
use Bhaktaraz\RSSGenerator\Item;
@ -498,4 +498,31 @@ final class WallPresenter extends OpenVKPresenter
# TODO localize message based on language and ?act=(un)pin
$this->flashFail("succ", tr("information_-1"), tr("changes_saved_comment"));
}
function renderEdit()
{
$this->assertUserLoggedIn();
$this->willExecuteWriteAction();
if($_SERVER["REQUEST_METHOD"] !== "POST")
$this->redirect("/id0");
if($this->postParam("type") == "post") {
$post = $this->posts->get((int)$this->postParam("postid"));
} else {
$post = (new Comments)->get((int)$this->postParam("postid"));
}
if(!$post || $post->isDeleted())
$this->returnJson(["error" => "Invalid post"]);
if(!$post->canBeEditedBy($this->user->identity))
$this->returnJson(["error" => "Access denied"]);
$post->setEdited(time());
$post->setContent($this->postParam("newContent"));
$post->save(true);
$this->returnJson(["error" => "no", "new_content" => $post->getText(), "new_edited" => (string)$post->getEditTime()]);
}
}

View file

@ -34,6 +34,14 @@
{/if}
<a n:if="$canDelete ?? false" class="profile_link" style="display:block;width:96%;" href="/wall{$post->getPrettyId()}/delete">{_delete}</a>
<a
n:if="$thisUser->getChandlerUser()->can('access')->model('admin')->whichBelongsTo(NULL) AND $post->getEditTime()"
style="display:block;width:96%;"
class="profile_link"
href="/admin/logs?type=1&obj_type=Post&obj_id={$post->getId()}"
>
{_changes_history}
</a>
<a n:if="$canReport ?? false" class="profile_link" style="display:block;width:96%;" href="javascript:reportPost()">{_report}</a>
</div>
<script n:if="$canReport ?? false">

View file

@ -20,7 +20,7 @@
</div>
<div class="post-content" id="{$comment->getId()}">
<div class="text" id="text{$comment->getId()}">
{$comment->getText()|noescape}
<span class="really_text">{$comment->getText()|noescape}</span>
<div n:ifcontent class="attachments_b">
<div class="attachment" n:foreach="$comment->getChildren() as $attachment" data-localized-nsfw-text="{_nsfw_warning}">
@ -29,17 +29,15 @@
</div>
</div>
<div n:if="isset($thisUser) &&! ($compact ?? false)" class="post-menu">
<a
href="{=$linkWithPost && get_class($comment->getTarget()) == 'openvk\Web\Models\Entities\Post' ? '/wall' . $comment->getTarget()->getPrettyId() : ''}#_comment{$comment->getId()}"
class="date"
>
{$comment->getPublicationTime()}
</a>
<a href="#_comment{$comment->getId()}" class="date">{$comment->getPublicationTime()} <span n:if="$post->getEditTime()" class="edited editedMark">({_edited_short})</span></a>
{if !$timeOnly}
&nbsp;|
{if $comment->canBeDeletedBy($thisUser)}
<a href="/comment{$comment->getId()}/delete">{_delete}</a>&nbsp;|
{/if}
{if $comment->canBeEditedBy($thisUser)}
<a id="editPost" data-id="{$comment->getId()}">{_edit}</a>&nbsp;|
{/if}
<a class="comment-reply">{_reply}</a>
{if $thisUser->getId() != $comment->getOwner()->getId()}
{var $canReport = true}

View file

@ -62,11 +62,15 @@
<a class="pin" href="/wall{$post->getPrettyId()}/pin?act=pin&hash={rawurlencode($csrfToken)}"></a>
{/if}
{/if}
{if $post->canBeEditedBy($thisUser) && !($forceNoEditLink ?? false) && $compact == false}
<a class="edit" id="editPost" data-id="{$post->getId()}"></a>
{/if}
</div>
<div class="post-content" id="{$post->getPrettyId()}">
<div class="text" id="text{$post->getPrettyId()}">
{$post->getText()|noescape}
<div class="text">
<span class="really_text">{$post->getText()|noescape}</span>
<div n:ifcontent class="attachments_b">
<div class="attachment" n:foreach="$post->getChildren() as $attachment" data-localized-nsfw-text="{_nsfw_warning}">
{include "../attachment.xml", attachment => $attachment}
@ -88,13 +92,15 @@
</div>
</div>
<div class="post-menu" n:if="$compact == false">
<a href="/wall{$post->getPrettyId()}" class="date">{$post->getPublicationTime()}</a>
<a href="/wall{$post->getPrettyId()}" class="date">{$post->getPublicationTime()}
<span n:if="$post->getEditTime()" class="edited editedMark">({_edited_short})</span>
</a>
<a n:if="!empty($platform)" class="client_app" data-app-tag="{$platform}" data-app-name="{$platformDetails['name']}" data-app-url="{$platformDetails['url']}" data-app-img="{$platformDetails['img']}">
<img src="/assets/packages/static/openvk/img/app_icons_mini/{$post->getPlatform(this)}.svg">
</a>
{if isset($thisUser)}
&nbsp;
<a n:if="!($forceNoCommentsLink ?? false) && $commentsCount == 0" href="javascript:expand_comment_textarea({$commentTextAreaId})">{_comment}</a>
<div class="like_wrap">

View file

@ -7,6 +7,8 @@
{var $deac = "post_deact_silent"}
{/if}
<table border="0" style="font-size: 11px;" n:class="post, $post->isExplicit() ? post-nsfw">
<tbody>
<tr>
@ -51,16 +53,18 @@
{/if}
<br/>
<a href="/wall{$post->getPrettyId()}" class="date">
{$post->getPublicationTime()}{if $post->isPinned()}, {_pinned}{/if}
{$post->getPublicationTime()} <span n:if="$post->getEditTime()" class="editedMark">({_edited_short})</span>{if $post->isPinned()}, {_pinned}{/if}
<a n:if="!empty($platform)" class="client_app" data-app-tag="{$platform}" data-app-name="{$platformDetails['name']}" data-app-url="{$platformDetails['url']}" data-app-img="{$platformDetails['img']}">
<img src="/assets/packages/static/openvk/img/app_icons_mini/{$post->getPlatform(this)}.svg">
</a>
</a>
</div>
<div class="post-content" id="{$post->getPrettyId()}">
<div class="text" id="text{$post->getPrettyId()}">
{$post->getText()|noescape}
<div class="text">
{var $owner = $author->getId()}
<span class="really_text">{$post->getText()|noescape}</span>
<div n:ifcontent class="attachments_b">
<div class="attachment" n:foreach="$post->getChildren() as $attachment" data-localized-nsfw-text="{_nsfw_warning}">
{include "../attachment.xml", attachment => $attachment}
@ -87,6 +91,10 @@
{var $forceNoPinLink = true}
{/if}
{if !($forceNoEditLink ?? false) && $post->canBeEditedBy($thisUser)}
<a id="editPost" data-id="{$post->getId()}">{_edit}</a> &nbsp;|&nbsp;
{/if}
{if !($forceNoDeleteLink ?? false) && $post->canBeDeletedBy($thisUser)}
<a href="/wall{$post->getPrettyId()}/delete">{_delete}</a> &nbsp;|&nbsp;
{/if}

View file

@ -129,6 +129,8 @@ 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"

View file

@ -2700,4 +2700,18 @@ body.article .floating_sidebar, body.article .page_content {
position: absolute;
right: 22px;
font-size: 12px;
}
}
.edited {
color: #9b9b9b;
}
.editMenu.loading {
filter: opacity(0.5);
cursor: progress;
user-select: none;
}
.editMenu.loading * {
pointer-events: none;
}

View file

@ -110,10 +110,24 @@
transition-duration: 0.3s;
}
.post-author .edit {
float: right;
height: 16px;
width: 16px;
overflow: auto;
background: url("/assets/packages/static/openvk/img/edit.png") no-repeat 0 0;
opacity: 0.1;
transition-duration: 0.3s;
}
.post-author .pin:hover {
opacity: 0.4;
}
.post-author .edit:hover {
opacity: 0.4;
}
.expand_button {
background-color: #eee;
width: 100%;

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 571 B

View file

@ -262,4 +262,68 @@ async function showArticle(note_id) {
u("#articleText").html(`<h1 class="articleView_nameHeading">${note.title}</h1>` + note.html);
u("body").removeClass("dimmed");
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")
if(content.querySelector("textarea") == null) {
content.insertAdjacentHTML("afterbegin", `
<div id="wall-post-input999" class="editMenu">
<textarea id="new_content">${text.innerHTML.replace(/(<([^>]+)>)/gi, '')}</textarea>
<input type="button" class="button" value="${tr("save")}" id="endEditing">
<input type="button" class="button" value="${tr("cancel")}" id="cancelEditing">
</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"
}
let xhr = new XMLHttpRequest()
xhr.open("POST", "/wall/edit")
xhr.onloadstart = () => {
content.querySelector(".editMenu").classList.add("loading")
}
xhr.onerror = () => {
MessageBox(tr("error"), "unknown error occured", 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>
`)
}
} else {
MessageBox(tr("error"), result.error, [tr("ok")], [Function.noop])
post.querySelector("#editPost").click()
}
}
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)
})
text.style.display = "none"
setupWallPostInputHandlers(999)
} else {
u(content.querySelector(".editMenu")).remove()
text.style.display = "block"
}
})

View file

@ -214,6 +214,8 @@
"reply" = "Reply";
"edited_short" = "edited";
/* Friends */
"friends" = "Friends";
@ -1128,6 +1130,7 @@
"warn_user_action" = "Warn user";
"ban_in_support_user_action" = "Ban in support";
"unban_in_support_user_action" = "Unban in support";
"changes_history" = "Editing history";
/* Admin panel */

View file

@ -191,6 +191,7 @@
"version_incompatibility" = "Не удалось отобразить это вложение. Возможно, база данных несовместима с текущей версией OpenVK.";
"graffiti" = "Граффити";
"reply" = "Ответить";
"edited_short" = "ред.";
/* Friends */
@ -1028,6 +1029,7 @@
"warn_user_action" = "Предупредить пользователя";
"ban_in_support_user_action" = "Заблокировать в поддержке";
"unban_in_support_user_action" = "Разблокировать в поддержке";
"changes_history" = "История редактирования";
/* Admin panel */