]> git.draconx.ca Git - homepage.git/blob - layouts/clickytable.xsl
Consolidate some clicky table label styles.
[homepage.git] / layouts / clickytable.xsl
1 <?xml version='1.0' encoding='UTF-8' ?>
2 <!--
3   Nick's web site: XHTML+CSS sortable clicky table headers.
4
5   Copyright © 2021 Nick Bowler
6
7   This implements the gory markup for clicky table headers, creating
8   input and related label elements to implement the clicking part.
9
10   To use: add the "clicky" attribute to each sortable header th element.
11   Class names corresponding to that header will be generated based on
12   the value of the attribute.  For example, a header with clicky='date'
13   will add class="clicky-date" to the header and generate two input
14   elements: one with class="clicky-date" to indicate when that column
15   is selected for sorting, and another with class="clicky-date-rev" to
16   indicate when the reverse ordering is selected for that column.
17
18   The input table itself must have two tbody sections. The first is a
19   completely normal table body in the default sort order.  The second
20   encodes all other possible orderings.
21
22   This program is free software: you can redistribute it and/or modify
23   it under the terms of the GNU General Public License as published by
24   the Free Software Foundation, either version 3 of the License, or
25   (at your option) any later version.
26
27   This program is distributed in the hope that it will be useful,
28   but WITHOUT ANY WARRANTY; without even the implied warranty of
29   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
30   GNU General Public License for more details.
31
32   You should have received a copy of the GNU General Public License
33   along with this program.  If not, see <https://www.gnu.org/licenses/>
34 -->
35 <xsl:stylesheet version='1.0'
36   xmlns='http://www.w3.org/1999/xhtml'
37   xmlns:xhtml='http://www.w3.org/1999/xhtml'
38   xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
39
40 <xsl:template match='xhtml:table/@clicky|xhtml:th/@clicky' />
41 <xsl:template match='xhtml:table[@clicky]'>
42   <xsl:variable name='group' select='generate-id(@clicky)' />
43   <xsl:variable name='clicky' select='@clicky' />
44
45   <div>
46     <script type='x'><![CDATA[]]x><!--]]></script>
47     <xsl:for-each select='xhtml:thead/*/xhtml:th/@clicky'>
48       <!-- hoist default element to be first in document order -->
49       <xsl:sort select='number(.!=$clicky)' data-type='number' />
50
51       <input style='display: none' id='sort-{generate-id(.)}'
52         type='radio' name='{$group}' class='clicky-{.}'>
53         <xsl:if test='.=$clicky'>
54           <xsl:attribute name='checked'>checked</xsl:attribute>
55         </xsl:if>
56       </input>
57     </xsl:for-each>
58     <xsl:for-each select='xhtml:thead/*/xhtml:th/@clicky'>
59       <input style='display: none' id='rev-{generate-id(.)}'
60         type='checkbox' class='clicky-{.}-rev' />
61     </xsl:for-each>
62     <script type='x'>--></script>
63
64     <xsl:copy>
65       <xsl:apply-templates select='node()|@*' />
66     </xsl:copy>
67   </div>
68 </xsl:template>
69
70 <xsl:template match='xhtml:table[@clicky]/xhtml:thead[*/xhtml:th/@clicky]'>
71   <xsl:copy>
72     <xsl:attribute name='class'>
73       <xsl:if test='@class'>
74         <xsl:value-of select='concat(@class, " ")' />
75       </xsl:if>
76       <xsl:text>clicky</xsl:text>
77     </xsl:attribute>
78     <xsl:apply-templates select='node()|@*[local-name() != "class"]' />
79   </xsl:copy>
80 </xsl:template>
81
82 <xsl:template match='xhtml:table[@clicky]/xhtml:thead/*/xhtml:th[@clicky]'>
83   <xsl:copy>
84     <xsl:attribute name='class'>
85       <xsl:if test='@class'>
86         <xsl:value-of select='concat(@class, " ")' />
87       </xsl:if>
88       <xsl:value-of select='concat("clicky-", @clicky)' />
89     </xsl:attribute>
90     <xsl:apply-templates select='@*[local-name() != "class"]' />
91
92     <label for='sort-{generate-id(@clicky)}'>
93       <xsl:text>&#x2060;</xsl:text>
94       <span><xsl:apply-templates select='node()' /></span>
95     </label>
96
97     <script type='x'><![CDATA[]]x><!--]]></script>
98     <label for='rev-{generate-id(@clicky)}' style='display: none'>
99       <xsl:text>&#x2060;</xsl:text>
100       <span><xsl:apply-templates select='node()' /></span>
101       <img alt='FWD' width='16' height='16' src='/icons/down.svg' />
102       <img alt='REV' width='16' height='16' src='/icons/up.svg' style='display: none' />
103     </label>
104     <script type='x'>--></script>
105   </xsl:copy>
106 </xsl:template>
107
108 <xsl:template match='xhtml:table[@clicky]/xhtml:tbody[last()]'>
109   <xsl:copy>
110     <xsl:attribute name='style'>
111       <xsl:if test='@style'>
112         <xsl:value-of select='concat(@style, "; ")' />
113       </xsl:if>
114       <xsl:text>display: none</xsl:text>
115     </xsl:attribute>
116     <xsl:apply-templates select='@*[local-name() != "style"]' />
117     <tr>
118       <td>
119         <xsl:for-each select='../*/xhtml:tr'>
120           <xsl:sort select='count(*)' data-type='number' order='descending' />
121           <xsl:if test='position()=1'>
122             <xsl:attribute name='colspan'>
123               <xsl:value-of select='count(*)' />
124             </xsl:attribute>
125           </xsl:if>
126         </xsl:for-each>
127         <hr/>
128       </td>
129     </tr>
130     <tr>
131       <xsl:for-each select='../xhtml:thead[1]/xhtml:tr[1]/*'>
132         <xsl:copy>
133           <xsl:value-of select='.' />
134         </xsl:copy>
135       </xsl:for-each>
136     </tr>
137     <xsl:apply-templates select='node()' />
138   </xsl:copy>
139 </xsl:template>
140
141 <!-- Insert script hack around the second <tbody> -->
142 <xsl:template match='xhtml:table[@clicky]/xhtml:tbody[1]/*[last()]/*[last()]'>
143   <xsl:copy>
144     <xsl:apply-templates select='node()|@*' />
145     <script type='x'><![CDATA[]]x><!--]]></script>
146   </xsl:copy>
147 </xsl:template>
148
149 <!-- Note that it is not allowed for <tr> to have no child elements. -->
150 <xsl:template
151   match='xhtml:table[@clicky]/xhtml:tbody[last()]/*[last()]/*[last()]'>
152   <xsl:copy>
153     <xsl:apply-templates select='node()|@*' />
154     <script type='x'>--></script>
155   </xsl:copy>
156 </xsl:template>
157
158 </xsl:stylesheet>