Changeset 7933 for branches/3.18-stable


Ignore:
Timestamp:
Apr 29, 2021, 2:19:17 PM (7 weeks ago)
Author:
Nicklas Nordborg
Message:

References #2246: Sticky table headers

Added support for setting sticky columns. The idea is to have the counter/checkbox/icon column sticky as well as the "Name" column for all item lists. This has been implemented in the samples list page.

Location:
branches/3.18-stable
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • branches/3.18-stable/src/clients/web/net/sf/basedb/clients/web/taglib/table/Cell.java

    r7908 r7933  
    337337    boolean overflowed = !disableOverflowCheck && maxCharacters > 0 && content.length() > maxCharacters &&
    338338      HTML.textLength(content) > maxCharacters;
     339    boolean isStickyCol = table.isColumnSticky(getColumn());
    339340
    340341    StringBuilder sb = new StringBuilder();
    341342    sb.append("\t<td");
    342     if (getClazz() != null || getSubclass() != null)
     343    if (getClazz() != null || getSubclass() != null || isStickyCol)
    343344    {
    344345      sb.append(" class=\"");
    345346      if (getClass() != null) sb.append(getClazz());
    346347      if (getSubclass() != null) sb.append(" ").append(getSubclass());
     348      if (isStickyCol) sb.append(" sticky-col bg-filled-100");
    347349      sb.append("\"");
    348350    }
  • branches/3.18-stable/src/clients/web/net/sf/basedb/clients/web/taglib/table/ColumnDef.java

    r7907 r7933  
    691691      boolean isSortable = isSortable() && table.getSc() != null &&  table.getItem() != null;
    692692      boolean isVisible = table.isColumnVisible(getId());
     693      boolean isStickyCol = table.isColumnSticky(getId());
    693694      boolean hasFilter = false;
    694695      if (isFilterable)
     
    714715        StringBuilder sb = new StringBuilder();
    715716        sb.append("<th");
    716         addIdAndStyles(sb, allowColumnDrag ? "table-col-draggable" : null);
     717        addIdAndStyles(sb, allowColumnDrag ? "table-col-draggable" : null, isStickyCol ? "sticky-col bg-filled-100" : null);
    717718        addDynamicAttributes(sb);
    718719        if (allowColumnDrag)
     
    767768         
    768769          sb = new StringBuilder();
    769           sb.append("<th class=\"propertyfilter\">");
     770          sb.append("<th class=\"propertyfilter"+(isStickyCol ? " sticky-col bg-filled-100" : "")+"\">");
    770771          if (isPermission)
    771772          {
  • branches/3.18-stable/src/clients/web/net/sf/basedb/clients/web/taglib/table/Table.java

    r7905 r7933  
    7070      subcontext=...
    7171      action=...
     72      stickyheaders=...
    7273      dragcolumns=true|false|null
    7374   &gt;
     
    198199      The name of the current subcontext. Used by some child taglibs for
    199200      generating context sensitive information (ie. PresetSelector).
     201    </td>
     202  </tr>
     203  <tr>
     204    <td>stickyheaders</td>
     205    <td>-</td>
     206    <td>no</td>
     207    <td>
     208      Enable sticky headers and optionally set the name of a sticky column.
     209      Do not set this attribute if the table should not have sticky headers.
    200210    </td>
    201211  </tr>
     
    271281 
    272282  /**
     283    If sticky headers is enabled or not.
     284  */
     285  private boolean stickyHeaders = false;
     286
     287  /**
     288    The id of a column that is "sticky".
     289  */
     290  private String stickyCol = null;
     291 
     292  /**
    273293    Number of filter rows in the table.
    274294  */
     
    337357  }
    338358
     359  /**
     360    @since 3.18.1
     361  */
     362  public void setStickyheaders(String stickyCol)
     363  {
     364    this.stickyCol = stickyCol;
     365    this.stickyHeaders = true;
     366  }
     367 
     368  /**
     369    @since 3.18.1
     370  */
     371  public boolean hasStickyHeaders()
     372  {
     373    return stickyHeaders;
     374  }
     375 
     376  /**
     377    @since 3.18.1
     378  */
     379  public String getStickyCol()
     380  {
     381    return stickyCol;
     382  }
     383 
     384 
    339385  private Boolean dragColumns;
    340386 
     
    495541    return visibleColumns;
    496542  }
     543  boolean isColumnSticky(String columnId)
     544  {
     545    return stickyHeaders && columnId.equals(stickyCol);
     546  }
    497547  Formatter<?> getFormatter(String columnId)
    498548  {
     
    708758    StringBuilder sb = new StringBuilder();
    709759    sb.append("<div ");
    710     addIdAndStyles(sb, "auto-init");
     760    addIdAndStyles(sb, "auto-init", hasStickyHeaders() ? "sticky-headers" : null);
    711761    sb.append(" data-auto-init=\"table\"");
    712762    addDynamicAttributes(sb);
  • branches/3.18-stable/www/WEB-INF/base.tld

    r7414 r7933  
    559559    </attribute>
    560560  </tag>
     561  <tag>
     562    <name>input</name>
     563    <tag-class>net.sf.basedb.clients.web.taglib.Input</tag-class>
     564    <body-content>JSP</body-content>
     565    <attribute>
     566      <name>id</name>
     567      <rtexprvalue>true</rtexprvalue>
     568    </attribute>
     569    <attribute>
     570      <name>clazz</name>
     571      <rtexprvalue>true</rtexprvalue>
     572    </attribute>
     573    <attribute>
     574      <name>subclass</name>
     575      <rtexprvalue>true</rtexprvalue>
     576    </attribute>
     577    <attribute>
     578      <name>style</name>
     579      <rtexprvalue>true</rtexprvalue>
     580    </attribute>
     581    <attribute>
     582      <name>type</name>
     583      <required>true</required>
     584      <rtexprvalue>true</rtexprvalue>
     585    </attribute>
     586    <attribute>
     587      <name>name</name>
     588      <required>true</required>
     589      <rtexprvalue>true</rtexprvalue>
     590    </attribute>
     591    <attribute>
     592      <name>value</name>
     593      <rtexprvalue>true</rtexprvalue>
     594    </attribute>
     595    <attribute>
     596      <name>checked</name>
     597      <rtexprvalue>true</rtexprvalue>
     598    </attribute>
     599    <attribute>
     600      <name>title</name>
     601      <rtexprvalue>true</rtexprvalue>
     602    </attribute>
     603    <attribute>
     604      <name>visible</name>
     605      <rtexprvalue>true</rtexprvalue>
     606    </attribute>
     607    <attribute>
     608      <name>tabindex</name>
     609      <rtexprvalue>true</rtexprvalue>
     610    </attribute>
     611    <dynamic-attributes>true</dynamic-attributes>
     612  </tag>
    561613</taglib>
  • branches/3.18-stable/www/WEB-INF/table.tld

    r7908 r7933  
    9595      <rtexprvalue>true</rtexprvalue>
    9696    </attribute>
     97    <attribute>
     98      <name>stickyheaders</name>
     99      <rtexprvalue>true</rtexprvalue>
     100    </attribute>
    97101    <dynamic-attributes>true</dynamic-attributes>
    98102  </tag>
  • branches/3.18-stable/www/biomaterials/samples/list_samples.jsp

    r7932 r7933  
    218218      item="<%=itemType%>"
    219219      filterrows="<%=cc.getFilterRows()%>"
    220       subclass="fulltable sticky-headers"
     220      subclass="fulltable"
    221221      data-inherited-annotations="true"
    222222      data-relateditem-columns="true"
     223      stickyheaders="name"
    223224      >
    224225      <tbl:hidden
     
    608609        <tbl:headers>
    609610          <tbl:headerrow>
    610             <tbl:header colspan="3" />
     611            <tbl:header clazz="row-index bg-filled-100" />
    611612            <tbl:columnheaders />
    612613          </tbl:headerrow>
     
    619620            %>
    620621            <tbl:headerrow>
    621               <tbl:header subclass="index" />
    622               <tbl:header
    623                 subclass="check"
    624                 visible="<%=mode.hasCheck()%>"
    625                 ><base:icon
    626                   subclass="link table-check"
    627                   image="check_uncheck.png"
    628                   tooltip="Toggle all (use CTRL, ALT or SHIFT to check/uncheck)"
    629                   visible="<%=lastRow%>"
    630                 /></tbl:header>
    631               <tbl:header
    632                 subclass="check"
    633                 visible="<%=mode.hasRadio()%>"
    634                 />
    635               <tbl:header
    636                 subclass="icons"
    637                 visible="<%=mode.hasIcons()%>"
    638                 >
    639                 <base:icon
    640                   subclass="link table-filter-row-action"
    641                   image="add.png"
    642                   tooltip="Add extra filter row"
    643                   visible="<%=lastRow%>"
    644                 /><base:icon
    645                   subclass="link table-filter-row-action"
    646                   image="remove.png"
    647                   tooltip="Remove this filter row"
    648                   visible="<%=numRows > 1 || numFilters > 0 %>"
    649                   data-remove-row="<%=filterNo%>"
    650                 />
     622              <tbl:header subclass="row-index bg-filled-100">
     623                <div class="index-<%=mode.getName()%>">
     624                  <div class="index"></div>
     625                  <div class="check">
     626                    <base:icon
     627                      subclass="link table-check"
     628                      image="check_uncheck.png"
     629                      tooltip="Toggle all (use CTRL, ALT or SHIFT to check/uncheck)"
     630                      visible="<%=lastRow && mode.hasCheck()%>"
     631                    />
     632                  </div>
     633                  <div class="icons">
     634                    <base:icon
     635                      subclass="link table-filter-row-action"
     636                      image="add.png"
     637                      tooltip="Add extra filter row"
     638                      visible="<%=lastRow%>"
     639                    /><base:icon
     640                      subclass="link table-filter-row-action"
     641                      image="remove.png"
     642                      tooltip="Remove this filter row"
     643                      visible="<%=numRows > 1 || numFilters > 0 %>"
     644                      data-remove-row="<%=filterNo%>"
     645                    />
     646                  </div>
     647                </div>
    651648              </tbl:header>
    652649              <tbl:propertyfilter row="<%=filterNo%>" />
     
    692689              %>
    693690              <tbl:row>
    694                 <tbl:header
    695                   clazz="index"
    696                   ><%=index%></tbl:header>
    697                 <tbl:header
    698                   clazz="check"
    699                   visible="<%=mode.hasCheck()%>"
    700                   ><input
    701                     type="checkbox"
    702                     name="<%=itemId%>"
    703                     value="<%=itemId%>"
    704                     title="<%=name%>"
    705                     <%=cc.getSelected().contains(itemId) ? "checked" : ""%>
    706                   ></tbl:header>
    707                 <tbl:header
    708                   clazz="check"
    709                   visible="<%=mode.hasRadio()%>"
    710                   ><input
    711                     type="radio"
    712                     name="item_id"
    713                     value="<%=itemId%>"
    714                     title="<%=name%>"
    715                     <%=selectedItemId == itemId ? "checked" : ""%>
    716                   ></tbl:header>
    717                 <tbl:header
    718                   clazz="icons"
    719                   visible="<%=mode.hasIcons()%>"
    720                   ><base:icon
    721                     image="deleted.png"
    722                     id="<%="delete."+itemId %>"
    723                     subclass="<%=deletePermission ? "table-delete-item" : "disabled" %>"
    724                     data-item-id="<%=itemId%>"
    725                     tooltip="This item has been scheduled for deletion"
    726                     visible="<%=item.isRemoved()%>"
    727                   /><base:icon
    728                     image="shared.png"
    729                     id="<%="share."+itemId %>"
    730                     subclass="<%=sharePermission ? "table-share-item" : "disabled" %>"
    731                     data-item-id="<%=itemId%>"
    732                     tooltip="This item is shared to other users, groups and/or projects"
    733                     visible="<%=item.isShared()%>"
    734                   />&nbsp;</tbl:header>
     691                <tbl:header clazz="row-index bg-filled-100">
     692                  <div class="index-<%=mode.getName()%>">
     693                    <div class="index"><%=index%></div>
     694                    <div class="check">
     695                      <base:input
     696                        type="checkbox"
     697                        name="<%=itemId%>"
     698                        value="<%=itemId%>"
     699                        title="<%=name%>"
     700                        checked="<%=cc.getSelected().contains(itemId)%>"
     701                        visible="<%=mode.hasCheck()%>"
     702                      />
     703                      <base:input
     704                        type="radio"
     705                        name="item_id"
     706                        value="<%=itemId%>"
     707                        title="<%=name%>"
     708                        checked="<%=selectedItemId == itemId%>"
     709                        visible="<%=mode.hasRadio()%>"
     710                      />
     711                    </div>
     712                    <div class="icons">
     713                      <base:icon
     714                        image="deleted.png"
     715                        id="<%="delete."+itemId %>"
     716                        subclass="<%=deletePermission ? "table-delete-item" : "disabled" %>"
     717                        data-item-id="<%=itemId%>"
     718                        tooltip="This item has been scheduled for deletion"
     719                        visible="<%=item.isRemoved()%>"
     720                      /><base:icon
     721                        image="shared.png"
     722                        id="<%="share."+itemId %>"
     723                        subclass="<%=sharePermission ? "table-share-item" : "disabled" %>"
     724                        data-item-id="<%=itemId%>"
     725                        tooltip="This item is shared to other users, groups and/or projects"
     726                        visible="<%=item.isShared()%>"
     727                      />
     728                    </div>
     729                  </div>
     730                </tbl:header>
    735731                <tbl:cell column="name"><div
    736732                  class="link table-item"
     
    738734                  data-no-edit="<%=writePermission ? 0 : 1 %>"
    739735                  tabindex="0"
    740                   title="<%=tooltip%>"><%=name%></div></tbl:cell>
     736                  title="<%=tooltip%>"
     737                  ><%=name%></div></tbl:cell>
    741738                <tbl:cell column="id"><%=item.getId()%></tbl:cell>
    742739                <tbl:cell column="itemSubtype"><base:propertyvalue
  • branches/3.18-stable/www/include/styles/main.css

    r7929 r7933  
    732732  -webkit-transition: all 0.3s ease 0.1s;
    733733}
     734
     735.highlight:hover > td, .highlight:hover > th
     736{
     737  background-color: #F8F8E8 !important;
     738  border-top: 1px solid #2288AA !important;
     739  border-bottom: 1px solid #2288AA !important;
     740  transition: all 0.3s ease 0.1s;
     741  -moz-transition: all 0.3s ease 0.1s;
     742  -webkit-transition: all 0.3s ease 0.1s;
     743}
     744
    734745
    735746/* The subtype of an item */
  • branches/3.18-stable/www/include/styles/table.css

    r7932 r7933  
    148148  font-weight: bold;
    149149  white-space: nowrap;
    150   border-left-width: 1px;
    151   border-left-style: dotted;
     150  border-right-width: 1px;
     151  border-right-style: dotted;
    152152  padding: 1px 2px 1px 2px;
    153153  vertical-align: middle;
     
    155155}
    156156
     157.itemlist div.data > table > thead > tr > th:last-child
     158{
     159  border-right-width: 0;
     160}
     161
    157162.itemlist div.data > table > thead > tr > th.subtitle
    158163{
     
    167172}
    168173
    169 .itemlist div.data > table > thead > tr > th:first-child
    170 {
    171   border-left: 0;
    172 }
    173 
     174.itemlist div.data th.row-index
     175{
     176  padding: 0;
     177}
     178
     179.itemlist div.data th.row-index > div
     180{
     181  display: grid;
     182  grid-template-columns: 1fr 20px 36px;
     183  align-items: center;
     184  margin: 0 2px;
     185}
     186.itemlist div.data th.row-index > div > div
     187{
     188  display: flex;
     189}
     190
     191.itemlist div.data th.row-index > div > div.index
     192{
     193  justify-content: flex-end;
     194}
     195.itemlist div.data th.row-index > div > div.check
     196{
     197  justify-content: center;
     198}
     199.itemlist div.data th.row-index > div > div.icons
     200{
     201  justify-content: flex-end;
     202}
     203
     204.itemlist div.data th.row-index > div > div.icons img
     205{
     206  margin: 1px;
     207}
    174208
    175209/* Header column that contains index number of item */
    176210.itemlist div.data th.index
    177211{
    178   border-left: 0;
     212  border-right-width: 0;
    179213  text-align: right;
    180214  width: 3em;
     
    185219.itemlist div.data th.check
    186220{
    187   border-left: 0;
     221  border-right-width: 0;
    188222  text-align: center;
    189223  width: 2em;
     
    195229{
    196230  width: 40px; /* Should be enough to hold two icons */
    197   border-left: 0;
     231  border-right-width: 1px;
     232  border-right-style: dotted;
    198233  text-align: right;
    199234  white-space: nowrap;
     
    339374.bg-evenrow
    340375{
    341   background: rgba(224, 224, 224, 0.5);
     376  background-color: rgba(224, 224, 224, 0.5);
     377}
     378.bg-evenrow .bg-filled-100
     379{
     380  background-color: rgba(240, 240, 240, 1);
    342381}
    343382
    344383.bg-oddrow
    345384{
    346   background: rgba(240, 240, 240, 0.5);
    347 }
    348 
     385  background-color: rgba(240, 240, 240, 0.5);
     386}
     387.bg-oddrow .bg-filled-100
     388{
     389  background-color: rgba(248, 248, 248, 1);
     390}
    349391
    350392/* A data cell */
    351393.itemlist div.data td.cell
    352394{
    353   border-left-width: 1px;
    354   border-left-style: dotted;
     395  border-right-width: 1px;
     396  border-right-style: dotted;
    355397  padding: 1px 2px 0px 2px;
    356398  vertical-align: middle;
     
    358400}
    359401
    360 .itemlist div.data td.cell:first-child
    361 {
    362   border-left: 0;
     402.itemlist div.data td.cell:last-child
     403{
     404  border-right-width: 0;
    363405}
    364406
     
    481523}
    482524
    483 .itemlist.sticky-headers div.data > table > tbody.rows > tr.row.highlight:hover > *
    484 {
    485   border-top: 1px solid #2288AA;
    486   border-bottom: 1px solid #2288AA;
    487 }
    488 
    489525.itemlist.sticky-headers div.data > table > tbody.rows > tr.row.highlight:hover + tr > *
    490526{
     
    492528}
    493529
     530.itemlist.sticky-headers div.data th.row-index
     531{
     532  position: sticky;
     533  left: 0;
     534  min-width: 8em;
     535  border-right-width: 1px;
     536  border-right-style: dotted;
     537}
     538
     539.itemlist.sticky-headers div.data .sticky-col
     540{
     541  position: sticky;
     542  left: 8em;
     543  right: 0;
     544}
Note: See TracChangeset for help on using the changeset viewer.