nimforum/forms.tmpl
2018-05-09 19:02:18 +01:00

589 lines
19 KiB
Cheetah

#? stdtmpl | standard
#
#template `!`(idx: untyped): untyped =
# row[idx]
#end template
#
#
#proc genThreadsList(c: TForumData, count: var int): string =
# const queryModAdmin = sql"""select id, name, views, modified from thread
# where id in (select thread from post where author in
# (select id from person where status not in ('Spammer') or id = ?))
# order by modified desc limit ?, ?"""
# const query = sql"""select id, name, views, modified from thread
# where id in (select thread from post where author in
# (select id from person where status not in ('Moderated', 'Spammer') or id = ?))
# 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, if c.rank >= Moderator: queryModAdmin else: query,
# c.userId, $((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: 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>
<script>appendRunBtn()</script>
</div>
#end proc
#
#
#proc genPostsList(c: TForumData, threadId: string, count: var int): string =
# let 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 = ? and $#
# and (u.status <> 'Spammer' or p.author = ?)
# order by p.id limit ?, ?""" %
# (if c.rank >= Moderator: "(1 or u.id = ?)" else: "(u.status <> 'Moderated' or p.author = ?)"))
# 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.userId, c.userId, $((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> &gt;
<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.rank >= Moderator 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"><a href="${c.genThreadUrl(!postId, "", $threadId, $(c.pageNum))}">${xmlEncode(!postCreation)}</a></span>
</div>
</div>
</div>
# end for
<script>
// tiny helper that run the code in the playground
function appendEachRunBtn(element) {
if (element.getElementsByClassName("runDiv").length>0){
return; // already has a run btn
}
var runDiv = document.createElement("DIV");
var btn = document.createElement("BUTTON");
var t = document.createTextNode("Run");
var playLink = document.createElement("a")
var code = element.textContent;
var spinners = [" ◆ "," ◇ "];
playLink.title = "Edit in playground"
playLink.textContent = "Edit"
playLink.setAttribute('href', "https://play.nim-lang.org?code="+encodeURIComponent(code));
playLink.setAttribute("class", "button");
playLink.setAttribute("target", "_blank");
runDiv.setAttribute("class", "runDiv");
btn.appendChild(t);
btn.onclick = function(){
var httpRequest = new XMLHttpRequest();
var start = null;
httpRequest.open("POST", "https://play.nim-lang.org/compile", true);
btn.textContent = spinners[1];
function step(timestamp) {
if (!start) start = timestamp;
if (timestamp - start > 500) {
if (btn.textContent == spinners[0]) { btn.textContent = spinners[1] }
else { btn.textContent = spinners[0] }
start = null;
}
if (httpRequest.status != 200){ window.requestAnimationFrame(step) }
else { btn.textContent = "Run" }
}
function displayContents(e){
if (httpRequest.readyState!=httpRequest.DONE){ return }
if (httpRequest.status == 200){
var res = JSON.parse(httpRequest.responseText);
// this works because only 1 `resDiv` is inside `element`
var resDiv = element.getElementsByClassName("resDiv")[0];
if (resDiv == null) {
resDiv = document.createElement("DIV");
runDiv.appendChild(resDiv);
}
if (res.compileLog.lastIndexOf("[SuccessX]") != -1){
resDiv.textContent = res.log;
resDiv.setAttribute("class", "resDiv successComp");
} else {
resDiv.textContent = res.compileLog;
resDiv.setAttribute("class","resDiv failedComp");
}
} else {
console.log("There was a problem with the request.");
}
}
httpRequest.onreadystatechange = displayContents;
httpRequest.send(JSON.stringify({"code": code, "compilationTarget": "c"}));
window.requestAnimationFrame(step);
}
runDiv.appendChild(document.createElement("HR"));
runDiv.appendChild(btn);
runDiv.appendChild(playLink);
element.appendChild(runDiv);
}
function appendRunBtn(){
var els = Array.prototype.slice.call(document.getElementsByClassName("langNim"));
els.forEach(appendEachRunBtn, this);
}
appendRunBtn()
</script>
</div>
#end proc
#
#proc genMarkHelp(): string
#end proc
#proc genFormPost(c: 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> &gt;
$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" />
${genMarkHelp()}
</form>
</div>
#end proc
#
#
#proc genFormRegister(c: TForumData): string =
# result = ""
<div id="talk-head">
<div class="info-post">
<div>
<a href="${c.req.makeUri("/")}"><b>forum index</b></a> &gt;
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" /></td>
</tr>
<tr>
<td>${fieldValid(c, "email", "E-Mail:")}</td>
<td>${textWidget(c, "email", reuseText, maxlength=300)}</td>
</tr>
#if useCaptcha:
<tr>
<td>${fieldValid(c, "g-recaptcha-response", "Captcha:")}</td>
<td>${captcha.render(includeNoScript=true)}</td>
</tr>
#end if
</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 genFormSetRank(c: TForumData; ui: TUserInfo): string =
# result = ""
<form action="${c.req.makeUri("/dosetrank/" & ui.nick, false)}" method="POST">
<table border="0">
<tr>
<th>Reason</th>
<td>${textWidget(c, "reason", ui.ban, maxlength=100)}</td>
</tr>
<tr>
<th>Rank</th>
<td><select name = "rank">
# for i in low(Rank)..high(Rank):
<option ${if i == ui.rank: "selected" else: ""}>
$i
</option>
# end for
</td></select>
</tr>
</table>
<input type="submit" value="Change">
</form>
#end proc
#
#proc genFormLogin(c: 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: 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> &nbsp;|&nbsp;
<b>${stats.totalThreads}</b> threads &nbsp;|&nbsp; <b>${stats.totalPosts}</b> posts &nbsp;|&nbsp;
newest member: <a href="$profileUrl">${stats.newestMember.nick}</a>
#end proc
#
#
#
#
#proc genSearchResults(c: TForumData,
# results: iterator: db_sqlite.Row {.closure, tags: [ReadDbEffect].},
# 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("&quot;","\""))}</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.rank >= Moderator 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
#
#
#proc genFormResetPassword(c: TForumData): string =
# result = ""
<div id="talk-head">
<div class="info-post">
<div>
<a href="${c.req.makeUri("/")}"><b>forum index</b></a> &gt;
Reset Password
</div>
</div>
</div>
<form action="${c.req.makeUri("/doresetpassword", false)}" method="POST">
<table border="0">
<tr>
<td>${fieldValid(c, "nick", "Your nickname:")}</td>
<td><input type="text" name="nick" maxlength="20" /></td>
</tr>
#if useCaptcha:
<tr>
<td>${fieldValid(c, "g-recaptcha-response", "Captcha:")}</td>
<td>${captcha.render(includeNoScript=true)}</td>
</tr>
#end if
</table>
#if c.errorMsg != "":
<div style="float: left; width: 100%;">
<span class="error">$c.errorMsg</span>
</div>
#end if
<input type="submit" value="Email me">
</form>
#end proc
#proc genMarkHelp(): string =
#result = ""
<div id="markhelp">
<p>nimforum uses a slightly-customized version of
<a href="http://www.sphinx-doc.org/en/stable/rest.html">reStructuredText</a> for formatting. See below for some basics, or check
<a href="/rst">this link</a> for a more detailed help reference.</p>
<table class="rst">
<tbody>
<tr class="markheading">
<td><em>you type:</em>
</td>
<td><em>you see:</em>
</td>
</tr>
<tr>
<td>*italics*</td>
<td><em>italics</em>
</td>
</tr>
<tr>
<td>**bold**</td>
<td><b>bold</b>
</td>
</tr>
<tr>
<td>`nim! &lt;http://nim-lang.org&gt;`_</td>
<td><a href="http://nim-lang.org">nim!</a>
</td>
</tr>
<tr>
<td>* item 1
<br>* item 2
<br>* item 3</td>
<td>
<ul>
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
</ul>
</td>
</tr>
<tr>
<td>&gt; quoted text</td>
<td>
<blockquote>quoted text</blockquote>
</td>
</tr>
<tr>
<td>The forum supports the Github Markdown syntax
<br>for code listings:
<br>
<br>```nim
<br>if 1 * 2 &lt; 3:
<br><span class="spaces">&nbsp;&nbsp;</span>echo "hello, world!"
<br>```
<br>
</td>
<td>The forum supports the Github Markdown syntax
<br>for code listings:
<br>
<pre class="listing">
<span class="Keyword">if</span> <span class="DecNumber">1</span><span class=
"Operator">*</span><span class="DecNumber">2</span> <span class=
"Operator">&lt;</span> <span class="DecNumber">3</span><span class=
"Punctuation">:</span>
<span class="Identifier">echo</span> <span class=
"StringLit">"hello, world!"</span>
</pre>
</td>
</tr>
<tr>
<td>A horizontal rule can be created<br/>----<br/>but it needs text after it</td>
<td>A horizontal rule can be created<hr/>but it needs text after it</td>
</tr>
</tbody>
</table>
</div>
#end proc