<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <!-- 
    Notes:
        created-by: mjs (matt@mattsouth.net)
        created-on: 4th Feb 2006
        The vision behind this page is a rendering of del.icio.us tags that gives each tag a square on the
        page and makes the size of that square proportional to the number of tags.
        delicious tags xml is returned from the url: http://del.icio.us/api/tags/get (requires auth)
        Implemented in XSLT because I thought it might be fun. Hmmm.
        
    todo:
        automatically detect the width of the widest box
        automatically detect the number of columns (dependent on the number of tags and maybe limited as well)
        implement auto-update of delicious XML (+ addition of the stylesheet instruction)
        introduce bundles (content, use)
        link content tags into wikipedia (nice)
    -->
    
    <!-- constants -->
    <xsl:variable name="borderWidth" select="1"/>
    <xsl:variable name="borderStyle" select="solid"/>
    <xsl:variable name="xoffset" select="10"/>
    <xsl:variable name="yoffset" select="65"/>    
    <xsl:variable name="charWidth" select="20"/>
    <xsl:variable name="maxWidth" select="160"/>
    <xsl:variable name="numCols" select="5"/>
    <xsl:variable name="colLength"><xsl:value-of select="sum(//tags/tag/@count) div $numCols"/></xsl:variable>
    
    <xsl:template match="/">
        <html>
            <head>
                <title>MattSouth.net | del.icio.us tags</title>
                <style>
                    .tag1 { background-color: #FF99FF; border: <xsl:value-of select="$borderWidth"/>px <xsl:value-of select="$borderStyle"/>; cursor:pointer;}
                    .tag2 { background-color: #66CCCC; border: <xsl:value-of select="$borderWidth"/>px <xsl:value-of select="$borderStyle"/>; cursor:pointer;}
                    .tag3 { background-color: #FFCC99; border: <xsl:value-of select="$borderWidth"/>px <xsl:value-of select="$borderStyle"/>; cursor:pointer;}
                    .tag0 { background-color: #66FFFF; border: <xsl:value-of select="$borderWidth"/>px <xsl:value-of select="$borderStyle"/>; cursor:pointer;}
                    A
                    {
                    TEXT-DECORATION: none;
                    COLOR: black;
                    }
                    BODY
                    {
                    FONT-FAMILY: georgia, verdana, arial;
                    TEXT-DECORATION: none;
                    COLOR: black;
                    }
                    #title { font-size: 14pt; font-family="century-new, verdana, arial, helvetica"; }
                    #subtitle {font-size: 11pt; color: gray;}
                </style>
                <script language="Javascript">
                    var currentColor=''; // for caching previous background colour
                    var currentStatus=''; // for caching previous status text
                    function showContents(divid) {
                        document.getElementById(divid).style.filter='alpha(opacity=40)'; // ie (0, 100]
                        document.getElementById(divid).style.opacity=0.4; // mozilla and Safari (0,1]
                        // replicate behaviour of href (doesnt work in firefox, unless you allow scripts to updated status bar in options)
                        currentStatus = window.status;
                        window.status = 'http://del.icio.us/matts/'+divid;
                    }
                    function hideContents(divid) {
                        document.getElementById(divid).style.filter='alpha(opacity=100)';
                        document.getElementById(divid).style.opacity=1.0;
                        //document.getElementById(divid).style.backgroundColor=currentColor;
                        window.status=currentStatus;
                    }
                </script>
            </head>
            <body>
                <div id="title">MattSouth.net</div>
                <div id="subtitle">While I'm thinking of something better to do with this space, here's a rendering of my <a href="http://del.icio.us/matts">del.icio.us</a> tags using <a href="render.xsl">this</a> stylesheet. </div>
                <hr/>
                <xsl:for-each select="tags/tag">
                    <xsl:call-template name="rendertag"/>
                </xsl:for-each>
                <!--copyright 2000-2007 Matt South-->
            </body>
        </html>
    </xsl:template>
    
    <xsl:template name="rendertag">
    <!-- render a tag as an absoluted positioned div box -->
        <xsl:variable name="currentNodePos"><xsl:value-of select="position()"/></xsl:variable>
        <xsl:variable name="weightedPos"><xsl:call-template name="currentTotal"><xsl:with-param name="nodes" select="//tags/tag[position()&lt;$currentNodePos]"/></xsl:call-template></xsl:variable>
        <xsl:variable name="thisTag" select="@tag"/>
        <div>
            <!-- NB: the whole div behaves like a hyperlink, via the mouseover and mouseclick events and css cursor changing. --> 
            <xsl:attribute name="class">tag<xsl:value-of select="$currentNodePos mod 4"/></xsl:attribute>
            <xsl:attribute name="id"><xsl:value-of select="@tag"/></xsl:attribute>
            <xsl:attribute name="style">position:absolute; left: <xsl:value-of select="$xoffset+(floor($weightedPos div $colLength) * $maxWidth) + $borderWidth"/>px; top: <xsl:value-of select="$yoffset+(($weightedPos mod $colLength) * $charWidth)+$borderWidth"/>px; height: <xsl:value-of select="@count*$charWidth - $borderWidth"/>px; width: <xsl:value-of select="$maxWidth - $borderWidth"/>px; z-index: 1;</xsl:attribute>
            <xsl:attribute name="onmouseover">showContents('<xsl:value-of select="@tag"/>')</xsl:attribute>
            <xsl:attribute name="onmouseout">hideContents('<xsl:value-of select="@tag"/>')</xsl:attribute>
            <xsl:attribute name="onclick">window.location='http://del.icio.us/matts/<xsl:value-of select="@tag"/>'</xsl:attribute>
            <xsl:value-of select="@tag" />
        </div>
        <div>
            <!-- NB: the whole div behaves like a hyperlink, via the mouseover and mouseclick events and css cursor changing. --> 
            <xsl:attribute name="class">tag<xsl:value-of select="$currentNodePos mod 4"/></xsl:attribute>
            <xsl:attribute name="id"><xsl:value-of select="@tag"/>links</xsl:attribute>
            <xsl:attribute name="style">position:absolute; left: <xsl:value-of select="$xoffset+(floor($weightedPos div $colLength) * $maxWidth) + $borderWidth"/>px; top: <xsl:value-of select="$yoffset+(($weightedPos mod $colLength) * $charWidth)+$borderWidth"/>px; height: <xsl:value-of select="@count*$charWidth - $borderWidth"/>px; width: <xsl:value-of select="$maxWidth - $borderWidth"/>px; z-index: -1;</xsl:attribute>
            <xsl:for-each select="//post[contains(./@tag, $thisTag)]">
                <a><xsl:value-of select="substring(@description,1,20)"/></a><br/>
            </xsl:for-each>
        </div>    
    </xsl:template>
    
    <xsl:template name="getCols">
<!-- 
    first go at a way of detecting number of columns 
    returns the maximum number whose square is less than the "value" parameter 
    not used (yet)
-->
        <xsl:param name="value" />
        <xsl:param name="result" select="0" />
        <xsl:choose>
            <xsl:when test="$result*$result &lt; $value">
                <xsl:call-template name="getCols">
                    <xsl:with-param name="value" select="$value" />
                    <xsl:with-param name="result" select="number($result)+1" />
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="number($result)-1"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
    
    <xsl:template name="currentTotal">
<!-- 
    When working your way through the tags, you need to know the weighted total so far.  This gives it to you.
    Call it by passing the set of tag nodes before the one you are currently rendering.
-->        
        <xsl:param name="nodes"/>
        <xsl:param name="result" select="0"/>
        <xsl:choose>
            <xsl:when test="$nodes">
                <xsl:call-template name="currentTotal">
                    <xsl:with-param name="nodes" select="$nodes[position()&gt;1]"/>
                    <xsl:with-param name="result" select="$result+$nodes[1]/@count"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="$result"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
    
</xsl:stylesheet>
