Matte: Theme HOWTO: Browse View
The first component of a Matte theme is the browse theme. This theme allows people to view all shared
albums of a particular user. The browse theme can be thought of as an album-centric blog, and in fact
this view can be published as an Atom RSS feed (more on that later).
An album listing in the Woosh browse view.
This view is accessed using the /matte/browse.do
URL, and requires
a userKey
parameter for the user whose albums you want to browse.
When you log into Matte, you can find your own userKey
value by
selecting Actions > Matte Settings. This will show you the browse URL
with your own userKey
next to the Shared Albums label.
The Matte XML model for this view contains a list of <m:search-album>
elements, which is an extension of the <m:album>
element geared
towards browsing large sets of shared albums. The albums
will be sorted chronologically in reverse, so the most-recent album appears first.
You can, of course, sort them any way you like in the theme's XSLT.
Sample browse data model
Here is a sample of the browse data model:
- <?xml version="1.0" encoding="UTF-8"?>
- <m:model xmlns:m="http://msqr.us/xsd/matte">
- <m:search-results returned-results="2" search-time="31" total-results="2">
- <m:pagination/>
- <m:index/>
- <m:album item-count="2" item-max-date="2007-06-25T00:00:00+12:00"
- item-min-date="2003-01-26T00:00:00+13:00" album-date="2007-06-25T00:00:00+12:00"
- album-id="4394" anonymous-key="wif0pqjIEEntKPluVpLrk64n4G/k"
- creation-date="2007-06-25T21:28:32.125+12:00"
- modify-date="2007-06-30T11:16:11.828+12:00" name="New Zealand">
- <m:comment>This is New Zealand. Oh yes. Really.</m:comment>
- <m:search-poster item-id="2138" name="IMG_4684.JPG"/>
- <m:search-album item-count="29" item-max-date="2007-06-25T00:00:00+12:00"
- item-min-date="2002-12-28T00:00:00+13:00" album-date="2007-06-25T00:00:00+12:00"
- album-id="4758" anonymous-key="sFu8FzrDiUPPR12unCtyeiPlpi4"
- creation-date="2007-06-25T21:29:13.171+12:00"
- modify-date="2007-07-08T07:47:37.375+12:00"
- name="02 Blomfield Spa With A Long Name That Goes On And On">
- <m:comment/>
- <m:search-poster item-id="2166" name="IMG_1084.JPG"/>
- </m:search-album>
- <m:search-album item-count="10" item-max-date="2003-02-04T00:00:00+13:00"
- item-min-date="2003-01-24T00:00:00+13:00" album-date="2007-06-25T21:29:20.765+12:00"
- album-id="5013" anonymous-key="Ap1wOi0R2iqgx1USRf6ok0By6DQ"
- creation-date="2007-06-25T21:29:20.765+12:00" name="03-auckland">
- <m:search-poster item-id="2449" name="IMG_4667.JPG"/>
- </m:search-album>
- </m:album>
- <m:album item-count="48" item-max-date="2002-11-01T00:00:00+13:00"
- item-min-date="2002-10-31T00:00:00+13:00" album-date="2002-10-31T00:00:00+13:00"
- album-id="11025" anonymous-key="mCmQAYDrarPfuDL/mmVBCwI4fzc"
- creation-date="2004-01-09T16:30:56+13:00" modify-date="2007-07-08T07:54:27.203+12:00"
- name="Halloween 2002">
- <m:comment>2002 version of the annual Castro event! With some related holiday events,
- too.</m:comment>
- <m:search-poster item-id="11055" name="IMG_0666.JPG"/>
- </m:album>
- </m:search-results>
- <m:media-size height="1200" size="BIGGEST" width="1600"/>
- <m:media-size height="768" size="BIGGER" width="1024"/>
- <m:media-size height="600" size="BIG" width="800"/>
- <m:media-size height="480" size="NORMAL" width="640"/>
- <m:media-size height="320" size="SMALL" width="480"/>
- <m:media-size height="240" size="TINY" width="320"/>
- <m:media-size height="180" size="THUMB_BIGGER" width="240"/>
- <m:media-size height="135" size="THUMB_BIG" width="180"/>
- <m:media-size height="90" size="THUMB_NORMAL" width="120"/>
- <m:media-size height="48" size="THUMB_SMALL" width="64"/>
- <m:theme author="Matte Development Team" author-email="matte@noplace" base-path="/core/woosh"
- creation-date="2007-03-31T18:46:33.250+12:00" name="Woosh" theme-id="1">
- <m:description>Default theme.</m:description>
- </m:theme>
- <m:user access-level="1" anonymous-key="test" country="US"
- creation-date="2007-03-31T18:46:33.453+12:00" email="matte-admin@localhost.localdomain"
- language="en" login="matte-admin" name="Admin" password="{SHA}W6ph5Mm5Pz8GgiULbPgzG37mj9g="
- quota="0" user-id="2">
- <m:tz code="Pacific/Auckland" name="Pacific/Auckland" offset="43200000" ordering="569"/>
- <m:thumbnail-setting quality="GOOD" size="THUMB_NORMAL"/>
- <m:view-setting quality="GOOD" size="NORMAL"/>
- <m:default-theme author="Matte Development Team" author-email="matte@noplace"
- base-path="/core/woosh" creation-date="2007-03-31T18:46:33.250+12:00" name="Woosh"
- theme-id="1">
- <m:description>Default theme.</m:description>
- </m:default-theme>
- <m:browse-theme author="Matte Development Team" author-email="matte@noplace"
- base-path="/core/woosh" creation-date="2007-03-31T18:46:33.250+12:00" name="Woosh"
- theme-id="1">
- <m:description>Default theme.</m:description>
- </m:browse-theme>
- </m:user>
- </m:model>
From this model you can see that an <m:search-results>
element is
returned (line 3), populated with two <m:album>
elements
(lines 6 and 29). Notice also that the first album has two child
<m:search-album>
elements inside of it
(lines 13 and 22). These elements are discussed in detail here:
<m:search-results>
This element represents a container for all the results returned by a search.
In the case of the browse view, the search results will be populated with
<m:search-album>
elements, one for each album the specified
user has shared.
- @returned-results
- The total number of search results returned in the response, for the
given pagination criteria specified for the request. In this case the
total number of top-level shared albums available for the specified user.
- @search-time
- The number of milliseconds the search took to execute.
- @total-results
- The total number of search results available, for all pages available.
In this case this is the total number of top-level shared albums available
for the specified user.
- <m:pagination>
- TODO
- <m:index>
- TODO
- <m:album>
- An album search result. Album search result elements are an extension
of the normal
<m:album>
elements discussed earlier. They
include additional data elements to help in the browsing of album data.
<m:album> and <m:search-album>
Within a <m:search-results>
element, the
<m:alubm>
element represents a top-level album, and the <m:search-album>
element represents a nested child album. They are the same data type, so they
will have the same data elements available. The following items are available
in addition to those detailed by the normal <m:album>
element previously:
- @item-count
- The total number of media items within this album, not including items in
any nested child albums.
- @item-max-date
- The date of the media item within this album with a date greater than or
equal to all other items within the album.
- @item-min-date
- The date of the media item within this album with a date less than or
equal to all other media items within the album.
- <m:search-poster>
- The media item to use as the poster for the album. This element will
have only an @item-id and a @name
parameters specified, so the theme is able to display a poster image
for the album if desired.
Linking to shared albums
In the browse view you'll need to provide links to the album view
for each shared album. Use the render-shared-album-url
XSLT
template to generate URLs to the shared albums. This template takes the
following parameters:
- album
- A <m:album> element (or <m:search-album>) for the
album to link to.
- web-context
- Matte's servlet context path, normally
/matte
. This is
also pre-defined as the helper variable $web-context
.
For example, to generate an HTML <a> tag to link to the album,
you'd have something like this (here the XSLT context node is a
<m:album>
element):
- <a>
- <xsl:attribute name="title">
- <xsl:value-of select="key('i18n','browse.album.view')"/>
- <xsl:text> </xsl:text>
- <xsl:value-of select="@name"/>
- </xsl:attribute>
- <xsl:attribute name="href">
- <xsl:call-template name="render-shared-album-url">
- <xsl:with-param name="album" select="."/>
- <xsl:with-param name="web-context" select="$web-context"/>
- </xsl:call-template>
- </xsl:attribute>
- <xsl:value-of select="key('i18n','browse.album.view')"/>
- <xsl:text> </xsl:text>
- <xsl:value-of select="@name"/>
- </a>
Notice the use of key('i18n','browse.album.view')
.
This shows the use of the built-in Matte message bundle, for displaying
internationalized values of various messages. Look in the
WEB-INF/classes/messages.properties
file inside the Matte WAR
file for the complete listing of available message resource keys.
Woosh - Dissection
Here is a dissection of the Woosh browse theme so you can see where the elements come from
the Matte XML data model.
An album listing in the Woosh browse view.
Here is what the final rendered XHTML for this snippet looks like:
-
- <div class="browse-album-frame">
- <div class="browse-odd">
- <h2>
- More John Muir Trail
- </h2>
- <div class="browse-album-info">
- 1 Jun 2006 - 6 items
- <div class="browse-album-info">
- Items ranging from 17 Dec 2006 to 18 Dec 2006
- </div>
- </div>
- <div class="browse-album-text">
- These are photos from the John Muir Trail.
- </div>
- </div>
- <div class="poster">
- <a title="View album More John Muir Trail"
- href="/matte-stage/album.do?key=2XlxVfKHja3CFGtMlyG57ofbchw">
- <img class="poster" alt="_6A_1392.jpg"
- onload="setShadow(this)"
- title="_6A_1392.jpg"
- src="http://localhost:8080/matte/media.do?id=8&size=THUMB_BIGGER&quality=GOOD" />
- </a>
- </div>
- </div>
Let's take a look at the numbered items from this snippet in more detail:
-
Image thumbnail: here the poster image for the album is shown as a thumbnail.
An album will have a poster image specified via the <m:search-poster> element. If
the album does not specify the poster itslef, then <m:search-poster> will be set to
the first available media item in the album. Then it uses the media size THUMB_BIGGER
for the thumbnail.
The XSLT to render the album thumbnail looks like this:
- <xsl:template match="m:search-poster">
- <div class="poster">
- <a>
- <xsl:attribute name="title">
- <xsl:value-of select="key('i18n','browse.album.view')"/>
- <xsl:text> </xsl:text>
- <xsl:value-of select="../@name"/>
- </xsl:attribute>
- <xsl:attribute name="href">
- <xsl:call-template name="render-shared-album-url">
- <xsl:with-param name="album" select=".."/>
- <xsl:with-param name="web-context" select="$web-context"/>
- </xsl:call-template>
- </xsl:attribute>
- <img class="poster" alt="{@name}" onload="setShadow(this)"
- title="{@name}">
- <xsl:attribute name="src">
- <xsl:call-template name="server-url"/>
- <xsl:call-template name="render-media-server-url">
- <xsl:with-param name="item" select="."/>
- <xsl:with-param name="size" select="'THUMB_BIGGER'"/>
- <xsl:with-param name="quality" select="$thumb-quality"/>
- <xsl:with-param name="web-context" select="$web-context"/>
- </xsl:call-template>
- </xsl:attribute>
- </img>
- </a>
- </div>
- </xsl:template>
This all generates XHTML like the following:
- <div class="poster">
- <a title="View album More John Muir Trail"
- href="/matte/album.do?key=2XlxVfKHja3CFGtMlyG57ofbchw">
- <img class="poster" alt="_6A_1392.jpg" onload="setShadow(this)" title="_6A_1392.jpg"
- src="/matte/media.do?id=8&size=THUMB_BIGGER&quality=GOOD"
- />
- </a>
- </div>
-
Image thumbnail shadow: Matte includes a URL you can call to generate shadows.
The shadows are sized according to the dimensions you pass and therefor can scale to any
size image. In Woosh, the shadows are set as CSS background images on the album poster
thumbnails. Since they need to be sized dynamically, Woosh uses JavaScript to set the
CSS property after the browser loads the image so it can know what the size of the image
is. In the previous dissection point, you can see it includes an
onload="setShadow(this)"
attribute. This is the JavaScript call to set the
shadow image. The JavaScript function looks like this:
- function setShadow(el) {
- var dim = Element.getDimensions(el);
- var width = dim.width;
- var height = dim.height;
- if ( width > 0 && height > 0 ) {
- var bgUrl = webContext+'/shadow.do?w=' +width
- +'&h=' +height +'&b=6&r=3&c=3289650';
- Element.setStyle(el.parentNode.parentNode, {
- 'background-image' : 'url('+bgUrl+')',
- 'background-repeat' : 'no-repeat',
- 'background-position' : '-3px -3px'
- });
- }
- }
Note that Woosh uses the Prototype JavaScript library.
Here the important part is the bgUrl
variable which is the URL set on the
background-image
CSS property. The URL must refernce
/shadow.do
and pass the following parameters:
- w
- The desired width, in pixels.
- h
- The desired height, in pixels.
- b
- The amount of blur to apply to the shadow, in pixels.
- r
- A corner radius to apply to the shadow, in pixels.
- c
- An 8-bit RGB color triplet value encoded as a 24-bit integer,
eg. R<<16 + G<<8 + B.
-
Album name: here Woosh is simply displaying the <m:album>
@name
attribute, like this:
- <h2>
- <xsl:value-of select="@name"/>
- </h2>
-
Album date: the album date is stored as the
attribute.
Woosh uses the EXSLT
date:format-date()
extension functions (included with the
Java 5 built-in XSLT engine) to render the date into a display-friendly format:
- <xsl:variable name="album.date">
- <xsl:choose>
- <xsl:when test="@album-date">
- <xsl:value-of select="@album-date"/>
- </xsl:when>
- <xsl:otherwise>
- <xsl:value-of select="@creation-date"/>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:variable>
- <xsl:value-of select="date:format-date(substring($album.date,1,19),$date.format)"/>
This XSLT uses the substring()
function to use just
the date's first 19 characters, because the EXSLT date:format-date()
function does not parse xs:dateTime values with precision greater than seconds. Thus,
if the date contains milliseconds, they would start at character 20 of the date string,
so we only want the first 19 characters here.
-
Album item count: here Woosh is displaying the total number of media
items that the album contains. This is accomplished by counting the number of
<m:item> elements in the >m:album>, like this:
- <xsl:value-of select="count(m:item)"/>
- <xsl:text> </xsl:text>
- <xsl:choose>
- <xsl:when test="count(m:item) = 1">
- <xsl:value-of select="key('i18n','browse.items.count.single')"/>
- </xsl:when>
- <xsl:otherwise>
- <xsl:value-of select="key('i18n','browse.items.count')"/>
- </xsl:otherwise>
- </xsl:choose>
Woosh is making use of the browse.items.count.single
and browse.items.count
message resource keys to correctly
display item or items (in English) if there is only one or more
than one item in the album.
-
Items date range: here Woosh displays the @item-min-date
and @item-max-date
album attributes, if available and they differ
from each other. It looks for the minimum/maximum dates within the entire album hierarchy,
using some XSLT sorting to accomplish, like this:
- <xsl:variable name="min-date">
- <xsl:for-each select=".//@item-min-date">
- <xsl:sort select="." order="ascending"/>
- <xsl:if test="position() = 1">
- <xsl:value-of select="."/>
- </xsl:if>
- </xsl:for-each>
- </xsl:variable>
- <xsl:variable name="max-date">
- <xsl:for-each select=".//@item-max-date">
- <xsl:sort select="." order="descending"/>
- <xsl:if test="position() = 1">
- <xsl:value-of select="."/>
- </xsl:if>
- </xsl:for-each>
- </xsl:variable>
- <xsl:if test="@item-count > 0 and $min-date != $max-date">
- <div class="browse-album-info">
- <xsl:value-of select="key('i18n', 'browse.items.itemrange')"/>
- <xsl:text> </xsl:text>
- <xsl:value-of select="date:format-date(
- substring($min-date, 1, 19), $date.format)"/>
- <xsl:text> </xsl:text>
- <xsl:value-of select="key('i18n', 'to')"/>
- <xsl:text> </xsl:text>
- <xsl:value-of select="date:format-date(
- substring($max-date, 1, 19), $date.format)"/>
- </div>
- </xsl:if>
-
Album comments: here Woosh displays the album's comments, which
are stored in the child <m:comment> element. If the
album does not have any comments, Woosh uses the
browse.album.nocomments
message resource key to display the
message No comments. (in English):
- <div class="browse-album-text">
- <xsl:choose>
- <xsl:when test="string-length(m:comment) > 0">
- <xsl:value-of select="m:comment"/>
- </xsl:when>
- <xsl:otherwise>
- <xsl:value-of select="key('i18n','browse.album.nocomments')"/>
- </xsl:otherwise>
- </xsl:choose>
- </div>
Publishing RSS album feed
Matte provides an album RSS feed URL for publishing shared albums with. This is something
you can easily provide a link to from the browse view, and many modern web browsers will recognize
the feed and allow users to subscribe to it.
Matte supports the Atom 1.0 feed format. The Matte-relative URL for accessing the feed for
a particular user is
/feed/atom-1.0.do?userKey=key
where key is the user's anonymous key.
To add a link to this feed from the browse view, you need to generate an HTML <link> element,
like this
- <link rel="alternate"
- type="application/atom+xml" lang="en-US"
- title="Matt's Photo Album Feed"
- href="http://localhost:8080/matte/feed/atom-1.0.do?userKey=XYZ"/>
The way Woosh accomplishes this is with this XSLT:
- <xsl:variable name="author" select="/x:x-data/x:x-model[1]/m:model[1]/m:user[1]"/>
- <link rel="alternate" type="application/atom+xml" lang="en-US">
- <xsl:attribute name="title">
- <xsl:value-of select="$author/@name"/>
- <xsl:value-of select="key('i18n','feed.author.posessive.suffix')"/>
- <xsl:text> </xsl:text>
- <xsl:value-of select="key('i18n','feed.album.title')"/>
- </xsl:attribute>
- <xsl:attribute name="href">
- <xsl:call-template name="server-url"/>
- <xsl:value-of select="$web-context"/>
- <xsl:text>/feed/atom-1.0.do?userKey=</xsl:text>
- <xsl:value-of select="$author/@anonymous-key"/>
- </xsl:attribute>
- </link>
Next: Album View
Continue next with details on the Album View.