mirror of
https://github.com/openvk/openvk
synced 2025-04-23 16:43:02 +03:00
Add editing posts
This commit is contained in:
parent
245f8690c6
commit
1518e424ca
14 changed files with 184 additions and 19 deletions
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -246,5 +246,16 @@ class Post extends Postable
|
|||
$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;
|
||||
}
|
||||
|
|
|
@ -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()]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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}
|
||||
|
|
||||
{if $comment->canBeDeletedBy($thisUser)}
|
||||
<a href="/comment{$comment->getId()}/delete">{_delete}</a> |
|
||||
{/if}
|
||||
{if $comment->canBeEditedBy($thisUser)}
|
||||
<a id="editPost" data-id="{$comment->getId()}">{_edit}</a> |
|
||||
{/if}
|
||||
<a class="comment-reply">{_reply}</a>
|
||||
{if $thisUser->getId() != $comment->getOwner()->getId()}
|
||||
{var $canReport = true}
|
||||
|
|
|
@ -62,10 +62,14 @@
|
|||
<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}">
|
||||
|
@ -88,7 +92,9 @@
|
|||
</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>
|
||||
|
|
|
@ -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,15 +53,17 @@
|
|||
{/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}">
|
||||
|
@ -87,6 +91,10 @@
|
|||
{var $forceNoPinLink = true}
|
||||
{/if}
|
||||
|
||||
{if !($forceNoEditLink ?? false) && $post->canBeEditedBy($thisUser)}
|
||||
<a id="editPost" data-id="{$post->getId()}">{_edit}</a> |
|
||||
{/if}
|
||||
|
||||
{if !($forceNoDeleteLink ?? false) && $post->canBeDeletedBy($thisUser)}
|
||||
<a href="/wall{$post->getPrettyId()}/delete">{_delete}</a> |
|
||||
{/if}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -2701,3 +2701,17 @@ body.article .floating_sidebar, body.article .page_content {
|
|||
right: 22px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.edited {
|
||||
color: #9b9b9b;
|
||||
}
|
||||
|
||||
.editMenu.loading {
|
||||
filter: opacity(0.5);
|
||||
cursor: progress;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.editMenu.loading * {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
|
|
@ -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
BIN
Web/static/img/edit.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 571 B |
|
@ -263,3 +263,67 @@ async function showArticle(note_id) {
|
|||
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"
|
||||
}
|
||||
})
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
Loading…
Reference in a new issue