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