369 lines
11 KiB
Cheetah
369 lines
11 KiB
Cheetah
#! stdtmpl
|
|
#
|
|
#template `%`(idx: expr): expr {.immediate.} =
|
|
# row[idx]
|
|
#end template
|
|
#
|
|
#
|
|
#proc genThreadsList(c: var TForumData, count: var int): string =
|
|
# const query = sql"select id, name, views, modified from thread order by modified desc limit ?, ?"
|
|
# const threadId = 0
|
|
# const name = 1
|
|
# const views = 2
|
|
#
|
|
# result = ""
|
|
# count = 0
|
|
<div id="talk-heads">
|
|
<div class="topic">
|
|
<div>
|
|
Topic
|
|
<a href="${c.req.makeUri("/threadActivity.xml")}">
|
|
<img src="/images/Feed-icon.svg" class="rssfeed">
|
|
</a>
|
|
</div>
|
|
</div>
|
|
<div class="users"><div>Users</div></div>
|
|
<div class="detail"><div>Details</div></div>
|
|
<div class="activity">
|
|
<div>
|
|
Activity
|
|
<a href="${c.req.makeUri("/postActivity.xml")}">
|
|
<img src="/images/Feed-icon.svg" class="rssfeed">
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div id="talk-threads">
|
|
# for row in rows(db, query, $((c.pageNum-1) * ThreadsPerPage), $ThreadsPerPage):
|
|
# inc(count)
|
|
<div>
|
|
<div class="topic">
|
|
<div>
|
|
<a href="${c.genThreadUrl(threadid = %threadid)}"
|
|
title="${xmlEncode(%name)}">${xmlEncode(%name)}</a>
|
|
${genPagenumLocalNav(c, (%threadid).parseInt)}
|
|
</div>
|
|
</div>
|
|
|
|
#let users = getAllRows(db,
|
|
# sql("select distinct name, email from person where id in " &
|
|
# "(select author from post where thread = ?)"), %threadId)
|
|
<div class="users">
|
|
<div>
|
|
#for i in 0 .. min(6, users.len-1):
|
|
<img src="${getGravatarUrl(users[i][1], 20)}" title="${users[i][0]}">
|
|
#end for
|
|
</div>
|
|
</div>
|
|
|
|
#let latestReplyAuthor = getValue(db, sql("select name from person where id = " &
|
|
# "(select author from post where id = " &
|
|
# "(select max(id) from post where thread = ?))"), %threadId)
|
|
|
|
#let replyProfileUrl = c.req.makeUri("profile/", false) &
|
|
# xmlEncode(latestReplyAuthor)
|
|
|
|
# let posts = getValue(db, sql"select count(*) from post where thread = ?", %threadId)
|
|
<div class="detail">
|
|
<div><div title="Views">${xmlEncode(%views)}</div></div>
|
|
<div><div title="Posts">$posts</div></div>
|
|
</div>
|
|
|
|
#let latestReplyDate = getValue(db, sql("SELECT strftime('%s', " &
|
|
# "(select creation from post where id = (select max(id) from post where thread = ?)))"), %threadId)
|
|
#let timeStr = formatTimestamp(latestReplyDate.parseInt())
|
|
<div class="activity">
|
|
<div>
|
|
<a href="$replyProfileUrl">$latestReplyAuthor</a> replied $timeStr
|
|
</div>
|
|
</div>
|
|
</div>
|
|
# end for
|
|
</div>
|
|
|
|
#end proc
|
|
#
|
|
#
|
|
#proc genPostPreview(c: var TForumData,
|
|
# title, content, author, date: string): string =
|
|
# result = ""
|
|
<a name="preview"></a>
|
|
<div id="talk-thread">
|
|
<div>
|
|
<div class="author">
|
|
<div>
|
|
#let profileUrl = c.req.makeUri("profile/", false) & xmlEncode(author)
|
|
<a class="name" href="$profileUrl">${xmlEncode(author)}</a>
|
|
</div>
|
|
</div>
|
|
<div class="topic">
|
|
<div>
|
|
#try:
|
|
${content.rstToHtml}
|
|
#except EParseError:
|
|
# c.errorMsg = getCurrentExceptionMsg()
|
|
#end
|
|
<span class="date">${xmlEncode(date)}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
#end proc
|
|
#
|
|
#
|
|
#proc genPostsList(c: var TForumData, threadId: string, count: var int): string =
|
|
# const query = sql"""select p.id, u.name, p.header, p.content, p.creation, p.author, u.email from post p,
|
|
# person u where u.id = p.author and p.thread = ? order by p.id limit ?, ?"""
|
|
# const postId = 0
|
|
# const userName = 1
|
|
# const postHeader = 2
|
|
# const postContent = 3
|
|
# const postCreation = 4
|
|
# const postAuthor = 5
|
|
# const userEmail = 6
|
|
# result = ""
|
|
# count = 0
|
|
# let posts = getAllRows(db, query, threadId, $((c.pageNum-1) * PostsPerPage), $PostsPerPage)
|
|
# if posts.len < 1: return ""
|
|
# end if
|
|
<div id="talk-head">
|
|
<div class="info-post">
|
|
<div>
|
|
<a href="${c.req.makeUri("/")}"><b>forum index</b></a> >
|
|
<a href="${c.req.makeUri("/t/" & $threadId)}">${posts[0][postHeader]}</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div id="talk-thread">
|
|
# for row in posts:
|
|
# inc(count)
|
|
<a name="${%postId}"></a>
|
|
<div id="${%postId}">
|
|
<div class="author">
|
|
<div>
|
|
#let profileUrl = c.req.makeUri("profile/", false) & xmlEncode(%userName)
|
|
<div class="avatar">${genGravatar(%userEmail)}</div>
|
|
<a class="name" href="$profileUrl">${xmlEncode(%userName)}</a>
|
|
#if c.userId == %postAuthor and c.currentPost.subject.len == 0:
|
|
<hr/><a href="${c.genThreadUrl(%postId, "edit")}">Edit post</a>
|
|
#elif c.isAdmin and c.currentPost.subject.len == 0:
|
|
<hr/><a style="color: red;" href="${c.genThreadUrl(%postId, "edit")}">Edit post</a>
|
|
#end if
|
|
</div>
|
|
</div>
|
|
<div class="topic">
|
|
<div>
|
|
#try:
|
|
${(%postContent).rstToHtml}
|
|
#except EParseError:
|
|
# c.errorMsg = getCurrentExceptionMsg()
|
|
#end
|
|
<span class="date">${xmlEncode(%postCreation)}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
# end for
|
|
</div>
|
|
#end proc
|
|
#
|
|
#
|
|
#proc genFormPost(c: var TForumData, action: string,
|
|
# topText, title, content: string, isEdit: bool): string =
|
|
# result = ""
|
|
<br />
|
|
<a name="reply"></a>
|
|
<div id="replywrapper">
|
|
<div id="talk-head">
|
|
<div class="info-post">
|
|
<div>
|
|
<a href="${c.req.makeUri("/")}"><b>forum index</b></a> >
|
|
$topText
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<form action="${c.req.makeUri(action, false) & "#preview"}" method="POST">
|
|
#if action == "doreply":
|
|
${HiddenField(c, "subject", title)}
|
|
#else:
|
|
${FieldValid(c, "subject", "Subject:")}
|
|
${TextWidget(c, "subject", title, maxlength=100)}
|
|
<br />
|
|
#end if
|
|
${FieldValid(c, "content", "Content:")}<br />
|
|
${TextAreaWidget(c, "content", content)}<br />
|
|
${FormSession(c, action)}
|
|
|
|
# if isEdit:
|
|
<input type="checkbox" name="delete" value="Delete">Delete Post<br />
|
|
# end if
|
|
#if c.errorMsg != "":
|
|
<div style="float: left; width: 100%;">
|
|
<span class="error">$c.errorMsg</span>
|
|
</div>
|
|
#end if
|
|
<br/>
|
|
<input type="submit" name="previewBtn" value="Preview" />
|
|
<input type="submit" name="postBtn" value="Submit" />
|
|
|
|
<a href="http://nim-lang.org/rst.html">Syntax Cheatsheet</a>
|
|
</form>
|
|
</div>
|
|
#end proc
|
|
#
|
|
#
|
|
#proc genFormRegister(c: var TForumData): string =
|
|
# result = ""
|
|
<div id="talk-head">
|
|
<div class="info-post">
|
|
<div>
|
|
<a href="${c.req.makeUri("/")}"><b>forum index</b></a> >
|
|
Register
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<form action="${c.req.makeUri("/doregister", false)}" method="POST">
|
|
<table border="0">
|
|
<tr>
|
|
<td>${FieldValid(c, "name", "Username:")}</td>
|
|
<td>${TextWidget(c, "name", reuseText, maxlength=20)}</td>
|
|
</tr>
|
|
<tr>
|
|
<td>${FieldValid(c, "new_password", "Password:")}</td>
|
|
<td><input type="password" name="new_password" maxlength="20" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td>${FieldValid(c, "email", "E-Mail:")}</td>
|
|
<td>${TextWidget(c, "email", reuseText, maxlength=30)}</td>
|
|
</tr>
|
|
<tr>
|
|
<td>${FieldValid(c, "antibot", "What is " & antibot(c) & "?")}</td>
|
|
<td>${TextWidget(c, "antibot", "", maxlength=4)}</td>
|
|
</tr>
|
|
</table>
|
|
#if c.errorMsg != "":
|
|
<div style="float: left; width: 100%;">
|
|
<span class="error">$c.errorMsg</span>
|
|
</div>
|
|
#end if
|
|
<input type="submit" value="Register">
|
|
</form>
|
|
#end proc
|
|
#
|
|
#proc genFormLogin(c: var TForumData): string =
|
|
# result = ""
|
|
# if not c.loggedIn:
|
|
<form action="${c.req.makeUri("/dologin", false)}" method="POST">
|
|
<table border="0">
|
|
<tr><td>Username:</td><td>
|
|
<input type="text" name="name" maxlength="20"></td></tr>
|
|
<tr><td>Password:</td><td>
|
|
<input type="password" name="password" maxlength="20"></td></tr>
|
|
</table>
|
|
<input type="submit" value="Login">
|
|
</form>
|
|
<span style="color:red">$c.loginErrorMsg</span>
|
|
# else:
|
|
<span style="color:red">You're already logged in!</span>
|
|
# end if
|
|
#end proc
|
|
#
|
|
#
|
|
#proc genListOnline(c: var TForumData, stats: TForumStats): string =
|
|
# result = ""
|
|
# var active: seq[string] = @[]
|
|
# for i in stats.activeUsers:
|
|
# active.add(i.nick)
|
|
# end for
|
|
# let profileUrl = c.req.makeUri("profile/", false) &
|
|
# xmlEncode(stats.newestMember.nick)
|
|
<span class="forum-user-info" title="${active.join(", ")}">
|
|
<b>${stats.activeUsers.len}</b> of <b>${stats.totalUsers}</b> users online</span> |
|
|
<b>${stats.totalThreads}</b> threads | <b>${stats.totalPosts}</b> posts |
|
|
newest member: <a href="$profileUrl">${stats.newestMember.nick}</a>
|
|
#end proc
|
|
#
|
|
#
|
|
#
|
|
#
|
|
#proc genSearchResults(c: var TForumData,
|
|
# results: iterator: db_sqlite.TRow {.closure, tags: [FReadDB].},
|
|
# count: var int): string =
|
|
# const threadId = 0
|
|
# const threadName = 1
|
|
# const postId = 2
|
|
# const postHeader = 3
|
|
# const postContent = 4
|
|
# const userName = 5
|
|
# const postCreation = 6
|
|
# const postAuthor = 7
|
|
# const userEmail = 8
|
|
# const what = 9
|
|
# result = ""
|
|
# count = 0
|
|
# var whCount: array[bool, int]
|
|
<div id="talk-head">
|
|
<div class="info-post">
|
|
<div>
|
|
Search results for: <i style="color: #332299">${xmlEncode(c.search.replace(""","\""))}</i>.
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div id="talk-thread" class="searchResults">
|
|
# for row in results():
|
|
# inc(count)
|
|
# let isThread = %what == "0"
|
|
# inc(whCount[isThread])
|
|
# let postUrl = c.genThreadUrl(%postId,"",%threadId,"")
|
|
# let threadUrl = c.genThreadUrl("","",%threadId)
|
|
# var headersDiffer = false
|
|
<div>
|
|
<div class="author">
|
|
<div>
|
|
#let profileUrl = c.req.makeUri("profile/", false) & xmlEncode(%userName)
|
|
<div><a href="$profileUrl">${genGravatar(%userEmail, 40)}</a></div>
|
|
<div style="padding: 8px 0"><a href="$profileUrl">${xmlEncode(%userName)}</a></div>
|
|
#if c.userId == %postAuthor and c.currentPost.subject.len == 0:
|
|
<hr/><a href="${c.genThreadUrl(%postId, "edit", %threadId)}">Edit post</a>
|
|
#elif c.isAdmin and c.currentPost.subject.len == 0:
|
|
<hr/><a style="color: red;" href="${c.genThreadUrl(%postId, "edit", %threadId)}">Edit post</a>
|
|
#end if
|
|
</div>
|
|
</div>
|
|
<div class="topic">
|
|
<div>
|
|
#if %postHeader != "":
|
|
<div class="postTitle">
|
|
<span class="titleHeader">Post:</span>
|
|
<a href="${postUrl}">
|
|
<span>${%postHeader}</span>
|
|
</a>
|
|
</div>
|
|
#end if
|
|
#if not isThread:
|
|
#try:
|
|
${(%postContent).rstToHtml}
|
|
#except EParseError:
|
|
# c.errorMsg = getCurrentExceptionMsg()
|
|
${xmlEncode(%postContent)}
|
|
#end
|
|
#end if
|
|
<span class="date">${xmlEncode(%postCreation)}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
# end for
|
|
</div>
|
|
# if c.pageNum > 1:
|
|
<form action="/search/${$(c.pageNum-1)}" method="post" class="searchNav">
|
|
<input type="hidden" name="q" value="${c.search}">
|
|
<input type="submit" value="Previous ${ThreadsPerPage} results">
|
|
</form>
|
|
# end if
|
|
# if whCount[true] == ThreadsPerPage or whCount[false] == ThreadsPerPage:
|
|
<form action="/search/${$(c.pageNum+1)}" method="post" class="searchNav">
|
|
<input type="hidden" name="q" value="${c.search}">
|
|
<input type="submit" value="Next ${ThreadsPerPage} results (if any)">
|
|
</form>
|
|
# end if
|
|
#end proc
|
|
#
|