Implements edit box and rearranges post buttons.
This commit is contained in:
parent
84caff7c97
commit
c5fd70d275
5 changed files with 108 additions and 16 deletions
15
forum.nim
15
forum.nim
|
|
@ -1258,6 +1258,21 @@ routes:
|
||||||
|
|
||||||
resp $(%list), "application/json"
|
resp $(%list), "application/json"
|
||||||
|
|
||||||
|
get "/karax/post.rst":
|
||||||
|
createTFD()
|
||||||
|
let postId = getInt(@"id", -1)
|
||||||
|
cond postId != -1
|
||||||
|
|
||||||
|
let postQuery = sql"""
|
||||||
|
select content from post where id = ?;
|
||||||
|
"""
|
||||||
|
|
||||||
|
let content = getValue(db, postQuery, postId)
|
||||||
|
if content.len == 0:
|
||||||
|
resp Http404, "Post not found"
|
||||||
|
else:
|
||||||
|
resp content, "text/x-rst"
|
||||||
|
|
||||||
get "/karax/profile.json":
|
get "/karax/profile.json":
|
||||||
createTFD()
|
createTFD()
|
||||||
var
|
var
|
||||||
|
|
|
||||||
43
redesign/editbox.nim
Normal file
43
redesign/editbox.nim
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
when defined(js):
|
||||||
|
import httpcore, options, sugar
|
||||||
|
|
||||||
|
include karax/prelude
|
||||||
|
import karax/kajax
|
||||||
|
|
||||||
|
import replybox, post, karaxutils, threadlist
|
||||||
|
|
||||||
|
type
|
||||||
|
EditBox* = ref object
|
||||||
|
box: ReplyBox
|
||||||
|
post: Option[Post]
|
||||||
|
rawContent: Option[kstring] ## The raw rst for a post (needs to be loaded)
|
||||||
|
status: HttpCode
|
||||||
|
|
||||||
|
proc newEditBox*(): EditBox =
|
||||||
|
EditBox(
|
||||||
|
box: newReplyBox(nil)
|
||||||
|
)
|
||||||
|
|
||||||
|
proc onRawContent(httpStatus: int, response: kstring, state: EditBox) =
|
||||||
|
state.status = httpStatus.HttpCode
|
||||||
|
if state.status != Http200: return
|
||||||
|
|
||||||
|
state.rawContent = some(response)
|
||||||
|
|
||||||
|
proc render*(state: EditBox, post: Post): VNode =
|
||||||
|
if state.post.isNone() or state.post.get().id != post.id:
|
||||||
|
state.post = some(post)
|
||||||
|
var params = @[("id", $post.id)]
|
||||||
|
let uri = makeUri("post.rst", params)
|
||||||
|
ajaxGet(uri, @[], (s: int, r: kstring) => onRawContent(s, r, state))
|
||||||
|
|
||||||
|
return buildHtml(tdiv(class="loading"))
|
||||||
|
|
||||||
|
state.box.setText(state.rawContent.get())
|
||||||
|
result = buildHtml():
|
||||||
|
tdiv(class="edit-box"):
|
||||||
|
renderContent(
|
||||||
|
state.box,
|
||||||
|
none[Thread](),
|
||||||
|
none[Post]()
|
||||||
|
)
|
||||||
|
|
@ -63,7 +63,7 @@ proc render(): VNode =
|
||||||
renderPostList(
|
renderPostList(
|
||||||
params["id"].parseInt(),
|
params["id"].parseInt(),
|
||||||
if postId == 0: none[int]() else: some[int](postId),
|
if postId == 0: none[int]() else: some[int](postId),
|
||||||
isLoggedIn()
|
getLoggedInUser()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ when defined(js):
|
||||||
include karax/prelude
|
include karax/prelude
|
||||||
import karax / [vstyles, kajax, kdom]
|
import karax / [vstyles, kajax, kdom]
|
||||||
|
|
||||||
import karaxutils, error, replybox
|
import karaxutils, error, replybox, editbox
|
||||||
|
|
||||||
type
|
type
|
||||||
State = ref object
|
State = ref object
|
||||||
|
|
@ -26,6 +26,8 @@ when defined(js):
|
||||||
status: HttpCode
|
status: HttpCode
|
||||||
replyingTo: Option[Post]
|
replyingTo: Option[Post]
|
||||||
replyBox: ReplyBox
|
replyBox: ReplyBox
|
||||||
|
editing: Option[Post] ## If in edit mode, this contains the post.
|
||||||
|
editBox: EditBox
|
||||||
|
|
||||||
proc onReplyPosted(id: int)
|
proc onReplyPosted(id: int)
|
||||||
proc newState(): State =
|
proc newState(): State =
|
||||||
|
|
@ -34,7 +36,8 @@ when defined(js):
|
||||||
loading: false,
|
loading: false,
|
||||||
status: Http200,
|
status: Http200,
|
||||||
replyingTo: none[Post](),
|
replyingTo: none[Post](),
|
||||||
replyBox: newReplyBox(onReplyPosted)
|
replyBox: newReplyBox(onReplyPosted),
|
||||||
|
editBox: newEditBox()
|
||||||
)
|
)
|
||||||
|
|
||||||
var
|
var
|
||||||
|
|
@ -106,10 +109,21 @@ when defined(js):
|
||||||
## Executed when a reply has been successfully posted.
|
## Executed when a reply has been successfully posted.
|
||||||
loadMore(state.list.get().posts.len, @[id])
|
loadMore(state.list.get().posts.len, @[id])
|
||||||
|
|
||||||
|
proc onEditPosted(id: int, content: string) =
|
||||||
|
## Executed when an edit has been successfully posted.
|
||||||
|
let list = state.list.get()
|
||||||
|
for i in 0 ..< list.posts.len:
|
||||||
|
if list.posts[i].id == id:
|
||||||
|
list.posts[i].info.content = content
|
||||||
|
break
|
||||||
|
|
||||||
proc onReplyClick(e: Event, n: VNode, p: Option[Post]) =
|
proc onReplyClick(e: Event, n: VNode, p: Option[Post]) =
|
||||||
state.replyingTo = p
|
state.replyingTo = p
|
||||||
state.replyBox.show()
|
state.replyBox.show()
|
||||||
|
|
||||||
|
proc onEditClick(e: Event, n: VNode, p: Option[Post]) =
|
||||||
|
state.editing = p
|
||||||
|
|
||||||
proc onLoadMore(ev: Event, n: VNode, start: int, post: Post) =
|
proc onLoadMore(ev: Event, n: VNode, start: int, post: Post) =
|
||||||
loadMore(start, post.moreBefore) # TODO: Don't load all!
|
loadMore(start, post.moreBefore) # TODO: Don't load all!
|
||||||
|
|
||||||
|
|
@ -128,8 +142,12 @@ when defined(js):
|
||||||
span(class="more-post-count"):
|
span(class="more-post-count"):
|
||||||
text "(" & $post.moreBefore.len & ")"
|
text "(" & $post.moreBefore.len & ")"
|
||||||
|
|
||||||
proc genPost(post: Post, thread: Thread, isLoggedIn: bool): VNode =
|
proc genPost(post: Post, thread: Thread, currentUser: Option[User]): VNode =
|
||||||
let postCopy = post # TODO: Another workaround here, closure capture :(
|
let postCopy = post # TODO: Another workaround here, closure capture :(
|
||||||
|
let loggedIn = currentUser.isSome()
|
||||||
|
let authoredByUser =
|
||||||
|
loggedIn and currentUser.get().name == post.author.name
|
||||||
|
|
||||||
result = buildHtml():
|
result = buildHtml():
|
||||||
tdiv(class="post", id = $post.id):
|
tdiv(class="post", id = $post.id):
|
||||||
tdiv(class="post-icon"):
|
tdiv(class="post-icon"):
|
||||||
|
|
@ -144,18 +162,33 @@ when defined(js):
|
||||||
a(href=renderPostUrl(post, thread), title=title):
|
a(href=renderPostUrl(post, thread), title=title):
|
||||||
text renderActivity(post.info.creation)
|
text renderActivity(post.info.creation)
|
||||||
tdiv(class="post-content"):
|
tdiv(class="post-content"):
|
||||||
verbatim(post.info.content)
|
if state.editing.isSome() and state.editing.get() == post:
|
||||||
|
render(state.editBox, postCopy)
|
||||||
|
else:
|
||||||
|
verbatim(post.info.content)
|
||||||
tdiv(class="post-buttons"):
|
tdiv(class="post-buttons"):
|
||||||
tdiv(class="like-button"):
|
if authoredByUser:
|
||||||
button(class="btn"):
|
tdiv(class="edit-button", onClick=(e: Event, n: VNode) =>
|
||||||
span(class="like-count"):
|
onEditClick(e, n, some(postCopy))):
|
||||||
if post.likes.len > 0:
|
|
||||||
text $post.likes.len
|
|
||||||
italic(class="far fa-heart")
|
|
||||||
if isLoggedIn:
|
|
||||||
tdiv(class="flag-button"):
|
|
||||||
button(class="btn"):
|
button(class="btn"):
|
||||||
italic(class="far fa-flag")
|
italic(class="far fa-edit")
|
||||||
|
tdiv(class="delete-button"):
|
||||||
|
button(class="btn"):
|
||||||
|
italic(class="far fa-trash-alt")
|
||||||
|
else:
|
||||||
|
tdiv(class="like-button"):
|
||||||
|
button(class="btn"):
|
||||||
|
span(class="like-count"):
|
||||||
|
if post.likes.len > 0:
|
||||||
|
text $post.likes.len
|
||||||
|
italic(class="far fa-heart")
|
||||||
|
|
||||||
|
if loggedIn:
|
||||||
|
tdiv(class="flag-button"):
|
||||||
|
button(class="btn"):
|
||||||
|
italic(class="far fa-flag")
|
||||||
|
|
||||||
|
if loggedIn:
|
||||||
tdiv(class="reply-button"):
|
tdiv(class="reply-button"):
|
||||||
button(class="btn", onClick=(e: Event, n: VNode) =>
|
button(class="btn", onClick=(e: Event, n: VNode) =>
|
||||||
onReplyClick(e, n, some(postCopy))):
|
onReplyClick(e, n, some(postCopy))):
|
||||||
|
|
@ -205,7 +238,7 @@ when defined(js):
|
||||||
text diffStr
|
text diffStr
|
||||||
|
|
||||||
proc renderPostList*(threadId: int, postId: Option[int],
|
proc renderPostList*(threadId: int, postId: Option[int],
|
||||||
isLoggedIn: bool): VNode =
|
currentUser: Option[User]): VNode =
|
||||||
if state.status != Http200:
|
if state.status != Http200:
|
||||||
return renderError("Couldn't retrieve posts.")
|
return renderError("Couldn't retrieve posts.")
|
||||||
|
|
||||||
|
|
@ -243,7 +276,7 @@ when defined(js):
|
||||||
genTimePassed(prevPost.get(), some(post), false)
|
genTimePassed(prevPost.get(), some(post), false)
|
||||||
if post.moreBefore.len > 0:
|
if post.moreBefore.len > 0:
|
||||||
genLoadMore(post, i)
|
genLoadMore(post, i)
|
||||||
genPost(post, list.thread, isLoggedIn)
|
genPost(post, list.thread, currentUser)
|
||||||
prevPost = some(post)
|
prevPost = some(post)
|
||||||
|
|
||||||
if prevPost.isSome:
|
if prevPost.isSome:
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ when defined(js):
|
||||||
state.shown = true
|
state.shown = true
|
||||||
|
|
||||||
proc getText*(state: ReplyBox): kstring = state.text
|
proc getText*(state: ReplyBox): kstring = state.text
|
||||||
|
proc setText*(state: ReplyBox, text: kstring) = state.text = text
|
||||||
|
|
||||||
proc onPreviewPost(httpStatus: int, response: kstring, state: ReplyBox) =
|
proc onPreviewPost(httpStatus: int, response: kstring, state: ReplyBox) =
|
||||||
postFinished:
|
postFinished:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue