Junkfood

Food and Junk.

All | Food | Junk | Work

20050127 Thursday January 27, 2005

Roller: Navigation Bar Improvement

The current behavior of the Navigation Bar (the one on my page, at the right, that starts with "Sun Bloggers" and "Weblog") is that if a Roller user logs into the system, the Navigation Bar also contains "New Entry", "Settings", and "Logout". It makes sense if I (the page owner) am the one looking at this page. However, for other Roller users who happen to see this on my page, it may be somewhat confusing. Similarly, when I am logged in and look at other users' pages, I see a "New Entry" link which is confusing for me.

The improved behavior is that "New Entry", "Settings", and "Logout" is seen in the Navigation Bar only when I (the page owner) am logged in. Other logged-in users don't see these links. Non-logged in users see a link to "Login". The below macro contains the fix. It overrides an existing Roller macro.

#macro( showNavBar2 $vertical $delimiter $useCSS)
    #set( $container = "div" )
    #if ( $useCSS ) #set( $container = "ul" ) #end
    #set( $rawUrl = "$ctxPath/page/$userName" )
    <$container class="rNavigationBar">
    #if ($siteName=="Main")
        #set( $mainUrl = "$ctxPath?rmk=tabbedmenu.main&amp;rmik=tabbedmenu.main" )
        #printNavLink( $mainUrl $text.get("navigationBar.main") $useCSS $vertical "" )
    #else
        #printNavLink( "$ctxPath/" $siteName $useCSS $vertical "" )
    #end
    #if( $website )
        #foreach( $iPage in $pages )
            #set( $invisible = $iPage.Name.startsWith("_") )
            ## Again, there is no "break" in Velocity
            #if( !$invisible )
                #set( $isSelected = false )
                #if( $page && $iPage.Id == $page.Id && 
!$editorui) #set($isSelected = true) #end

                #if( !$isSelected )
                    #printNavLink( "$rawUrl/$iPage.Link" $iPage.Name 
$useCSS $vertical $delimiter )
                #else
                    #if( $useCSS )<li class="rNavItem">
                    #elseif( $vertical ) <br />
                    #else $delimiter
                    #end
                    $iPage.Name
                #end
            #end
        #end
    #end

    ## strutsUrlHelper( useIds, isAction, path, val1, val2)
    #if ($req.getUserPrincipal())
        ## // The person looking at the page is logged into Roller.
        #if ($req.getUserPrincipal().getName().equals($userName))
            ## // The person looking at the page is this blog's owner
            ## // who is also currently logged in.
            #set( $editUrl = $rawUrl )
            #set( $editUrl = $pageHelper.strutsUrlHelper(false, true, 
"weblogCreate", "tabbedmenu.weblog", "tabbedmenu.weblog.newEntry") )
            #printNavLink( $editUrl $text.get("navigationBar.newEntry") 
$useCSS $vertical $delimiter )

            #set( $editUrl = $rawUrl )
            #set( $editUrl = $pageHelper.strutsUrlHelper(false, true, 
"editWebsite", "tabbedmenu.website", "tabbedmenu.website.settings") )
            #printNavLink( $editUrl $text.get("navigationBar.settings") 
$useCSS $vertical $delimiter )
            #set( $editUrl = $rawUrl )
            #set( $editUrl = $pageHelper.strutsUrlHelper(false, true, 
"logout-redirect", "", "") )
            #printNavLink( $editUrl $text.get("navigationBar.logout") 
$useCSS $vertical $delimiter )
        #else
            ## // The person looking at the page is the owner of a
            ## // different blog.  They are logged in.
        #end
    #else
        ## // The user is not logged into Roller.
        #set( $editUrl = $pageHelper.strutsUrlHelper(false, true, "login-redirect", 
"", "") )
        #printNavLink( $editUrl $text.get("navigationBar.login") $useCSS $vertical 
$delimiter )

        #if ($req.getAttribute("allowNewUsers"))
            #set( $registerUrl = $pageHelper.strutsUrlHelper(false, true, 
"registerUser", "", "") )
            #printNavLink( $registerUrl $text.get("navigationBar.register") $useCSS 
$vertical $delimiter )
        #end
    #end
    </$container >
#end

(Some long lines have been broken into separate lines, so you may need to join them back together manually.)

(2005-01-27 13:00:00.0) Permalink | Comments [1]

20050125 Tuesday January 25, 2005

Example of Improved Permalink Format

(2005-01-25 09:40:49.0) Permalink |

Roller: Improved Permalink Format

In most blogs I've seen, a Permalink for an entry is a URL that points to a page containing just that entry, along with that entry's comments. However, Roller uses Permalink URLs that contain a date and point to a page containing all entries from that date and earlier (containing the entry specified, along with a whole bunch of other entries). This is so, even though Roller already has the capability to generate pages that look like "standard" Permalink pages.

If you look at the URL for any Roller blog entry's "Comments" page, you'll see that it is very similar to a "standard" Permalink URL. And, if you follow the Comments link, the resulting page looks very much like a "standard" Permalink page. In fact, if we take a Roller comments page URL and simply remove the "#comments" anchor from the end, it makes a pretty good alternate Permalink.

The below macro overrides the standard Roller macro for generating Permalink URLs, to use the alternate format. The diff is also below. Because I do not know whether overriding the Permalink URL format might have any side effects (within Roller or for outside agents/aggregators), I have not implemented it on my blog. (I have tested it, and it appears to work just fine.) This macro needs to be put in the "_day" template. Putting it in the "Weblog" template does not work.

#macro( showEntryPermalink $entry )
    <a href="$ctxPath/page/$userName/$page.link/$utilities.encode($entry.anchor)"
        title="$text.get( "macro.weblog.entrypermalink.title" )"
        class="entrypermalink">Permalink</a>
    #if ($pageHelper.isUserAuthorizedToEdit())
        [<a href="$pageHelper.getEntryEditUrl($entry)">
        $text.get( "macro.weblog.entrypermalink.edit" )</a>]
    #end
#end

2c2
<     <a href="$baseURL$entry.permaLink"
---
>     <a href="$ctxPath/page/$userName/$page.link/$utilities.encode($entry.anchor)"

(2005-01-25 09:24:00.0) Permalink | Comments [3]

20050124 Monday January 24, 2005

Roller: Re-ordering the Category Bar

The following macro allows you to re-order Categories shown by the showWeblogCategoryChooser macro. Specifically, it alphabetically sorts Categories by their Descriptions. I don't think that the Description field is used elsewhere, so it is probably safe to use it as a sorting key.

#macro( showWeblogSubcategoryChooser2 $parentCategory $divider )
    #set( $rawUrl = "$ctxPath/page/$userName/$page.link" )

    <div class="rWeblogCategoryChooser">
    #set( $weblogUrl = $rawUrl )
    #set( $chosenCat = "" )
    #if( $req.getParameter( $WEBLOGCATEGORYNAME_KEY ) )
        #set( $chosenCat = $req.getParameter( $WEBLOGCATEGORYNAME_KEY ) )
        <span class="rUnchosenCategory"><a href="$weblogUrl">
        $text.get( "macro.weblog.allcategories" )</a></span>
    #else
        <span class="rChosenCategory">$text.get( "macro.weblog.allcategories" )</span>
    #end

    #if ( $req.getParameter($PAGEID_KEY)  )
        #set( $pageParam = "&$PAGEID_KEY=$req.getParameter($PAGEID_KEY)" )
    #end
    #set( $rawcats = $pageModel.getWeblogCategories($parentCategory) )
    ## // Sort categories by description, using a bubble sort.
    ## // The "All" category is not sorted; it's always first.
    #set( $cats = [] )
    #foreach( $rawcat in $rawcats )
       #set ($curcat = $rawcat)
       #set ($catcounter = 0)
       #foreach ($cat in $cats)
            #if ($curcat.description.compareTo($cat.description) < 0)
                #set ($curcat = $cats.set($catcounter, $curcat))
            #end
            #set ($catcounter = $catcounter + 1)
        #end
        #if ($cats.add($curcat))
        #end
    #end
    #foreach( $cat in $cats )
        ## $pageHelper.strutsUrlHelper() wasn't working, so do it manually
        #set( $catParam = "?$WEBLOGCATEGORYNAME_KEY=$utilities.encode($cat.path)" )
        #set( $weblogUrl = "$rawUrl$catParam$!pageParam" )
        $divider
        #if( $chosenCat == $cat.path )
            <span class="rChosenCategory">$cat.Name</span>
        #else
            <span class="rUnchosenCategory"><a href="$weblogUrl">$cat.Name</a></span>
        #end
    #end
    </div>
#end

The macro does not change category order anywhere else. Specifically, it does not change it in the Search drop-down menu or in the New Weblog Entry category drop-down menu (and therefore the default category for new entries is also unchanged). It also doesn't change the position of the "All" category (which is always in the first position).

I'm not sure how Roller orders categories by default. It's either reverse alphabetical order by name or reverse of the order that the categories were added.

(2005-01-24 13:00:00.0) Permalink |

20050120 Thursday January 20, 2005

Roller: Macro Customization and Hacking

Most Roller customization documents I've read seem to deal with customizing the look of the weblog by editing page templates or CSS stylesheets. However, they are not helpful if what you want to change is output produced by Roller macros. Here are some tips for writing/customizing Roller macros (levels 4 and 5 of the Levels of Roller Customization below).

Levels of Roller Customization (from high to low-level):

  1. Edit CSS stylesheets to customize styles.
  2. Edit page templates to add/delete/move page elements and Roller macros.
  3. Select different theme packages to get different base page templates and CSS stylesheets.
  4. Create and use new macros.
  5. Override existing Roller macros.
  6. Change Roller configuration and installation.
  7. Change Apache configuration.
  8. Edit Roller source code.

Unfortunately, the documentation you need is scattered across many different sites. Specifically, you need documentation on Roller macros, Roller templates, Roller Java source code, the Velocity Template Language, and the Java programming language.

  1. The Roller source code can be downloaded at: https://roller.dev.java.net/servlets/ProjectDocumentList?folderID=2525&expandFolder=2525&folderID=0
    1. The Roller Velocity macros are in roller/web/WEB-INF/classes/*.vm
    2. The themes are in roller/web/themes/*. They are useful to see what can be done by simply editing CSS and page templates.
    3. The Java source code is in roller/src/*. You need it to be able to discover the many useful (but undocumented) Roller variables. You'll also want to see how the hardcoded functions work. The most interesting classes are:
      • org.roller.pojos.CommentData
      • org.roller.pojos.PageData
      • org.roller.pojos.RefererData
      • org.roller.pojos.WeblogCategoryData
      • org.roller.pojos.WeblogEntryData
      • org.roller.pojos.WebsiteData
      • org.roller.presentation.velocity.PageHelper
      • org.roller.presentation.velocity.PageModel
      • org.roller.business.RefererManagerImpl
      • org.roller.business.WeblogManagerImpl
      • org.roller.util.*
  2. Roller documentation is available at:
    1. User Guide (incomplete, but an okay start): http://www.rollerweblogger.org/wiki/Wiki.jsp?page=UserGuide
    2. Macro and Variable Reference (very incomplete): http://www.rollerweblogger.org/wiki/Wiki.jsp?page=RollerMacros
  3. Velocity documentation is needed to learn how to program in the Velocity Template Language. Specifically, you'll need:
    1. User Guide: http://jakarta.apache.org/velocity/user-guide.html
    2. Reference Guide (really, it's the second half of the User Guide): http://jakarta.apache.org/velocity/vtl-reference-guide.html
  4. Java documentation is needed to find out what can be done with Velocity objects. You will probably need to know how to program in the Java language. Documentation is at: http://java.sun.com/j2se/1.4.2/docs/api/index.html. The most useful classes are:
    1. java.lang.String
    2. java.util.ArrayList
    3. java.util.Map

Customization at this level is really just programming: writing new macros and re-writing the Roller macros. This requires knowledge of the Velocity Template Language (which is a programming language). It also requires knowledge of Java since Velocity is designed to interface with Java. Its basic variable types (String, ArrayList, Map) are Java objects whose methods are available to be used (if you know how). Roller is written in Java, and its objects, variables, and methods can also be used. Unfortunately, Roller is poorly documented and reading/interpreting its Java source code is necessary.

Some tips:

  • Create a (possibly hidden) test page which is a duplicate of your main Weblog page. Do all your experimentation on the test page. When things work right, you can copy the changes over to the Weblog page.
  • Removing the stylesheet from your test page may be helpful to prevent CSS from affecting how changes appear.
  • Velocity seems to be very picky about how lines are indented. Be sure to indent all lines properly (following the Roller macros as examples), with 4 spaces per indent. I've found that mis-indented lines can cause mysterious errors.
  • If you make a change to a template macro and the resulting page is blank, you've made a mistake that prevents the macro from running. Try commenting out lines in the macro to see where the problem lies.
  • Velocity control operators and data structures are very primitive. You will probably need to write programs that do things the hard way to work around this.
  • Starting with page templates, drill down through the macros to see how things work and how the Roller developers did things.
  • Instead of making a few big changes, make many small changes.
  • Reload the test page after each change you make. This will help to identify problems as soon as they are introduced.
  • Be sure to save copies of your page templates offline. You may want to save a copy each time you make a major change.
  • Velocity macros take space-separated arguments, but Java methods take comma-separated arguments.
  • The showWeblogEntries macro and its sub-macros contain most of the "guts" of how Roller works for weblog entries, comments, and search pages. It is the main "black box" whose contents can be overridden and customized.

Good luck!

(2005-01-20 13:00:00.0) Permalink | Comments [2]

20050118 Tuesday January 18, 2005

Roller: Customizing Comment Details

Through experimentation, I've found that you can write macros that override the default implementation by Roller. On comments pages, email addresses (or IP addresses, if no email is provided) and websites are displayed by default. I don't like this behavior, so I wrote a macro that overrides it. The macro gets added to the top of the Weblog file, just after the DOCTYPE line.

#macro( showCommentDetails $comment $showPermalink )
    $dateFormatter.applyPattern($text.get( "macro.weblog.datepattern" ))
    #set($email = $utilities.hexEncode($comment.email))
    <p class="comment-details">
    $text.get("macro.weblog.postedby")
    #if (!$stringUtils.isEmpty($comment.name))
        <b>$comment.name</b>
    #else
        <b>Anonymous</b>
    #end
    $text.get("macro.weblog.on") $dateFormatter.format($comment.postTime)
    #if( $showPermalink )
    <a href=
"${ctxPath}/comments/${userName}/${page.link}/${entry.anchor}#comment${velocityCount}"
       class="entrypermalink"
       title="$text.get( "macro.weblog.commentpermalink.title" )">#</a>
    #end
    </p>
#end

The macro is intended for use with Roller 1.0. I'm not sure whether it works with other versions.

(2005-01-18 08:00:00.0) Permalink | Comments [2]

Calendar

« November 2009
SunMonTueWedThuFriSat
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
     
       
Today

Recent Entries

Search

Navigation



XML