XForms/Folding Menus

      Motivation

      You want to display a complex list of choices in a tree structure where each branch could be opened and closed.

      ↑Jump back a section

      Sample Program

      <html
         xmlns="http://www.w3.org/1999/xhtml"
         xmlns:xf="http://www.w3.org/2002/xforms"
         xmlns:xsd="http://www.w3.org/2001/XMLSchema"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns:ev="http://www.w3.org/2001/xml-events">
         <head>
            <title>Folding Menus</title>
            <xf:model id="modelID" ev:event="" functions="" schema="">
               <xf:instance id="instanceData" xmlns="">
                  <group id="mainGroup">
                     <group id="group1" fold="0" category="Category One">
                        <item id="item1">Enter Data</item>
                        <item id="item2">Enter Data</item>
                        <item id="item3">Enter Data</item>
                        <group id="group2" fold="0" category="Category Two">
                           <item id="item4">Enter Data</item>
                           <item id="item5">Enter Data</item>
                           <group id="group3" fold="0" category="Category Three">
                              <item id="item6">Enter Data</item>
                              <item id="item7">Enter Data</item>
                              <item id="item8">Enter Data</item>
                           </group>
                           <item id="item9">Enter Data</item>
                        </group>
                     </group>
                  </group>
               </xf:instance>
               <xf:instance id="foldedNodes" xmlns="">
                  <foldednodes>
                     <nodelist />
                  </foldednodes>
               </xf:instance>
       
               <xf:bind nodeset="descendant::*"
                  relevant="not(contains(instance('foldedNodes')/nodelist, current()/parent::*/@id))"
                />
            </xf:model>
       
            <style type="text/css">
               @namespace xhtml url("http://www.w3.org/1999/xhtml");
               @namespace xf url("http://www.w3.org/2002/xforms");
               xf|*:disabled {
               display: none;
               }
            </style>
       
         </head>
       
         <body>
       
            <div class="header">Folding Test</div>
       
            <xf:group id="mainGroup">
               <xf:output ref="instance('foldedNodes')/nodelist">
                  <xf:label>ID List</xf:label>
               </xf:output>
               <xf:repeat nodeset="instance('instanceData')/descendant::group" id="repeatGroup">
                  <xf:output class="outputInline"
                     value="concat(substring('&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;',1,3 * count(current()/ancestor::*)), '&#160;&#160;&#160;&#160;&#160;')" />
                  <xf:trigger>
                     <xf:label>
                        <xf:output
                           value="if(contains(instance('foldedNodes')/nodelist, ./@id), '+', '-')"
                         />
                     </xf:label>
                     <xf:action ev:event="DOMActivate">
                        <xf:setvalue ref="instance('foldedNodes')/nodelist"
                           value="if(contains(instance('foldedNodes')/nodelist, instance('instanceData')/descendant::group[position()=index('repeatGroup')]/@id), concat(substring-before(instance('foldedNodes')/nodelist, instance('instanceData')/descendant::group[position()=index('repeatGroup')]/@id), substring-after(instance('foldedNodes')/nodelist, instance('instanceData')/descendant::group[position()=index('repeatGroup')]/@id)), concat(instance('foldedNodes')/nodelist, instance('instanceData')/descendant::group[position()=index('repeatGroup')]/@id))"
                         />
                     </xf:action>
                  </xf:trigger>
                  <xf:output class="outputInline" ref="./@category" />
                  <xf:repeat nodeset="./item" id="repeatItem">
                     <xf:output class="outputInline"
                        value="concat(substring('&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;',1,3 * count(current()/ancestor::*)), '&#160;&#160;&#160;&#160;&#160;')" />
                     <xf:output class="outputInline" ref="./@id">
                        <xf:label>id: </xf:label>
                     </xf:output>
                     <xf:input class="inputInline" ref=".[name() = 'item' or name() = 'file']">
                        <xf:label>data: </xf:label>
                     </xf:input>
                  </xf:repeat>
               </xf:repeat>
            </xf:group>
       
         </body>
      </html>
      
      ↑Jump back a section

      Discussion

      There are some interesteing XPath expressions in this example. For example the following counts the number of ancestor nodes of the current node:

        count(current()/ancestor::*)
      

      The following gets all of the decendant groups within the instance data:

        instance('instanceData')/descendant::group
      

      The following returns a "+" if the nodelist contains the value in the id attribute and a "-" if it does not.

        if(contains(instance('foldedNodes')/nodelist, ./@id), '+', '-')
      
      ↑Jump back a section

      Credits

      Thanks to Fraser for posting this on the Mozilla XForms developer newsgroup in Oct. of 2007


      Next Page: Tree Menus | Previous Page: Vertical Menu

      Home: XForms

      ↑Jump back a section
      Last modified on 9 July 2009, at 20:11