xformsxsltforms

XSLTforms/xforms moving elements up and down with in a repeat section


I am using XSLTforms to render my XForms. I have a form that dynamically groups elements into different repeat groups (client wants to group the elements in this way for UI purposes). The two groups of elements are all children of the same parent element, which can also repeat. I want to be able to move elements up and down within the repeat groups, this works for the first repeat group, but not for second group. Essentially I need to be able to get the position of the current item within the parent element, but the repeat index seems to only operate on the current repeat.

Simplified code:

<html xmlns="http://www.w3.org/1999/xhtml" 
   xmlns:ev="http://www.w3.org/2001/xml-events"
   xmlns:xf="http://www.w3.org/2002/xforms">
   <head>
      <xf:model id="m-mss">
         <xf:instance id="i-rec">
            <TEI xmlns="http://www.tei-c.org/ns/1.0">
               <msIdentifier>
                  <!-- group a -->
                  <country>1a</country>
                  <institution>2a</institution>
                  <settlement>3a</settlement>
                  <institution>4a</institution>
                  <!-- group b -->
                  <altIdentifier>1b</altIdentifier>
                  <altIdentifier>2b</altIdentifier>
                  <altIdentifier>3b</altIdentifier>
                  <msName>4b</msName>
               </msIdentifier>
            </TEI>
         </xf:instance>
         <xf:instance id="i-move">
            <data xmlns="">
               <tmp/>
            </data>
         </xf:instance>
         <xf:instance id="i-repeatIndex">
            <data xmlns="">
               <index>1</index>
            </data>
         </xf:instance>
      </xf:model>
   </head>
   <body>
      <h2>Parent Element </h2>
      <xf:repeat
         ref="instance('i-rec')//descendant::*:msIdentifier[position() = instance('i-repeatIndex')/index]"
         id="msIdentifierRepeatLevel1">
         <div id="elementGroup" style="margin:12px; padding:12px; border:1px solid #ccc;">
            <div>
               <h2>location, institution, settlement</h2>
               <div>
                  <xf:repeat id="msIdentifierRepeatLevel11"
                     ref="./*[contains(local-name(),'country') or contains(local-name(),'settlement') or contains(local-name(),'institution')]">
                     <div class="btn-group" role="group">
                        <xf:trigger xmlns="http://www.w3.org/2002/xforms" appearance="minimal"
                           class="btn controls moveUp inline">
                           <xf:label>up</xf:label>
                           <xf:action ev:event="DOMActivate">
                              <setvalue ref="instance('i-move')/tmp"
                                 value="index('msIdentifierRepeatLevel11')"/>
                              <insert
                                 origin="instance('i-rec')//tei:msIdentifier[position() = instance('i-repeatIndex')/index]/*[index('msIdentifierRepeatLevel11')]"
                                 nodeset="instance('i-rec')//tei:msIdentifier[position() = instance('i-repeatIndex')/index]/*"
                                 at="index('msIdentifierRepeatLevel11') - 1" position="before"/>
                              <delete
                                 nodeset="instance('i-rec')//tei:msIdentifier[position() = instance('i-repeatIndex')/index]/*[instance('i-move')/tmp + 1]"
                              />
                           </xf:action>
                        </xf:trigger> | <xf:trigger xmlns="http://www.w3.org/2002/xforms"
                           appearance="minimal" class="btn controls moveDown inline">
                           <xf:label>down</xf:label>
                           <xf:action ev:event="DOMActivate">
                              <setvalue ref="instance('i-move')/tmp"
                                 value="index('msIdentifierRepeatLevel1')"/>
                              <insert
                                 origin="instance('i-rec')//tei:msIdentifier[position() = instance('i-repeatIndex')/index]/*[index('msIdentifierRepeatLevel11')]"
                                 nodeset="instance('i-rec')//tei:msIdentifier[position() = instance('i-repeatIndex')/index]/*"
                                 at="index('msIdentifierRepeatLevel11') + 1" position="after"/>
                              <delete nodeset="."/>
                           </xf:action>
                        </xf:trigger> | <span class="elementLabel"><xf:output value="local-name()"
                              class="elementLabel"/></span>
                     </div>
                     <span class="element">
                        <xf:input class="elementInput" ref="."/>
                     </span>
                  </xf:repeat>
               </div>
            </div>
         </div>
         <div id="elementGroup2" style="margin:12px; padding:12px; border:1px solid #ccc;">
            <div>
               <h2>altIdentifier, msName</h2>
               <div>
                  <xf:repeat id="msIdentifierRepeatLevel12"
                     ref="./*[contains(local-name(),'altIdentifier') or contains(local-name(),'msName')]">
                     <div class="btn-group" role="group">
                        <xf:trigger xmlns="http://www.w3.org/2002/xforms" appearance="minimal"
                           class="btn controls moveUp inline">
                           <xf:label>up</xf:label>
                           <xf:action ev:event="DOMActivate">
                              <setvalue ref="instance('i-move')/tmp"
                                 value="index('msIdentifierRepeatLevel12')"/>
                              <insert
                                 origin="instance('i-rec')//tei:msIdentifier[position() = instance('i-repeatIndex')/index]/*[index('msIdentifierRepeatLevel12')]"
                                 nodeset="instance('i-rec')//tei:msIdentifier[position() = instance('i-repeatIndex')/index]/*"
                                 at="index('msIdentifierRepeatLevel12') - 1" position="before"/>
                              <delete
                                 nodeset="instance('i-rec')//tei:msIdentifier[position() = instance('i-repeatIndex')/index]/*[instance('i-move')/tmp + 1]"
                              />
                           </xf:action>
                        </xf:trigger> | <xf:trigger xmlns="http://www.w3.org/2002/xforms"
                           appearance="minimal" class="btn controls moveDown inline">
                           <xf:label>down</xf:label>
                           <xf:action ev:event="DOMActivate">
                              <setvalue ref="instance('i-move')/tmp"
                                 value="index('msIdentifierRepeatLevel12')"/>
                              <insert
                                 origin="instance('i-rec')//tei:msIdentifier[position() = instance('i-repeatIndex')/index]/*[index('msIdentifierRepeatLevel12')]"
                                 nodeset="instance('i-rec')//tei:msIdentifier[position() = instance('i-repeatIndex')/index]/*"
                                 at="index('msIdentifierRepeatLevel12') + 1" position="after"/>
                              <delete nodeset="."/>
                           </xf:action>
                        </xf:trigger> | <span class="elementLabel"><xf:output value="local-name()"
                              class="elementLabel"/></span>
                     </div>
                     <span class="element">
                        <xf:input class="elementInput" ref="."/>
                     </span>
                  </xf:repeat>
               </div>
            </div>
         </div>
      </xf:repeat>
   </body>
</html>

This form is part of a larger more complex form, I have tried to simplify it is much as possible. If anyone has any ideas how this might work, or if it is even possible that would be so helpful, I have run out of ideas.

Thanks so much! -Winona


Solution

  • Getting the position of the current item is always possible using the preceding-sibling:: axis and the count() function.

    Without using variables, this test case can be fixed like this:

    <xf:repeat id="msIdentifierRepeatLevel11" ref="tei:country | tei:settlement | tei:institution">
       <div class="btn-group" role="group">
          <xf:trigger xmlns="http://www.w3.org/2002/xforms" appearance="minimal" class="btn controls moveUp inline">
             <xf:label><xf:output value="choose(count(preceding-sibling::*[self::tei:country | self::tei:settlement | self::tei:institution]) != 0, 'up', '--')"/></xf:label>
             <xf:action ev:event="DOMActivate" if="count(preceding-sibling::*[self::tei:country | self::tei:settlement | self::tei:institution]) != 0">
                <xf:setvalue ref="instance('i-move')/tmp" value="count(context()/preceding-sibling::*[self::tei:country | self::tei:settlement | self::tei:institution][1]/preceding-sibling::*) + 1"/>
                <xf:insert origin="." ref="parent::*/*" at="instance('i-move')/tmp" position="before"/>
                <xf:delete ref="."/>
             </xf:action>
          </xf:trigger> | 
          <xf:trigger xmlns="http://www.w3.org/2002/xforms" appearance="minimal" class="btn controls moveDown inline">
             <xf:label><xf:output value="choose(count(following-sibling::*[self::tei:country | self::tei:settlement | self::tei:institution]) != 0, 'down', '----')"/></xf:label>
             <xf:action ev:event="DOMActivate" if="count(following-sibling::*[self::tei:country | self::tei:settlement | self::tei:institution]) != 0">
                <xf:setvalue ref="instance('i-move')/tmp" value="count(context()/following-sibling::*[self::tei:country | self::tei:settlement | self::tei:institution][1]/preceding-sibling::*) + 1"/>
                <xf:insert origin="." ref="parent::*/*" at="instance('i-move')/tmp" position="after"/>
                <xf:delete ref="."/>
             </xf:action>
          </xf:trigger> | 
          <span class="elementLabel"><xf:output value="local-name()" class="elementLabel"/></span>
       </div>
       <span class="element">
          <xf:input class="elementInput" ref="."/>
       </span>
    </xf:repeat>
    ...
    <xf:repeat id="msIdentifierRepeatLevel12" ref="tei:altIdentifier | tei:msName">
       <div class="btn-group" role="group">
          <xf:trigger xmlns="http://www.w3.org/2002/xforms" appearance="minimal" class="btn controls moveUp inline">
             <xf:label><xf:output value="choose(count(preceding-sibling::*[self::tei:altIdentifier | self::tei:msName]) != 0, 'up', '--')"/></xf:label>
             <xf:action ev:event="DOMActivate">
                <xf:setvalue ref="instance('i-move')/tmp" value="count(context()/preceding-sibling::*[self::tei:altIdentifier | self::tei:msName][1]/preceding-sibling::*) + 1"/>
                <xf:insert origin="." ref="parent::*/*" at="instance('i-move')/tmp" position="before"/>
                <xf:delete ref="."/>
             </xf:action>
          </xf:trigger> | 
          <xf:trigger xmlns="http://www.w3.org/2002/xforms" appearance="minimal" class="btn controls moveDown inline">
             <xf:label><xf:output value="choose(count(following-sibling::*[self::tei:altIdentifier | self::tei:msName]) != 0, 'down', '----')"/></xf:label>
             <xf:action ev:event="DOMActivate">
                <xf:setvalue ref="instance('i-move')/tmp" value="count(context()/following-sibling::*[self::tei:altIdentifier | self::tei:msName][1]/preceding-sibling::*) + 1"/>
                <xf:insert origin="." ref="parent::*/*" at="instance('i-move')/tmp" position="after"/>
                <xf:delete ref="."/>
             </xf:action>
          </xf:trigger> | 
          <span class="elementLabel"><xf:output value="local-name()" class="elementLabel"/></span>
       </div>
       <span class="element">
          <xf:input class="elementInput" ref="."/>
       </span>
    </xf:repeat>