scala-news-reader
rss/atom news reader in scala
git clone https://9o.is/git/scala-news-reader.git
ArticleSnip.scala
(7324B)
1 package com.joereader.snippet
2
3 import net.liftweb._
4 import common._
5 import http._
6 import SHtml._
7 import js._
8 import JsCmds._
9 import util._
10 import Helpers._
11 import sitemap.Loc
12
13 import com.joereader._
14 import com.joereader.actor.EntriesEngine._
15 import config._
16 import lib.rss._
17 import model._
18 import Article._
19
20 import dispatch._
21 import Defaults._
22 import xml._
23 import java.util.Date
24
25 import net.liftmodules.extras.SnippetHelper
26
27 /**
28 * Mix this in to list articles.
29 */
30 trait ArticleSnip {
31
32 def noArticles: CssSel =
33 ".reader-nav [class+]" #> "hide" &
34 ".article *" #>
35 <p style="padding: 200px 0; text-align: center">
36 No articles to display here
37 </p>
38
39 def articles(articles: List[Article]): CssSel =
40 if (articles.isEmpty) noArticles
41 else ".article *" #> sort(articles).map {
42 article =>
43
44 def bwu = article.bwu
45 def sharedBy = article.sharedBy
46 def entry = article.entry
47 def shareId = article.toString + "-share"
48 def saveId = article.toString + "-save"
49 def color = "color:" + bwu.color
50
51 def saveLink: NodeSeq = a(
52 () => {
53 article.save
54 Replace(saveId, unSaveLink)
55 }: JsCmd,
56 Text("Save"),
57 "id" -> saveId,
58 "style" -> color)
59
60 def unSaveLink: NodeSeq = a(
61 () => {
62 article.unSave
63 Replace(saveId, saveLink)
64 }: JsCmd,
65 Text("Undo Save"),
66 "id" -> saveId,
67 "style" -> color)
68
69 def shareLink: NodeSeq = a(
70 () => {
71 article.share
72 Replace(shareId, unShareLink)
73 }: JsCmd,
74 Text("Share"),
75 "id" -> shareId,
76 "style" -> color)
77
78 def unShareLink: NodeSeq = a(
79 () => {
80 article.unShare
81 Replace(shareId, shareLink)
82 }: JsCmd,
83 Text("Undo Share"),
84 "id" -> shareId,
85 "style" -> color)
86
87 def articleSave =
88 if (User.isLoggedIn)
89 if (article.saved)
90 unSaveLink
91 else
92 saveLink
93 else
94 NodeSeq.Empty
95
96 def articleShare =
97 if (User.isLoggedIn)
98 if (article.shared)
99 unShareLink
100 else
101 shareLink
102 else
103 NodeSeq.Empty
104
105 ".article-save" #> articleSave &
106 ".article-share" #> articleShare &
107 ".article-inner [style]" #> ("border-right:3px solid " + bwu.color) &
108 ".article-sharedby *" #> sharedBy.map {
109 bwu =>
110 "a *" #> s"Shared by ${bwu.name}" &
111 "a [href]" #> bwu.user.map(Site.userProfileLoc.calcHref) &
112 "img [src]" #> bwu.image
113 } &
114 ".article-key [class+]" #> bwu.toString &
115 ".article-user-link [href]" #> bwu.link &
116 "#article-user-image [src]" #> bwu.image &
117 "#article-user-name *" #> bwu.name &
118 ".timeago [datetime]" #> entry.dateFormatted &
119 ".title a [href]" #> entry.link &
120 ".title a [rel]" #> "nofollow" &
121 ".title a *" #> entry.title &
122 "#article-content" #> entry.content
123 } &
124 "#reader-writers" #> {
125 "#writer" #> articles.distinct.groupBy(_.bwu).map {
126 f =>
127 val bwu = f._1
128
129 "#writer [id]" #> bwu.toString &
130 "#writer-image [src]" #> bwu.image &
131 "#writer-name *" #> bwu.name &
132 "a [href]" #> bwu.link
133 }
134 }
135 }
136
137 /**
138 * This is where the magic happens. Based on page location,
139 * get the articles that you need from here.
140 */
141 object Articles extends ArticleSnip with SnippetHelper with Logger {
142
143 protected def serveArticles(snip: Loc[_] => List[Article]) =
144 (for {
145 loc <- S.location ?~ "Location not found"
146 } yield {
147 articles {
148 snip(loc)
149 }
150 }): Box[CssSel]
151
152 def render: CssSel = serveArticles {
153 loc =>
154 import Site._
155
156 def name(m: MenuLoc) = m.menu.loc.name
157 def testing = TestUser.isLoggedIn
158
159 // reader.html
160 if (name(reader) == loc.name && testing) {
161 followingArticles ::: followingSharedArticles
162 }
163
164 // index.html
165 else if (name(home) == loc.name) {
166 def blog = Blog.findByBlogName("readmeans")
167 blogArticles(blog).headOption.toList
168 }
169
170 // saved.html
171 else if (name(savedArticles) == loc.name && testing) {
172 userSaved
173 }
174
175 // /*[User].html
176 else if (userProfileLoc.name == loc.name) {
177 def user = userProfileLoc.currentValue
178 userArticles(user) ::: userShared(user)
179 }
180
181 // /blog/*[Blog].html
182 else if (blogProfileLoc.name == loc.name) {
183 def blog = blogProfileLoc.currentValue
184 blogArticles(blog)
185 }
186
187 // /blog/*[Blog]/*[BlogWriter].html
188 else if (blogWriterProfileLoc.name == loc.name) {
189 def blogWriter = blogWriterProfileLoc.currentValue
190 blogWriterArticles(blogWriter)
191 }
192
193 // Nothing
194 else {
195 warn("Called Articles snippet from a page" +
196 " that cannot be handled")
197 Nil
198 }
199 }
200
201 def blogWriterArticles(bwu: Box[BlogWriterUser]) =
202 (for {
203 bwu <- bwu
204 blog <- bwu.blog
205 blogWriter <- bwu.blogWriter
206 } yield {
207 entries(blog).
208 filter(_.author.name == blogWriter.name.get).
209 map(new Article(new BlogWriterUser(blog, blogWriter), _))
210 }) openOr Nil
211
212 /* Articles from a blog. */
213 def blogArticles(blog: Box[Blog]) =
214 (for (blog <- blog) yield {
215 entries(blog).
216 filter(e => blog.writers.existsStr(e.author.name)).
217 map {
218 entry =>
219 val blogWriter = blog.writers.findStr(entry.author.name)
220 val bwu = new BlogWriterUser(
221 blogWriter.flatMap(_.user.obj), Some(blog), blogWriter)
222 new Article(bwu, entry)
223 }
224 }) openOr Nil
225
226
227
228 /* Articles written by user. */
229 def userArticles(user: Box[User]) =
230 (for (user <- user)
231 yield (for {
232 blogs <- user.blogs.get
233 blog <- Blog.find(blogs)
234 blogWriter <- blog.writers.find(user)
235 } yield {
236 entries(blog).
237 filter(_.author.name == blogWriter.name.get).
238 map(new Article(new BlogWriterUser(user, blog, blogWriter), _))
239 }) flatten
240 ) openOr Nil
241
242 /*
243 * All articles by blog writers that the
244 * logged in user follows.
245 */
246 def followingArticles =
247 (for (user <- User.currentUser)
248 yield (for (bwu <- user.following.allUsers)
249 yield (for {
250 blog <- bwu.blog
251 blogWriter <- bwu.blogWriter
252 } yield {
253 entries(blog).
254 filter(_.author.name == blogWriter.name.get).
255 map(new Article(bwu, _))
256 }) getOrElse Nil
257 ) flatten
258 ) openOr Nil
259
260
261 /*
262 * All articles shared by blog writers that the
263 * logged in user follows.
264 */
265 def followingSharedArticles = User.currentUser.map {
266 _.following.usersSharedArticles.flatMap(_.shared.get)
267 } openOr Nil
268
269 /* The logged in user's saved articles. */
270 def userSaved = User.currentUser.map(_.saved.get) openOr Nil
271
272 /* Articles shared by user. */
273 def userShared(u: Box[User]) = u.map(_.shared.get) openOr Nil
274
275 }
276
277