Implement inbox with infinite scroll

pull/1/merge
Thibault Duplessis 2012-05-27 17:56:26 +02:00
parent 43254bde81
commit a226e85f0f
12 changed files with 225 additions and 10 deletions

View File

@ -0,0 +1,25 @@
package controllers
import lila._
import views._
import http.Context
import play.api._
import play.api.mvc._
import play.api.mvc.Results._
import scalaz.effects._
object Message extends LilaController {
def api = env.message.api
def forms = env.message.forms
def inbox(page: Int) = Auth { implicit ctx
implicit me
Ok(html.message.inbox(api.inbox(me, page)))
}
def thread(id: String) = TODO
def form = TODO
def create = TODO
def delete(id: String) = TODO
}

View File

@ -35,6 +35,11 @@ final class CoreEnv private (application: Application, val settings: Settings) {
mongodb = mongodb.apply _,
userRepo = user.userRepo)
lazy val message = new lila.message.MessageEnv(
settings = settings,
mongodb = mongodb.apply _,
userRepo = user.userRepo)
lazy val lobby = new lila.lobby.LobbyEnv(
app = app,
settings = settings,

View File

@ -8,6 +8,15 @@ import com.github.ornicar.paginator._
import scala.math.ceil
final class Api(
threadRepo: ThreadRepo,
maxPerPage: Int) {
threadRepo: ThreadRepo,
maxPerPage: Int) {
def inbox(user: User, page: Int): Paginator[Thread] = Paginator(
SalatAdapter(
dao = threadRepo,
query = threadRepo visibleByUserQuery user,
sort = threadRepo.sortQuery),
currentPage = page,
maxPerPage = maxPerPage
) | inbox(user, 1)
}

View File

@ -27,6 +27,10 @@ case class Thread(
def nbUnreadBy(user: User) = isCreator(user).fold(
posts count { post post.isByInvited && post.isUnRead },
posts count { post post.isByCreator && post.isUnRead })
def userIds = List(creatorId, invitedId)
def otherUserId(user: User) = isCreator(user).fold(creatorId, invitedId)
}
object Topic {

View File

@ -14,9 +14,9 @@ final class SiteMenu(trans: I18nKeys) {
val game = new Elem(routes.Game.realtime, trans.games)
val user = new Elem(routes.User.list(page = 1), trans.people)
val forum = new Elem(routes.ForumCateg.index, trans.forum)
val inbox = new Elem(routes.Lobby.home, trans.inbox)
val message = new Elem(routes.Message.inbox(page = 1), trans.inbox)
val all = List(play, game, user, forum)
val all = List(play, game, user, message, forum)
}
object SiteMenu {

View File

@ -13,7 +13,7 @@
@menu
</div>
<div class="all_games infinitescroll">
<div class="pager"><a href="@next">Next</a></div>
<div class="pager none"><a href="@next">Next</a></div>
@game.widgets(paginator.currentPageResults)
</div>
</div>

View File

@ -0,0 +1,42 @@
@(threads: Paginator[lila.message.Thread])(implicit ctx: Context, me: User)
@message.layout(
title = trans.inbox.str()) {
<div class="head">
<h1>@trans.inbox()</h1>
</div>
<table>
@if(threads.nbResults > 0) {
<tbody class="infinitescroll">
@if(threads.hasToPaginate) {
<tr><th class="pager none">
<a href="@routes.Message.inbox(threads.nextPage | 1)">Next</a>
</th></tr>
}
@threads.currentPageResults.map { thread =>
<tr class="paginated_element @thread.isUnReadBy(me).fold(" new", "")">
<td class="subject">
<a href="@routes.Message.thread(thread.id)#bottom">@thread.name</a>
</td>
<td class="author">
@userIdLink(thread.otherUserId(me).toString.some)
</td>
<td class="date">
@showDate(thread.updatedAt)
</td>
</tr>
}
</tbody>
} else {
<tbody>
<tr>
<td colspan="4">
<br />
No message!
</td>
</tr>
</tbody>
}
</tbody>
</table>
}

View File

@ -0,0 +1,19 @@
@(title: String)(body: Html)(implicit ctx: Context)
@moreCss = {
@cssTag("message.css")
}
@moreJs = {
@jsTag("vendor/jquery.infinitescroll.min.js")
}
@base.layout(
title = title,
moreCss = moreCss,
moreJs = moreJs,
active = siteMenu.message.some) {
<div id="lichess_message" class="content_box">
@body
</div>
}

View File

@ -21,7 +21,7 @@ goodies = goodies.some) {
<input id="search_user_input" class="search_user autocomplete" data-provider="@routes.User.autocomplete" />
</form>
<div class="infinitescroll">
<div class="pager"><a href="@routes.User.list(paginator.nextPage | 1)">Next</a></div>
<div class="pager none"><a href="@routes.User.list(paginator.nextPage | 1)">Next</a></div>
<ol start="@{ 1+(paginator.currentPage-1)*paginator.maxPerPage }" class="users paginated_element">
@paginator.currentPageResults.map { u => <li>@userLink(u, None, true)</li> }
</ol>

View File

@ -98,6 +98,13 @@ GET /forum/:categSlug/:slug controllers.ForumTopic.show(categSlug: St
POST /forum/:categSlug/:slug/new controllers.ForumPost.create(categSlug: String, slug: String, page: Int ?= 1)
POST /forum/delete/post/:id controllers.ForumPost.delete(id: String)
# Message
GET /inbox controllers.Message.inbox(page: Int ?= 1)
GET /inbox/new controllers.Message.form
POST /inbox/new controllers.Message.create
GET /inbox/$id<[\w]{8}> controllers.Message.thread(id: String)
POST /inbox/$id<[\w]{8}>/delete controllers.Message.delete(id: String)
# Monitor
GET /monitor controllers.Monitor.index
GET /monitor/stream controllers.Monitor.stream

View File

@ -118,11 +118,11 @@ $(function() {
});
}
$('div.infinitescroll').each(function() {
$('.infinitescroll').each(function() {
$(this).infinitescroll({
navSelector: "div.pager",
nextSelector: "div.pager a:last",
itemSelector: "div.infinitescroll .paginated_element",
navSelector: ".pager",
nextSelector: ".pager a:last",
itemSelector: ".infinitescroll .paginated_element",
loadingText: "",
donetext: "---"
}, function() {

View File

@ -0,0 +1,104 @@
#lichess_message h1 {
font-size: 1.8em;
color: #666;
font-weight: normal;
margin-bottom: 0.5em;
}
#lichess_message {
min-height: 300px;
}
div.sidebar {
margin-top: 30px;
}
div.sidebar a {
display: block;
font-size: 1.2em;
padding: 1em 0 1em 1em;
}
#lichess_message table {
width: 100%;
}
#lichess_message tr {
border-top: 1px solid #e4e4e4;
}
#lichess_message tr.odd {
background: #f4f4f4;
}
#lichess_message td.subject a {
display: block;
padding: 1em;
font-size: 120%;
}
#lichess_message tr.new td.subject a {
color: #0090b0;
font-weight: bold;
}
#lichess_message td.author, #lichess_message td.date {
white-space: nowrap;
padding-right: 1em;
}
#lichess_message div.thread_actions {
margin-top: 0.4em;
float: right;
}
#lichess_message div.thread_message {
font-size: 1.2em;
margin-top: 2em;
border-top: 1px solid #d4d4d4;
padding-top: 2em;
}
#lichess_message div.thread_message span.infos {
margin-bottom: 1em;
display: block;
}
#lichess_message div.answer {
margin-top: 3em;
}
#lichess_message div.form {
font-size: 1.1em;
border-top: 1px solid #d4d4d4;
padding-top: 2em;
}
#lichess_message div.form div.actions,
#lichess_message div.answer div.actions {
padding: 0.5em 0;
font-size: 1.1em;
}
#lichess_message div.form .actions a,
#lichess_message div.answer div.actions a {
margin-left: 1em;
}
#lichess_message label {
float: left;
width: 60px;
text-align: right;
margin-right: 10px;
vertical-align: middle;
margin-top: 3px;
}
#lichess_message .field_to input,
#lichess_message .field_subject input {
width: 450px;
border: 1px solid #D4D4D4;
padding: 3px 5px;
}
#lichess_message .field_to,
#lichess_message .field_subject {
margin-bottom: 1em;
}
#lichess_message form textarea {
width: 547px;
height: 150px;
padding: 10px;
border: 1px solid #D4D4D4;
}
#lichess_message ul {
color: red;
margin-left: 60px;
}