Archive Calendar Widget for Graffiti CMS

The JmbCalendar is a full-featured monthly archive calendar widget for Graffiti CMS. Being a widget it can only appear in one of the two sidebars.

The calendar widget supports the following features:

  1. Presents a compact display of a month calendar for the sidebar.
  2. Has links for monthly and daily archives. Includes links for previous and next months' archives.
  3. Shows the archive month if the page is showing archived posts, otherwise shows the current month.
  4. Shows number of posts for both days and months.
  5. Uses simple URL queries for displaying archived posts.
  6. Validates all input data (such as URLs).
  7. Renders as XHTML-compliant markup and will validate either as HTML or XHTML.
  8. Pages archived posts.
  9. Filters posts through the reader's security role. The user will not see those posts denied to them.
  10. Allows for editing of the title and the formats for the next/previous month links.
  11. Comes with a supporting Chalk extension library to easily retrieve archive posts.

 

Deploying

1. Copy the JmbCalendar.dll into the /bin folder on your website.

2. To make sure that Graffiti recognizes it, go to your website's home page, hit refresh in your browser, then go to the widget control panel in Graffiti CMS. In the left hand drop down list, you should see JmbCalendar as one of the widgets.

3. Add the JmbCalendar widget to one of your sidebars using the control panel.

4. If necessary, edit the calendar's properties. By default, the title is "Archives", the previous month link format is "« {0}" and the next month link format is "{0} »". Clearing a text box will restore the default for that property when you update.

5. Create an uncategorized post called "archive" (without the quotes). There's no need to enter any content for that post, it won't get displayed. All this does is create a placeholder post in the root folder of the Graffiti site.

6. Create a view file in your current theme called archive.view. Define the HTML markup and Chalk calls to display a collection of posts. (See below for full details.)

7. Create some CSS to theme the calendar (see below).

8. Check the look of the calendar, and tweak the view, the CSS, or both if necessary.

 

Calendar styling hints, using CSS

The calendar uses just one id: jmbCalendar. It is set on the <table> element. Nevertheless you can reference all other elements in the calendar from this.

Here are the selectors to use:

As an example, here's the CSS I use for my blog:

#jmbCalendar {border-spacing:0px;border-collapse:collapse;margin:0 auto;}
#jmbCalendar caption {margin:5px auto 5px auto;}
#jmbCalendar thead th {border:1px solid #5F5F5F;margin:0;}
#jmbCalendar tfoot td {border:1px solid #5F5F5F;margin-top:5px;text-align:center;}
#jmbCalendar tbody td {padding:2px 4px;text-align:right;}
#jmbCalendar tbody td a {display:block;}
#jmbCalendar tbody td a:hover {background-color:#5F4C4C;}

 

Writing the view file for archive lists

The archive.view file will be rendered in two situations: either to display the archived posts for a particular month (the reader clicked on a month link in the calendar), or for a particular date (the reader clicked on one of the days in the calendar). Consequently there will be some kind of Chalk if statement in there.

Here's an example view file.

    <div id="blog">

        #if($request.day)
            <h1>Archives for $JmbCalendarHelper.GetDateDisplayName($request.year, $request.month, $request.day)</h1>
            #foreach($post in $JmbCalendarHelper.GetPostsForDay($request.year, $request.month, $request.day) )
                <div class="post" id="$post.id">
                    $macros.LoadThemeView("postheader.view")
                    <div class="text">
                        $post.Excerpt("<p>", "</p>" ,"Read more...", 300)
                        $macros.LoadThemeView("postfooter.view")
                    </div>

                </div><!--end of post -->

            #nodata
                <div class="post">
                    Sorry, there are no posts matching your request.
                </div>

            #end
        #else
            <h1>Archives - $JmbCalendarHelper.GetMonthDisplayName($request.year, $request.month)</h1>
            #foreach($post in $JmbCalendarHelper.GetPostsForMonth($request.year, $request.month) )
                <div class="post" id="$post.id">
                    $macros.LoadThemeView("postheader.view")
                    <div class="text">
                        $post.Excerpt("<p>", "</p>" ,"Read more...", 300)
                        $macros.LoadThemeView("postfooter.view")
                    </div>

                </div><!--end of post -->

            #nodata
                <div class="post">
                    Sorry, there are no posts matching your request.
                </div>

            #end
        #end

        $JmbCalendarHelper.Pager("pager", "&laquo; older posts", "newer posts &raquo;")

    </div><!--end of blog -->

Ignore the HTML markup in there: this will depend on the theme you are using. Instead focus on the Chalk code. The first if statement checks to see whether a "day" parameter was passed in the URL query string (the URL will look like "<yoursitename>/archive/?year=2009&month=1&day=4" and this statement looks for the day part).

If that's present, the view uses some Chalk extensions (the extension is called JmbCalendarHelper and was installed along with the widget). GetDateDisplayName returns a pretty string of the date (pass in the request's year, month and day as shown) and GetPostsForDay returns a collection of posts for that same date. The posts are then iterated through. Note that the number of posts in the returned collection is limited to 10. You will need to use the pager to see the others.

A similar bit of code works for displaying the posts for a month. Here the day part of the request is empty, so we only use the month and year parts. The Chalk methods to use are GetMonthDisplayName and GetPostsForMonth, and work in a similar way to their date counterparts.

Finally there's the call to the pager method. This works in the same way as the $macros.pager command. The parameters are the CSS class name for the <div> element to hold the pager links, and the two link texts for older and newer posts.

If you use the calendar for a while, you'll notice that the most popular page on your site as displayed by the GraffitiCMS control panel becomes the archive page. Since this information isn't really that interesting, the JmbCalendarHelper Chalk extension has an extra method to clear the statistics for the archive page. Just put the command $JmbCalendarHelper.ResetArchivePageStatistics() at the top of your archive view file, and it will clear the stats every time the archive page is displayed.

 

Known issues

Although the month and day names are retrieved from the operating system hosting Graffiti, ancillary text such as tips is still hardcoded in English.

The day that starts the week is retrieved from the operating system hosting Graffiti. If you want the calendar to start on a different day of the week, you will have to make an operating system configuration change.

Date formats are hard-coded, although some are read from the operating system hosting Graffiti. However, nowhere is the ambiguous 99/99/9999 date format used.

 

Implementation details

If you are interested in how I designed and implemented this widget please see these posts on my blog.

 

Small print

This document, the code, and the compiled binaries for JmbCalendar are all © Copyright 2008-2009, Julian M Bucknall.

The license for this product is the MIT license:

Copyright (c) 2009 Julian M Bucknall
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

If that lot scares you off, I'll certainly help out with changes if your request is reasonable. I can be reached via my blog http://blog.boyet.com, or by email at julianb@boyet.com.