module ForumTags include Radiant::Taggable include ActionView::Helpers::UrlHelper include ActionController::UrlWriter include I18n class TagError < StandardError; end tag 'forum' do |tag| tag.expand end tag 'forum:topics' do |tag| tag.expand end desc %{ Renders a standard list of recent topics. Pass a 'limit' parameter to set the length of the list: default is 10.

      
      # is the same as:
      

} tag 'forum:topics:latest' do |tag| limit = (tag.attr['limit'] || 10).to_i output = "" output end desc %{ Loops over the most recently-updated forum topics. Supply a `limit` attribute to set the number of topics shown. The default is 10. Within the loop you can use all the usual r:forum:topic and r:forum:post tags. The post tags will refer to the latest reply (or to the first post if there are no replies). } tag 'forum:topics:each' do |tag| output = [] limit = (tag.attr['limit'] || 10).to_i Topic.latest(limit).each do |topic| tag.locals.topic = topic tag.locals.post = topic.posts.last output << tag.expand end output end tag 'forum:topic' do |tag| tag.locals.topic = Topic.find( tag.attr['id'] ) unless tag.attr['id'].blank? raise TagError, "can't have forum:topic without a topic" unless tag.locals.topic tag.expand end desc %{ Renders a standard, minimal topic list item consisting of link and explanation. This is the shorthand used by forum:topics:latest but it can also be used in other settings.

      
      # is the same as:
      

  • } tag 'forum:topic:summary' do |tag| "
  • #{tag.render('forum:topic:link')}
    #{tag.render('forum:topic:context')}
  • " end desc %{ Renders the url of the current topic. } tag 'forum:topic:url' do |tag| forum_topic_path(tag.locals.topic.forum, tag.locals.topic) end desc %{ Renders a link to the current topic using its name as the text. } tag 'forum:topic:link' do |tag| options = tag.attr.dup anchor = options['anchor'] ? "##{options.delete('anchor')}" : '' attributes = options.inject('') { |s, (k, v)| s << %{#{k.downcase}="#{v}" } }.strip attributes = " #{attributes}" unless attributes.empty? text = tag.double? ? tag.expand : tag.render('forum:topic:name') %{#{text}} end tag 'link' do |tag| end desc %{ Renders the name of the reader who started the current topic. } tag 'forum:topic:author' do |tag| tag.locals.topic.reader.name end desc %{ Renders the name of the current topic. } tag 'forum:topic:name' do |tag| tag.locals.topic.name end desc %{ Renders the (sanitized and textilized) body of the first post in the current topic. } tag 'forum:topic:body' do |tag| tag.locals.topic.posts.first.body_html end desc %{ Renders the usual context line for the current topic, but with no date. } tag 'forum:topic:context' do |tag| output = [] topic = tag.locals.topic if tag.locals.topic.has_replies? output << I18n.t('reply_from') output << %{#{tag.locals.topic.replied_by.name}} else output << I18n.t('started_by') output << %{#{tag.render('forum:topic:author')}} end output.join(' ') end desc %{ Renders the creation date of the current topic in a colloquial form. } tag 'forum:topic:date' do |tag| I18n.l tag.locals.topic.created_at, :format => :standard end desc %{ Renders the reply date of the current topic in a colloquial form. } tag 'forum:topic:replydate' do |tag| I18n.l tag.locals.topic.replied_at, :format => :standard end tag 'forum:posts' do |tag| tag.expand end desc %{ Loops over the posts most recently added. In effect this is very similar to calling r:topics:each, but there are some differences: * page comments and any other non-topic posts are included * here r:post tags always refer to the current post. Within the topics:each loop they always refer to the last reply to that topic. * tag.locals.page is set if the foreground post is a page comment, so you can use all the usual radius tags for that page. Supply a `limit` attribute to set the number of posts shown. The default is 10. } tag 'forum:posts:each' do |tag| results = [] limit = (tag.attr['limit'] || 10).to_i Post.latest(limit).each do |post| tag.locals.post = post tag.locals.topic = post.topic tag.locals.page = post.page results << tag.expand end results end desc %{ This tag is generally used in double form or as a silent prefix, where it will just expand:
    
          
          # or just
          
        
    But if used in single form it will return a standard, minimal post list item consisting of link and explanation:
    
          
          # is the same as:
          

  • Note that the text of the link will be the name of the topic or page to which this post is attached, and that within a topics:each loop any r:forum:post tags will show the last post to the topic. } tag 'forum:post' do |tag| tag.locals.post = Post.find(tag.attr['id']) unless tag.attr['id'].blank? raise TagError, "can't have forum:post without a post" unless tag.locals.post tag.expand if tag.locals.post end desc %{ Renders a url (with pagination and anchor) for the current post. Within a topics:each loop this is a way to link to the last post. } tag 'forum:post:url' do |tag| paginated_post_path(tag.locals.post) end desc %{ Renders a title that can be used over the post: this will be the name of its page or topic. } tag 'forum:post:name' do |tag| tag.locals.post.holder.title end desc %{ Renders a link to the current post. The link text will be the page or topic title and within that the destination of the link will be the page and anchor for this post. } tag 'forum:post:link' do |tag| link_to tag.render('forum:post:name'), tag.render('forum:post:url') end desc %{ Renders the name of the author of this post. } tag 'forum:post:author' do |tag| tag.locals.post.reader.name end desc %{ Renders the (sanitized and textilized) body of the current post. } tag 'forum:post:body' do |tag| tag.locals.post.body_html end desc %{ Renders a description line for the current post, which is usually something like 'comment added by', 'new reply from' or 'new topic begun by' followed by the author's name and the colloquial form of the creation date. } tag 'forum:post:context' do |tag| output = [] post = tag.locals.post if post.page output << I18n.t('new_comment_from') elsif post.first? output << I18n.t('new_reply_from') else output << I18n.t('new_topic_from') end output << %{#{tag.render('forum:post:author')}} output << tag.render('forum:post:date') output.join(' ') end desc %{ Renders the creation date of the current post } tag 'forum:post:date' do |tag| I18n.l tag.locals.post.created_at, :format => :standard end # page comments are just a special case of posts that have a page but not topic # there is the difference that we generally want to display the whole set # and the added complication that they should be paginated. # but we only need to define some more collection and summary tags and set the post collection appropriately desc %{ The address for add-a-comment links } tag 'comment_url' do |tag| add_comment_path(tag.locals.page) end tag 'comment_link' do |tag| options = tag.attr.dup if tag.locals.page.still_commentable? attributes = options.inject('') { |s, (k, v)| s << %{#{k.to_s.downcase}="#{v}" } }.strip text = tag.double? ? tag.expand : I18n.t("add_comment") %{#{text}} else I18n.t("comments_closed") end end desc %{ Anything between if_comments tags is displayed only - dramatic pause - if there are comments. } tag 'if_comments' do |tag| tag.expand if tag.locals.page.posts.any? end desc %{ Anything between unless_comments tags is displayed only if there are no comments. *Usage:*
    ...
    } tag 'unless_comments' do |tag| tag.expand unless tag.locals.page.posts.any? end tag 'comments' do |tag| tag.expand if tag.locals.page.commentable? end desc %{ Renders string (internationalised) like "1 comment", "27 comments" or "no comments yet". } tag 'comments:summary' do |tag| if tag.locals.posts.respond_to? :total_entries I18n.t("comment_count", :count => tag.locals.posts.total_entries) else I18n.t("comment_count", :count => tag.locals.posts.length) end end desc %{ Loops over the (paginated) comment set in ascending order of date. Within the loop you can use the r:comment shorthand or any r:forum:post:* tags. Note that r:forum:topic tags won't work: there is no topic to show. } tag 'comments:each' do |tag| results = [] if paging = pagination_find_options tag.locals.posts = tag.locals.paginated_list = page.posts.paginate(paging) else tag.locals.posts = page.posts end tag.locals.posts.each do |post| tag.locals.post = post results << tag.expand end results << tag.render('pagination', tag.attr.dup) if paging results end desc %{ A useful shortcut: To enable page commenting, all you have to do is put this in your layout:
    It will display a (paginated) list of page comments followed by an 'add comment' link that you can hook into using the supplied forum javascript or your own equivalent. } tag 'comments:all' do |tag| if tag.attr['paginated'] == 'true' tag.locals.posts = tag.locals.paginated_list = tag.locals.page.posts.paginate(pagination_parameters) else tag.locals.posts = tag.locals.page.posts end results = "" results << %{
    } results << %{

    #{tag.render('comments:summary')}

    } tag.locals.posts.each do |post| tag.locals.post = post results << tag.render('comment') end results << %{

    #{tag.render('comment_link', 'class' => 'remote')}

    } results << tag.render('pagination', tag.attr.dup) results << "
    " results end desc %{ A useful shortcut that renders an entire post - in much the same way as a post would appear in the forum - so that it can be displayed as a comment on the page. } tag 'comment' do |tag| raise TagError, "can't have r:comment without a post" unless post = tag.locals.post if tag.double? tag.locals.reader = post.reader tag.expand else output = %{
    } output << %{
    } output << %{

    #{tag.render("forum:post:reader")}

    } output << %{

    #{tag.render("forum:post:context")}

    } output << %{
    } output << %{
    } output << tag.render("forum:post:body") output end end end