]> git.draconx.ca Git - homepage.git/blobdiff - layouts/clickytable.xsl
Improve clicky table generation.
[homepage.git] / layouts / clickytable.xsl
diff --git a/layouts/clickytable.xsl b/layouts/clickytable.xsl
new file mode 100644 (file)
index 0000000..f442fa4
--- /dev/null
@@ -0,0 +1,125 @@
+<?xml version='1.0' encoding='UTF-8' ?>
+<!--
+  Nick's web site: XHTML+CSS sortable clicky table headers.
+
+  Copyright © 2021 Nick Bowler
+
+  This implements the gory markup for clicky table headers, creating
+  input and related label elements to implement the clicking part.
+
+  To use: add the "clicky" attribute to each sortable header th element.
+  Class names corresponding to that header will be generated based on
+  the value of the attribute.  For example, a header with clicky='date'
+  will add class="clicky-date" to the header and generate two input
+  elements: one with class="clicky-date" to indicate when that column
+  is selected for sorting, and another with class="clicky-date-rev" to
+  indicate when the reverse ordering is selected for that column.
+
+  The input table itself must have two tbody sections. The first is a
+  completely normal table body in the default sort order.  The second
+  encodes all other possible orderings.
+
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <https://www.gnu.org/licenses/>
+-->
+<xsl:stylesheet version='1.0'
+  xmlns='http://www.w3.org/1999/xhtml'
+  xmlns:xhtml='http://www.w3.org/1999/xhtml'
+  xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
+
+<xsl:template match='xhtml:table/@clicky|xhtml:th/@clicky' />
+<xsl:template match='xhtml:table[@clicky]'>
+  <xsl:variable name='group' select='generate-id(@clicky)' />
+  <xsl:variable name='clicky' select='@clicky' />
+
+  <div>
+    <script type='x'><![CDATA[]]x><!--]]></script>
+    <xsl:for-each select='xhtml:thead/*/xhtml:th/@clicky'>
+      <!-- hoist default element to be first in document order -->
+      <xsl:sort select='number(.!=$clicky)' data-type='number' />
+
+      <input style='display: none' id='sort-{generate-id(.)}'
+        type='radio' name='{$group}' class='clicky-{.}'>
+        <xsl:if test='.=$clicky'>
+          <xsl:attribute name='checked'>checked</xsl:attribute>
+        </xsl:if>
+      </input>
+    </xsl:for-each>
+    <xsl:for-each select='xhtml:thead/*/xhtml:th/@clicky'>
+      <input style='display: none' id='rev-{generate-id(.)}'
+        type='checkbox' class='clicky-{.}-rev' />
+    </xsl:for-each>
+    <script type='x'>--></script>
+
+    <xsl:copy>
+      <xsl:apply-templates select='node()|@*' />
+    </xsl:copy>
+  </div>
+</xsl:template>
+
+<xsl:template match='xhtml:table[@clicky]/xhtml:thead/*/xhtml:th[@clicky]'>
+  <xsl:copy>
+    <xsl:attribute name='class'>
+      <xsl:if test='@class'>
+        <xsl:value-of select='concat(@class, " ")' />
+      </xsl:if>
+      <xsl:value-of select='concat("clicky-", @clicky)' />
+    </xsl:attribute>
+    <xsl:apply-templates select='@*[local-name() != "class"]' />
+
+    <label for='sort-{generate-id(@clicky)}'>
+      <xsl:text>&#x2060;</xsl:text>
+      <span><xsl:apply-templates select='node()' /></span>
+    </label>
+
+    <script type='x'><![CDATA[]]x><!--]]></script>
+    <label for='rev-{generate-id(@clicky)}' style='display: none'>
+      <xsl:text>&#x2060;</xsl:text>
+      <span><xsl:apply-templates select='node()' /></span>
+      <img alt='FWD' width='16' height='16' src='/images/down.svg' />
+      <img alt='REV' width='16' height='16' src='/images/up.svg' style='display: none' />
+    </label>
+    <script type='x'>--></script>
+  </xsl:copy>
+</xsl:template>
+
+<xsl:template match='xhtml:table[@clicky]/xhtml:tbody[last()]'>
+  <xsl:copy>
+    <xsl:attribute name='style'>
+      <xsl:if test='@style'>
+        <xsl:value-of select='concat(@style, "; ")' />
+      </xsl:if>
+      <xsl:text>display: none</xsl:text>
+    </xsl:attribute>
+    <xsl:apply-templates select='node()|@*[local-name() != "style"]' />
+  </xsl:copy>
+</xsl:template>
+
+<!-- Insert script hack around the second <tbody> -->
+<xsl:template match='xhtml:table[@clicky]/xhtml:tbody[1]/*[last()]/*[last()]'>
+  <xsl:copy>
+    <xsl:apply-templates select='node()|@*' />
+    <script type='x'><![CDATA[]]x><!--]]></script>
+  </xsl:copy>
+</xsl:template>
+
+<!-- Note that it is not allowed for <tr> to have no child elements. -->
+<xsl:template
+  match='xhtml:table[@clicky]/xhtml:tbody[last()]/*[last()]/*[last()]'>
+  <xsl:copy>
+    <xsl:apply-templates select='node()|@*' />
+    <script type='x'>--></script>
+  </xsl:copy>
+</xsl:template>
+
+</xsl:stylesheet>