Matte: Theme HOWTO: Album View

The Matte album view allows people to view the media items within a shared album. In many ways it is analogous to an album slide show. The primary purpose of the album view is to allow a user to view the media items within an album. Thus it must provide a way for the user to move between the items within the album in some way, and can also support showing detailed information about each item.

Woosh Browse Theme
An album in the Woosh browse view.

Sample album data model

The album data model includes the album the item is shared in (a <m:album> element). The album will have the items within the album available (as child <m:item> elements) but those items will not have their detailed metadata elements available (i.e. they will not have <m:metadata> elements).

Here is a sample of the album data model:

  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <x:x-data xmlns:x="http://msqr.us/xsd/jaxb-web" xmlns:m="http://msqr.us/xsd/matte">  
  3.   <x:x-context>  
  4.     <x:server-name>localhost</x:server-name>  
  5.     <x:server-port>8080</x:server-port>  
  6.     <x:user-agent>Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.4) Gecko/20070515  
  7.       Firefox/2.0.0.4</x:user-agent>  
  8.     <x:user-locale>en_US</x:user-locale>  
  9.     <x:web-context>/matte</x:web-context>  
  10.     <x:path>/album.do</x:path>  
  11.   </x:x-context>  
  12.   <x:x-auxillary>  
  13.     <x:x-param key="display.album.key">2XlxVfKHja3CFGtMlyG57ofbchw</x:x-param>  
  14.   </x:x-auxillary>  
  15.   <x:x-session>  
  16.     <m:session>  
  17.       <m:thumbnail-setting quality="GOOD" size="THUMB_NORMAL"/>  
  18.       <m:view-setting quality="GOOD" size="NORMAL"/>  
  19.     </m:session>  
  20.   </x:x-session>  
  21.   <x:x-request>  
  22.     <x:param key="key">2XlxVfKHja3CFGtMlyG57ofbchw</x:param>  
  23.   </x:x-request>  
  24.   <x:x-request-headers>  
  25.     <x:param key="host">localhost</x:param>  
  26.     <x:param key="user-agent">Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.4)  
  27.       Gecko/20070515 Firefox/2.0.0.4</x:param>  
  28.     <x:param key="accept"  
  29.       >text/xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5</x:param>  
  30.     <x:param key="accept-language">en-us,en;q=0.5</x:param>  
  31.     <x:param key="accept-encoding">gzip,deflate</x:param>  
  32.     <x:param key="accept-charset">ISO-8859-1,utf-8;q=0.7,*;q=0.7</x:param>  
  33.     <x:param key="Keep-Alive">300</x:param>  
  34.     <x:param key="connection">keep-alive</x:param>  
  35.     <x:param key="cookie">cookies=trueJSESSIONID=69BB450E95FDBD01A29D4118920EBBAC;</x:param>  
  36.     <x:param key="content-length">0</x:param>  
  37.   </x:x-request-headers>  
  38.   <x:x-model>  
  39.     <m:model>  
  40.       <m:media-size height="1200" size="BIGGEST" width="1600"/>  
  41.       <m:media-size height="768" size="BIGGER" width="1024"/>  
  42.       <m:media-size height="600" size="BIG" width="800"/>  
  43.       <m:media-size height="480" size="NORMAL" width="640"/>  
  44.       <m:media-size height="320" size="SMALL" width="480"/>  
  45.       <m:media-size height="240" size="TINY" width="320"/>  
  46.       <m:media-size height="180" size="THUMB_BIGGER" width="240"/>  
  47.       <m:media-size height="135" size="THUMB_BIG" width="180"/>  
  48.       <m:media-size height="90" size="THUMB_NORMAL" width="120"/>  
  49.       <m:media-size height="48" size="THUMB_SMALL" width="64"/>  
  50.       <m:album album-date="2006-06-01T00:00:00+12:00" album-id="21" allow-anonymous="true"  
  51.         allow-browse="true" allow-feed="true" allow-original="true"  
  52.         anonymous-key="2XlxVfKHja3CFGtMlyG57ofbchw"  
  53.         creation-date="2006-12-17T13:40:26.691+13:00" name="More John Muir Trail"  
  54.         sort-mode="0">  
  55.         <m:comment>These are photos from the John Muir Trail.</m:comment>  
  56.         <m:owner access-level="0" anonymous-key="db35b2faa3ad4527e76be12fba4ceab1"  
  57.           country="US" creation-date="2006-12-17T12:10:50.123+13:00" email="matt@localhost"  
  58.           language="en" login="matt" name="Matt"  
  59.           password="{SHA}Mv+VCPQnH3dNmi0W7qXI9nQCI78=" quota="0" user-id="3">  
  60.           <m:tz code="Pacific/Auckland" name="Pacific/Auckland" offset="43200000"  
  61.             ordering="563"/>  
  62.           <m:thumbnail-setting quality="GOOD" size="THUMB_NORMAL"/>  
  63.           <m:view-setting quality="GOOD" size="NORMAL"/>  
  64.           <m:default-theme author="Matte Development Team" author-email="matte@noplace"  
  65.             base-path="/core/woosh" creation-date="2006-12-17T12:06:38.387+13:00"  
  66.             name="Woosh" theme-id="1">  
  67.             <m:description>Default theme.</m:description>  
  68.           </m:default-theme>  
  69.           <m:browse-theme author="Matte Development Team" author-email="matte@noplace"  
  70.             base-path="/core/woosh" creation-date="2006-12-17T12:06:38.387+13:00"  
  71.             name="Woosh" theme-id="1">  
  72.             <m:description>Default theme.</m:description>  
  73.           </m:browse-theme>  
  74.         </m:owner>  
  75.         <m:theme author="Matte Development Team" author-email="matte@noplace"  
  76.           base-path="/core/woosh" creation-date="2006-12-17T12:06:38.387+13:00"  
  77.           name="Woosh" theme-id="1">  
  78.           <m:description>Default theme.</m:description>  
  79.         </m:theme>  
  80.         <m:item creation-date="2006-12-17T13:35:09.608+13:00" display-order="0"  
  81.           file-size="96111" height="683" hits="6" item-id="8" mime="image/jpeg"  
  82.           name="_6A_1392.jpg" path="_6A_1392.jpg" use-icon="false" width="1024">  
  83.           <m:tz code="Pacific/Auckland" name="Pacific/Auckland" offset="43200000"  
  84.             ordering="563"/>  
  85.           <m:tz-display code="Pacific/Auckland" name="Pacific/Auckland" offset="43200000"  
  86.             ordering="563"/>  
  87.         </m:item>  
  88.         <m:item creation-date="2006-12-17T13:36:07.812+13:00" display-order="0"  
  89.           file-size="42628" height="683" hits="4" item-id="10" mime="image/jpeg"  
  90.           name="IMG_0868.jpg" path="IMG_0868.jpg" use-icon="false" width="1024">  
  91.           <m:tz code="Pacific/Auckland" name="Pacific/Auckland" offset="43200000"  
  92.             ordering="563"/>  
  93.           <m:tz-display code="Pacific/Auckland" name="Pacific/Auckland" offset="43200000"  
  94.             ordering="563"/>  
  95.         </m:item>  
  96.         <m:item creation-date="2006-12-17T13:37:20.746+13:00" display-order="0"  
  97.           file-size="66438" height="768" hits="2" item-id="12" mime="image/jpeg"  
  98.           name="IMG_0848.jpg" path="IMG_0848.jpg" use-icon="false" width="512">  
  99.           <m:tz code="Pacific/Auckland" name="Pacific/Auckland" offset="43200000"  
  100.             ordering="563"/>  
  101.           <m:tz-display code="Pacific/Auckland" name="Pacific/Auckland" offset="43200000"  
  102.             ordering="563"/>  
  103.         </m:item>  
  104.         <m:item creation-date="2006-12-17T13:37:35.716+13:00" display-order="0"  
  105.           file-size="91771" height="683" hits="3" item-id="14" mime="image/jpeg"  
  106.           name="_19_1404.jpg" path="_19_1404.jpg" use-icon="false" width="1024">  
  107.           <m:tz code="Pacific/Auckland" name="Pacific/Auckland" offset="43200000"  
  108.             ordering="563"/>  
  109.           <m:tz-display code="Pacific/Auckland" name="Pacific/Auckland" offset="43200000"  
  110.             ordering="563"/>  
  111.         </m:item>  
  112.         <m:item creation-date="2006-12-17T13:37:51.336+13:00" display-order="0"  
  113.           file-size="51705" height="683" hits="4" item-date="2006-12-18T13:37:51+13:00"  
  114.           item-id="16" mime="image/jpeg" name="IMG_0871.jpg" path="IMG_0871.jpg"  
  115.           use-icon="false" width="1024">  
  116.           <m:tz code="Pacific/Auckland" name="Pacific/Auckland" offset="43200000"  
  117.             ordering="563"/>  
  118.           <m:tz-display code="Pacific/Auckland" name="Pacific/Auckland" offset="43200000"  
  119.             ordering="563"/>  
  120.         </m:item>  
  121.         <m:item creation-date="2006-12-17T13:47:49.441+13:00" display-order="0"  
  122.           file-size="67498" height="768" hits="3" item-id="18" mime="image/jpeg"  
  123.           name="IMG_5164.jpg" path="IMG_5164.jpg" use-icon="false" width="512">  
  124.           <m:tz code="Pacific/Auckland" name="Pacific/Auckland" offset="43200000"  
  125.             ordering="563"/>  
  126.           <m:tz-display code="Pacific/Auckland" name="Pacific/Auckland" offset="43200000"  
  127.             ordering="563"/>  
  128.         </m:item>  
  129.       </m:album>  
  130.     </m:model>  
  131.   </x:x-model>  
  132. </x:x-data>  

Woosh - Dissection

Here is a dissection of the Woosh album theme so you can see where the elements come from the Matte XML data model.

Woosh Album View
An album in the Woosh album view.

The Woosh theme presents an album with all media items displayed as thumbnails in a scrolling widget at the top of the page (#3). Clicking on individual thumbnails loads a full-size version of that item in the center of the page (#4), and also displays detailed information about that item in another widget on the right side of the page. (#5) Let's take a look at the numbered items from this snippet in more detail:

  1. Page title: Woosh displays the album name and the album date as the page title.

  2. Album date: Albums can have a user-specifed date (the @album-date attribute). If the album has been modified, it will have a @modify-date. An album will always have a @creation-date for the date it was created. Knowing this, Woosh attempts to display the user-specified album date. If the album does not have an album date, it looks for the album's modification date. If it does not have a modification date, it uses the album creation date.

    The overall XSLT that generates the title (name and date) looks like this:

    1. <xsl:template match="m:album" mode="title">  
    2.     <xsl:value-of select="@name"/>  
    3.     <xsl:if test="string-length(@name) > 0">  
    4.         <xsl:text> - </xsl:text>  
    5.     </xsl:if>  
    6.     <xsl:variable name="date">  
    7.         <xsl:choose>  
    8.             <xsl:when test="@album-date">  
    9.                 <xsl:value-of select="@album-date"/>  
    10.             </xsl:when>  
    11.             <xsl:when test="@modify-date">  
    12.                 <xsl:value-of select="@modify-date"/>  
    13.             </xsl:when>  
    14.             <xsl:when test="@creation-date">  
    15.                 <xsl:value-of select="@creation-date"/>  
    16.             </xsl:when>  
    17.         </xsl:choose>  
    18.     </xsl:variable>  
    19.     <xsl:value-of select="date:format-date(substring($date, 1, 19), 'yyyy.MM.dd')"/>  
    20. </xsl:template>  
  3. Thumbnail navigation: here Woosh generates thumbnails for all the items in the album dynamically using JavaScript on the client's browser. To do this, it generates an array of data based on all the items available in the album. Matte provides an XSLT template that is useful for this purpose:

    1. <!--  
    2.     Template: m:item, mode album-data  
    3.       
    4.     Render album data JavaScript array. The data array is ordered   
    5.     as follows:  
    6.       
    7.     0: itemId  
    8.     1: original width  
    9.     2: original height  
    10.     3: collection-relative path  
    11.     4: name  
    12.     5: comment  
    13.     6: create date  
    14.     7: icon width  
    15.     8: icon height  
    16.     9: mime type  
    17. -->  
    18. <xsl:template match="m:item" mode="album-data">  
    19.     <xsl:text>[</xsl:text>  
    20.     <xsl:value-of select="@item-id"/>  
    21.     <xsl:text>,</xsl:text>  
    22.     <xsl:value-of select="@width"/>  
    23.     <xsl:text>,</xsl:text>  
    24.     <xsl:value-of select="@height"/>  
    25.     <xsl:text>,"</xsl:text>  
    26.     <xsl:call-template name="javascript-string">  
    27.         <xsl:with-param name="output-string" select="@path"/>  
    28.     </xsl:call-template>  
    29.     <xsl:text>","</xsl:text>  
    30.     <xsl:call-template name="javascript-string">  
    31.         <xsl:with-param name="output-string" select="@name"/>  
    32.     </xsl:call-template>  
    33.     <xsl:text>","</xsl:text>  
    34.     <xsl:if test="m:comment">  
    35.         <xsl:call-template name="javascript-string">  
    36.             <xsl:with-param name="output-string" select="normalize-space(m:comment)"/>  
    37.         </xsl:call-template>  
    38.     </xsl:if>  
    39.     <xsl:text>","</xsl:text>  
    40.     <xsl:value-of select="date:format-date(substring(@creation-date,1,19),'dd MMM yyyy')"/>  
    41.     <xsl:text>",</xsl:text>  
    42.     <xsl:value-of select="@icon-width"/>  
    43.     <xsl:text>,</xsl:text>  
    44.     <xsl:value-of select="@icon-height"/>  
    45.     <xsl:text>,"</xsl:text>  
    46.     <xsl:value-of select="@mime"/>  
    47.     <xsl:text>"]</xsl:text>  
    48.     <xsl:if test="position() != last()">  
    49.         <xsl:text>,</xsl:text>  
    50.     </xsl:if>  
    51. </xsl:template>  

    The way Woosh calls this template is like this:

    1. var imageData = [  
    2. [-1,-1,-1,"dummy/path","dummy name","dummy comment","dummy date"],  
    3. <xsl:apply-templates select="$display-album/m:item" mode="album-data"/>  
    4. ];  

    Which generates JavaScript like this:

    1. var imageData = [  
    2.     [-1,-1,-1,"dummy/path","dummy name","dummy comment","dummy date"],  
    3.     [8,1024,683,"_6A_1392.jpg","_6A_1392.jpg","","17 Dec 2006",,,"image/jpeg"],  
    4.     [10,1024,683,"IMG_0868.jpg","IMG_0868.jpg","","17 Dec 2006",,,"image/jpeg"],  
    5.     [12,512,768,"IMG_0848.jpg","IMG_0848.jpg","","17 Dec 2006",,,"image/jpeg"],  
    6.     [14,1024,683,"_19_1404.jpg","_19_1404.jpg","","17 Dec 2006",,,"image/jpeg"],  
    7.     [16,1024,683,"IMG_0871.jpg","IMG_0871.jpg","","17 Dec 2006",,,"image/jpeg"],  
    8.     [18,512,768,"IMG_5164.jpg","IMG_5164.jpg","","17 Dec 2006",,,"image/jpeg"]  
    9.     ];  

    In order to generate URLs to Matte resources, such as the thumbnail images, the JavaScript needs to know the server path it should use. Matte makes this available to themes, so Woosh generates some more JavaScript data to pass this to the client:

    1. <xsl:variable name="root-album" select="/x:x-data/x:x-model/m:model/descendant::m:album[1]"/>  
    2. <script type="text/javascript">  
    3.     var albumKey = '<xsl:value-of select="$root-album/@anonymous-key"/>';  
    4.     var webContext = '<xsl:value-of select="$web-context"/>';  
    5.     var serverName = '<xsl:value-of select="$server-name"/>'  
    6.     var serverPort = '<xsl:value-of select="$server-port"/>'  
    7.     var myLang = '<xsl:value-of select="$user-locale"/>'  
    8. </script>  

    Now the client has all the information it needs to dynamically generate the thumbnail images. The JavaScript (simplified here) looks like this:

    1. var albumKey = '2XlxVfKHja3CFGtMlyG57ofbchw';  
    2. var webContext = '/matte';  
    3. var serverName = 'localhost'  
    4. var serverPort = '8080'  
    5. var myLang = 'en_US'  
    6. for ( var i = 0; i < imageData.length; i++ ) {  
    7.     var data = imageData[i];  
    8.     var url = webContext +"/media.do?id="+data[0]  
    9.         +"&albumKey=" +albumKey  
    10.         +"&size=THUMB_NORMAL&quality=GOOD";  
    11.     var alt = data[4] ? data[4] : data[3];  
    12.     var img = document.createElement("img");  
    13.     img.setAttribute("src", url);  
    14.     img.setAttribute("alt", alt);  
    15.     img.className = "tb-thumbnail";  
    16.     $('slider-container').appendChild(img);  
    17. }  

    Here you can see Woosh is generating <img> elements for each item, setting the src attribute to the Matte /media.do URL for generating images. Woosh has hard-coded the media size to be a normal sized thumbnail.

  4. Full size image: The process of generating full-size images is similar to how the thumbnails images are generated. Woosh does it in this way (again, simplifed here):

    1. function displayImage(imageNumber) {  
    2.     var newImg = document.createElement("img");  
    3.     var newImgUrl = webContext   
    4.             +"/media.do?id="+imageData[imageNumber][0]  
    5.             +"&albumKey=" +albumKey  
    6.             +"&size=" +imgSize   
    7.             +"&quality=" +imgCompress;  
    8.     var title = imageData[imageNumber][4]  
    9.         ? imageData[imageNumber][4]  
    10.         : imageData[imageNumber][3];  
    11.     newImg.title = title;  
    12.     newImg.alt = title;  
    13.     newImg.onload = function() {  
    14.         handleDisplayImageLoad(newImg, imageNumber);  
    15.     }  
    16.     newImg.src = newImgUrl;  
    17. }  
    18.   
    19. function handleDisplayImageLoad(newImg, imageNumber) {  
    20.     $('image-frame').appendChild(newImg);  
    21.     updateImageInfo(imageNumber);  
    22. }  

    Note the call to updateImageInfo() at the bottom. We discuss that next.

  5. Image detail information: Matte themes can utilize another URL for generating detailed information about a single media item. The URL is /viewMediaItemInfo.do and Woosh uses this via an AJAX call to populate this information here.

    The updateImageInfo() method uses the Prototype Ajax.Updater class to call the detail URL and place the result into the page. The JavaScript looks like this:

    1. function updateImageInfo(imageNumber) {  
    2.     Element.addClassName('ii-imageMetaFrame''updating');  
    3.     new Ajax.Updater(  
    4.         {success : 'ii-imageMetaFrame'},   
    5.         webContext +'/viewMediaItemInfo.do',   
    6.         {  
    7.             method : 'get',  
    8.             parameters : "albumKey="+albumKey +"&itemId=" +imageData[imageNumber][0]   
    9.                 +"&themeId=" +themeId,   
    10.             onSuccess : function(t) {  
    11.                 Element.removeClassName('ii-imageMetaFrame''updating');  
    12.             },  
    13.             onComplete : function() {  
    14.                 workingUpdaterAjaxHandler.manualStop();  
    15.             }  
    16.         });  
    17. }  

    The @anonymous-key of the album being viewed and the @item-id of the item you want to view the details for are passed to the /viewMediaItemInfo.do URL (as the albumKey and itemId URL parameters, respectively).

Next: Detail View

Continue next with information on how the Detail View handles returning the detailed information for a single item.

SourceForge.net Logo