Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   /*
    * JBoss, Home of Professional Open Source
    * Copyright ${year}, Red Hat, Inc. and individual contributors
    * by the @authors tag. See the copyright.txt in the distribution for a
    * full listing of individual contributors.
    *
    * This is free software; you can redistribute it and/or modify it
    * under the terms of the GNU Lesser General Public License as
    * published by the Free Software Foundation; either version 2.1 of
   * the License, or (at your option) any later version.
   *
   * This software 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
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
   * License along with this software; if not, write to the Free
   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
   */
  package org.richfaces.renderkit;
  
  import static org.richfaces.renderkit.RenderKitUtils.addToScriptHash;
  import static org.richfaces.renderkit.RenderKitUtils.renderAttribute;
  import static org.richfaces.renderkit.util.AjaxRendererUtils.buildAjaxFunction;
  
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  
  import  javax.faces.FacesException;
  import  javax.faces.application.FacesMessage;
  import  javax.faces.application.ResourceDependencies;
  import  javax.faces.application.ResourceDependency;
  import  javax.faces.component.UIComponent;
  import  javax.faces.context.FacesContext;
  import  javax.faces.context.PartialResponseWriter;
  import  javax.faces.context.PartialViewContext;
  import  javax.faces.context.ResponseWriter;
  
  import  org.ajax4jsf.javascript.JSFunction;
  import  org.ajax4jsf.javascript.JSReference;
  import  org.ajax4jsf.javascript.ScriptUtils;
  import  org.ajax4jsf.model.DataVisitResult;
  import  org.ajax4jsf.model.DataVisitor;
  import  org.ajax4jsf.model.SequenceRange;
  import  org.richfaces.component.SortOrder;
  import  org.richfaces.model.SelectionMode;

Author(s):
Konstantin Mishin
  
  @JsfRenderer(type = "org.richfaces.ExtendedDataTableRenderer", family = .)
  @ResourceDependencies({ @ResourceDependency(library = "org.richfaces", name = "ajax.reslib"),
          @ResourceDependency(library = "org.richfaces", name = "base-component.reslib"),
          @ResourceDependency(name = "jquery.position.js"),
          @ResourceDependency(name = "richfaces-event.js"),
          @ResourceDependency(library = "org.richfaces", name = "extendedDataTable.js"),
          @ResourceDependency(library = "org.richfaces", name = "extendedDataTable.ecss") })
  public class ExtendedDataTableRenderer extends SelectionRenderer implements MetaComponentRenderer {
      private static final JSReference CLIENT_PARAMS = new JSReference("clientParams");
  
      private static enum PartName {
  
          frozen,
          normal;
          private String id;
  
          private PartName() {
               = String.valueOf(this.toString().charAt(0));
          }
  
          public String getId() {
              return ;
          }
      }
  
      private class Part {
          private PartName name;
          private List<UIComponent> columns;
  
          public Part(PartName nameList<UIComponent> columns) {
             this. = name;
             this. = columns;
         }
 
         public PartName getName() {
             return ;
         }
 
         public List<UIComponent> getColumns() {
             return ;
         }
     }
 
     private class RendererState extends RowHolderBase {
         private UIDataTableBase table;
         private List<Partparts;
         private Part current;
         private Iterator<PartpartIterator;
         private EncoderVariance encoderVariance = .;
 
         public RendererState(FacesContext contextUIDataTableBase table) {
             super(context);
             this. = table;
 
             List<UIComponent> columns = getOrderedColumns(context);
 
             int frozenColumnsAttribute = (Integertable.getAttributes().get("frozenColumns");
             if (frozenColumnsAttribute < 0 || frozenColumnsAttribute >= columns.size()) {
                 frozenColumnsAttribute = 0;
             }
 
             int count = Math.min(frozenColumnsAttributecolumns.size());
             List<UIComponent> frozenColumns = columns.subList(0, count);
             columns = columns.subList(countcolumns.size());
              = new ArrayList<Part>(PartName.values().length);
             if (frozenColumns.size() > 0) {
                 .add(new Part(.frozenColumns));
             }
             if (columns.size() > 0) {
                 .add(new Part(.columns));
             }
         }
 
         private List<UIComponent> getOrderedColumns(FacesContext context) {
             Map<String, UIComponent> columnsMap = new LinkedHashMap<String, UIComponent>();
             Iterator<UIComponent> iterator = .columns();
             while (iterator.hasNext()) { // initialize a map of all the columns
                 UIComponent component = iterator.next();
                 if (component.isRendered()) {
                     columnsMap.put(component.getId(), component);
                 }
             }
 
             List<UIComponent> columns = new ArrayList<UIComponent>();
 
             String[] columnsOrder = RenderKitUtils.evaluateAttribute("columnsOrder"context);
             if (columnsOrder != null && columnsOrder.length > 0) { // add columns in the order specified by columnsOrder
                 for (int i = 0; i < columnsOrder.length && !columnsMap.isEmpty(); i++) {
                     columns.add(columnsMap.remove(columnsOrder[i]));
                 }
             }
             for (UIComponent column : columnsMap.values()) { // add the remaining columns
                 columns.add(column);
             }
 
             return columns;
         }
 
         public UIDataTableBase getRow() {
             return ;
         }
 
         public void startIterate() {
              = .iterator();
         }
 
         public Part nextPart() {
              = .next();
             return ;
         }
 
         public Part getPart() {
             return ;
         }
 
         public boolean hasNextPart() {
             return .hasNext();
         }
 
         public EncoderVariance getEncoderVariance() {
             return ;
         }
 
         public void setEncoderVariance(EncoderVariance encoderVariance) {
             this. = encoderVariance;
         }
     }
 
     private enum EncoderVariance {
         full {
             public void encodeStartUpdate(FacesContext contextString targetIdthrows IOException {
                 // do nothing
             }
 
             public void encodeEndUpdate(FacesContext contextthrows IOException {
                 // do nothing
             }
         },
         partial {
             private void switchResponseWriter(FacesContext contextboolean writerState) {
                 ResponseWriter writer = context.getResponseWriter();
                 ((OnOffResponseWriterwriter).setSwitchedOn(writerState);
             }
 
             public void encodeStartUpdate(FacesContext contextString targetIdthrows IOException {
                 switchResponseWriter(contexttrue);
 
                 context.getPartialViewContext().getPartialResponseWriter().startUpdate(targetId);
             }
 
             public void encodeEndUpdate(FacesContext contextthrows IOException {
                 context.getPartialViewContext().getPartialResponseWriter().endUpdate();
 
                 switchResponseWriter(contextfalse);
             }
         };
 
         public abstract void encodeStartUpdate(FacesContext contextString targetIdthrows IOException;
 
         public abstract void encodeEndUpdate(FacesContext contextthrows IOException;
 
     }
 
     private static final Map<java.lang.Stringorg.richfaces.renderkit.ComponentAttributeEVENT_ATTRIBUTES = Collections
         .unmodifiableMap(ComponentAttribute.createMap(
             new ComponentAttribute("onselectionchange").setEventNames(new String[] { "selectionchange" }),
             new ComponentAttribute("onbeforeselectionchange").setEventNames(new String[] { "beforeselectionchange" }),
             new ComponentAttribute("onready").setEventNames(new String[] { "ready" })));
 
     private void encodeEmptyFooterCell(FacesContext context, ResponseWriter writer, UIComponent columnboolean isLastColumnthrows IOException {
         if (column.isRendered()) {
             writer.startElement(HtmlConstants.TD_ELEM, column);
             if (!isLastColumn) {
                 writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, "rf-edt-td-" + column.getId(), null);
             }
             writer.startElement(HtmlConstants.DIV_ELEM, column);
             writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, "rf-edt-ftr-c-emp rf-edt-c-" + column.getId(), null);
             writer.endElement(HtmlConstants.DIV_ELEM);
             writer.endElement(HtmlConstants.TD_ELEM);
         }
     }
 
     private void encodeHeaderOrFooterCell(FacesContext context, ResponseWriter writer, UIComponent columnString facetNameboolean isLastColumn)
         throws IOException {
         if (column.isRendered()) {
 
             String classAttribute = facetName + "Class";
             boolean useBuiltInSort = "header".equals(facetName) && column instanceof AbstractColumn && ((AbstractColumncolumn).useBuiltInSort();
             writer.startElement(HtmlConstants.TD_ELEM, column);
             if (!isLastColumn) {
                 writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, "rf-edt-td-" + column.getId(), null);
             }
             if ("header".equals(facetName)) {
                 writer.startElement(HtmlConstants.DIV_ELEM, column);
                 writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, "rf-edt-rsz-cntr rf-edt-c-" + column.getId(), null);
                 writer.startElement(HtmlConstants.DIV_ELEM, column);
                 writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, "rf-edt-rsz"null);
                 writer.endElement(HtmlConstants.DIV_ELEM);
                 writer.endElement(HtmlConstants.DIV_ELEM);
             }
 
             writer.startElement(HtmlConstants.DIV_ELEM, column);
             writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, HtmlUtil.concatClasses("rf-edt-"
                 + getFacetClassName(facetName) + "-c""rf-edt-c-" + column.getId()), null);
             writer.startElement(HtmlConstants.DIV_ELEM, column);
             String columnHeaderClass = "rf-edt-" + getFacetClassName(facetName) + "-c-cnt";
             if (useBuiltInSort) {
                 columnHeaderClass = HtmlUtil.concatClassescolumnHeaderClass"rf-edt-c-srt");
             }
             columnHeaderClass = HtmlUtil.concatClassescolumnHeaderClasscolumn.getAttributes().get(classAttribute));
             writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, columnHeaderClassnull);
             UIComponent facet = column.getFacet(facetName);
             if (facet != null && facet.isRendered()) {
                 facet.encodeAll(context);
             }
 
             if ("header".equals(facetName) && column instanceof AbstractColumn && ((AbstractColumncolumn).useBuiltInSort()) {
                 writer.startElement(HtmlConstants.SPAN_ELEM, column);
                 String classAttr = "rf-edt-srt rf-edt-srt-btn ";
                 SortOrder sortOrder = (SortOrder) column.getAttributes().get("sortOrder");
                 if (sortOrder == null || sortOrder == SortOrder.unsorted) {
                     classAttr = classAttr + "rf-edt-srt-uns";
                 } else if (sortOrder == SortOrder.ascending) {
                     classAttr = classAttr + "rf-edt-srt-asc";
                 } else if (sortOrder == SortOrder.descending) {
                     classAttr = classAttr + "rf-edt-srt-des";
                 }
                 writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, classAttrnull);
                 writer.writeAttribute("data-columnid"column.getId(), null);
                 writer.endElement(HtmlConstants.SPAN_ELEM);
             }
 
             writer.endElement(HtmlConstants.DIV_ELEM);
             writer.endElement(HtmlConstants.DIV_ELEM);
             writer.endElement(HtmlConstants.TD_ELEM);
         }
     }
 
     private String getFacetClassName(String name) {
         if ("header".equals(name)) {
             return "hdr";
         } else if ("footer".equals(name)) {
             return "ftr";
         }
 
         throw new IllegalArgumentException(name);
     }
 
     private void encodeHeaderOrFooter(RendererState stateString facetNamethrows IOException {
         FacesContext context = state.getContext();
         ResponseWriter writer = context.getResponseWriter();
         UIDataTableBase table = state.getRow();
         boolean columnFacetPresent = table.isColumnFacetPresent(facetName);
         if (columnFacetPresent || "footer".equals(facetName)) {
             writer.startElement(HtmlConstants.DIV_ELEM, table);
             writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, "rf-edt-" + getFacetClassName(facetName), null);
             writer.startElement(HtmlConstants.TABLE_ELEMENT, table);
             writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, "rf-edt-tbl"null);
             writer.startElement(HtmlConstants.TBODY_ELEMENT, table);
             writer.startElement(HtmlConstants.TR_ELEMENT, table);
             String clientId = table.getClientId(context);
             for (state.startIterate(); state.hasNextPart();) {
                 Part part = state.nextPart();
                 PartName partName = part.getName();
                 Iterator<UIComponent> columns = part.getColumns().iterator();
                 if (columns.hasNext()) {
                     writer.startElement(HtmlConstants.TD_ELEM, table);
                     if (..equals(partName) && "footer".equals(facetName)) {
                         writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, "rf-edt-ftr-fzn"null);
                     }
                     writer.startElement(HtmlConstants.DIV_ELEM, table);
                     if (..equals(partName)) {
                         if ("header".equals(facetName)) {
                             writer.writeAttribute(HtmlConstants.ID_ATTRIBUTE, clientId + ":frozenHeader"null);
                         }
                     } else {
                         writer.writeAttribute(HtmlConstants.ID_ATTRIBUTE, clientId + ":" + facetNamenull);
                         writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, "rf-edt-cnt"
                             + ("footer".equals(facetName) ? " rf-edt-ftr-cnt" : ""), null);
                     }
 
                     String tableId = clientId + ":cf" + facetName.charAt(0) + partName.getId();
                     EncoderVariance encoderVariance = state.getEncoderVariance();
                     encoderVariance.encodeStartUpdate(contexttableId);
 
                     writer.startElement(HtmlConstants.TABLE_ELEMENT, table);
                     writer.writeAttribute(HtmlConstants.ID_ATTRIBUTE, tableIdnull);
                     writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, "rf-edt-tbl"null);
                     writer.startElement(HtmlConstants.TBODY_ELEMENT, table);
                     writer.startElement(HtmlConstants.TR_ELEMENT, table);
                     int columnNumber = 0;
                     boolean filterRowRequired = false;
                     int lastColumnNumber = part.getColumns().size() - 1;
                     while (columns.hasNext()) {
                         UIComponent column = columns.next();
                         if (!filterRowRequired && "header".equals(facetName) && column instanceof AbstractColumn && ((AbstractColumncolumn).useBuiltInFilter()) {
                             filterRowRequired = true;
                         }
                         if (columnFacetPresent) {
                             encodeHeaderOrFooterCell(contextwritercolumnfacetNamecolumnNumber == lastColumnNumber);
                         } else {
                             encodeEmptyFooterCell(contextwritercolumncolumnNumber == lastColumnNumber);
                         }
                         columnNumber++;
                     }
                     writer.endElement(HtmlConstants.TR_ELEMENT);
                     if (filterRowRequired) {  // filter row
                         writer.startElement(HtmlConstants.TR_ELEMENT, table);
                         columns = part.getColumns().iterator();
                         while (columns.hasNext()) {
                             UIComponent column = columns.next();
                             if (column.isRendered()) {
                                 writer.startElement(HtmlConstants.TD_ELEM, column);
                                 writer.startElement(HtmlConstants.DIV_ELEM, column);
                                 writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, "rf-edt-flt-c rf-edt-c-" + column.getId(), null);
                                 writer.startElement(HtmlConstants.DIV_ELEM, column);
                                 writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, "rf-edt-flt-cnt"null);
                                 if (column.getAttributes().get("filterField") != null &&  ! "custom".equals(column.getAttributes().get("filterType"))) {
                                     writer.startElement(HtmlConstants.INPUT_ELEM, column);
                                     writer.writeAttribute(HtmlConstants.ID_ATTRIBUTE, clientId + ":" + column.getId() + ":flt"null);
                                     writer.writeAttribute(HtmlConstants.NAME_ATTRIBUTE, clientId + ":" + column.getId() + ":flt"null);
                                     String inputClass = "rf-edt-flt-i";
                                     List<FacesMessage> messages = context.getMessageList(column.getClientId());
                                     if (! messages.isEmpty()) {
                                         inputClass += " rf-edt-flt-i-err";
                                         writer.writeAttribute("value"column.getAttributes().get("submittedFilterValue"), null);
                                     } else {
                                         writer.writeAttribute("value"column.getAttributes().get("filterValue"), null);
                                     }
                                     writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, inputClassnull);
                                     writer.writeAttribute("data-columnid"column.getId(), null);
                                     writer.endElement(HtmlConstants.INPUT_ELEM);
                                 }
                                 writer.endElement(HtmlConstants.DIV_ELEM);
                                 writer.endElement(HtmlConstants.DIV_ELEM);
                                 writer.endElement(HtmlConstants.TD_ELEM);
                             }
                         }
                         writer.endElement(HtmlConstants.TR_ELEMENT);
                     }
                     writer.endElement(HtmlConstants.TBODY_ELEMENT);
                     writer.endElement(HtmlConstants.TABLE_ELEMENT);
 
                     encoderVariance.encodeEndUpdate(context);
 
                     writer.endElement(HtmlConstants.DIV_ELEM);
 
                     writer.endElement(HtmlConstants.TD_ELEM);
                 }
             }
             writer.endElement(HtmlConstants.TR_ELEMENT);
             // the start of the scroller
             if ("footer".equals(facetName)) {
                 int frozenColumns = 0;
                 int scrollingColumns = 0;
                 for (state.startIterate(); state.hasNextPart();) {
                     Part part = state.nextPart();
                     PartName partName = part.getName();
                     Iterator<UIComponent> columns = part.getColumns().iterator();
                     if (columns.hasNext()) {
                         if (..equals(partName)) {
                             frozenColumns += 1;
                         } else {
                             scrollingColumns += 1;
                         }
                     }
                 }
                 writer.startElement(HtmlConstants.TR_ELEMENT, table);
                 if (frozenColumns > 0) {
                     writer.startElement(HtmlConstants.TD_ELEM, table);
                     writer.writeAttribute(HtmlConstants.COLSPAN_ATTRIBUTE, frozenColumnsnull);
                     writer.endElement(HtmlConstants.TD_ELEM);
                 }
                 if (scrollingColumns > 0) {
                     writer.startElement(HtmlConstants.TD_ELEM, table);
                     writer.writeAttribute(HtmlConstants.COLSPAN_ATTRIBUTE, scrollingColumnsnull);
                     writer.startElement(HtmlConstants.DIV_ELEM, table);
                     writer.writeAttribute(HtmlConstants.ID_ATTRIBUTE, clientId + ":scrl"null);
                     writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, "rf-edt-scrl"null);
                     writer.startElement(HtmlConstants.DIV_ELEM, table);
                     writer.writeAttribute(HtmlConstants.ID_ATTRIBUTE, clientId + ":scrl-cnt"null);
                     writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, "rf-edt-scrl-cnt"null);
                     writer.endElement(HtmlConstants.DIV_ELEM);
                     writer.endElement(HtmlConstants.DIV_ELEM);
                     writer.endElement(HtmlConstants.TD_ELEM);
                 }
                 writer.endElement(HtmlConstants.TR_ELEMENT);
             }
             // the end of the scroller
             writer.endElement(HtmlConstants.TBODY_ELEMENT);
             writer.endElement(HtmlConstants.TABLE_ELEMENT);
             writer.endElement(HtmlConstants.DIV_ELEM);
         }
     }
 
     public void encodeHeader(RendererState statethrows IOException {
         FacesContext context = state.getContext();
         ResponseWriter writer = context.getResponseWriter();
         UIDataTableBase table = state.getRow();
 
         UIComponent header = table.getFacet("header");
         if (header != null && header.isRendered()) {
             String elementId = table.getClientId(context) + ":tfh";
 
             EncoderVariance encoderVariance = state.getEncoderVariance();
             encoderVariance.encodeStartUpdate(contextelementId);
 
             writer.startElement(HtmlConstants.DIV_ELEM, table);
             writer.writeAttribute(HtmlConstants.ID_ATTRIBUTE, elementIdnull);
             writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE,
                 HtmlUtil.concatClasses("rf-edt-tbl-hdr"table.getHeaderClass()), null);
             header.encodeAll(context);
             writer.endElement(HtmlConstants.DIV_ELEM);
 
             encoderVariance.encodeEndUpdate(context);
         }
 
         encodeHeaderOrFooter(state"header");
     }
 
     public void encodeBody(RendererState statethrows IOException {
         FacesContext context = state.getContext();
         ResponseWriter writer = context.getResponseWriter();
         UIDataTableBase table = state.getRow();
         String clientId = table.getClientId(context);
         String tableBodyId = clientId + ":b";
         EncoderVariance encoderVariance = state.getEncoderVariance();
         encoderVariance.encodeStartUpdate(contexttableBodyId);
         writer.startElement(HtmlConstants.DIV_ELEM, table);
         writer.writeAttribute(HtmlConstants.ID_ATTRIBUTE, tableBodyIdnull);
         writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, "rf-edt-b"null);
         if (table.getRowCount() == 0) {
             UIComponent facet = table.getFacet("noData");
             writer.startElement(HtmlConstants.DIV_ELEM, table);
             writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, "rf-edt-ndt"null);
             if (facet != null && facet.isRendered()) {
                 facet.encodeAll(context);
             } else {
                 Object noDataLabel = table.getAttributes().get("noDataLabel");
                 if (noDataLabel != null) {
                     writer.writeText(noDataLabel"noDataLabel");
                 }
             }
             writer.endElement(HtmlConstants.DIV_ELEM);
         } else {
             table.getAttributes().put("clientFirst", 0);
             writer.startElement(HtmlConstants.DIV_ELEM, table);
             writer.startElement(HtmlConstants.DIV_ELEM, table);
             writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, "rf-edt-spcr"null);
             writer.endElement(HtmlConstants.DIV_ELEM);
             writer.startElement(HtmlConstants.TABLE_ELEMENT, table);
             writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, "rf-edt-tbl"null);
             writer.startElement(HtmlConstants.TBODY_ELEMENT, table);
             writer.startElement(HtmlConstants.TR_ELEMENT, table);
             for (state.startIterate(); state.hasNextPart();) {
                 writer.startElement(HtmlConstants.TD_ELEM, table);
                 writer.startElement(HtmlConstants.DIV_ELEM, table);
                 PartName partName = state.nextPart().getName();
                 if (..equals(partName)) {
                     writer.writeAttribute(HtmlConstants.ID_ATTRIBUTE, clientId + ":body"null);
                     writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, "rf-edt-cnt"null);
                 }
                 String targetId = clientId + ":tbt" + partName.getId();
                 writer.startElement(HtmlConstants.TABLE_ELEMENT, table);
                 writer.writeAttribute(HtmlConstants.ID_ATTRIBUTE, targetIdnull);
                 writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, "rf-edt-tbl"null);
                 writer.startElement(HtmlConstants.TBODY_ELEMENT, table);
                 writer.writeAttribute(HtmlConstants.ID_ATTRIBUTE, clientId + ":tb" + partName.getId(), null);
                 encodeRows(contextstate);
                 writer.endElement(HtmlConstants.TBODY_ELEMENT);
                 writer.endElement(HtmlConstants.TABLE_ELEMENT);
 
                 writer.endElement(HtmlConstants.DIV_ELEM);
                 writer.endElement(HtmlConstants.TD_ELEM);
             }
             writer.endElement(HtmlConstants.TR_ELEMENT);
             writer.endElement(HtmlConstants.TBODY_ELEMENT);
             writer.endElement(HtmlConstants.TABLE_ELEMENT);
             writer.endElement(HtmlConstants.DIV_ELEM);
         }
         writer.endElement(HtmlConstants.DIV_ELEM);
         encoderVariance.encodeEndUpdate(context);
     }
 
     public void encodeFooter(RendererState statethrows IOException {
         FacesContext context = state.getContext();
         ResponseWriter writer = context.getResponseWriter();
         UIDataTableBase table = state.getRow();
 
         encodeHeaderOrFooter(state"footer");
 
         UIComponent footer = table.getFacet("footer");
         if (footer != null && footer.isRendered()) {
             String elementId = table.getClientId(context) + ":tff";
 
             EncoderVariance encoderVariance = state.getEncoderVariance();
             encoderVariance.encodeStartUpdate(contextelementId);
 
             writer.startElement(HtmlConstants.DIV_ELEM, table);
             writer.writeAttribute(HtmlConstants.ID_ATTRIBUTE, elementIdnull);
             writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE,
                 HtmlUtil.concatClasses("rf-edt-tbl-ftr"table.getFooterClass()), null);
             footer.encodeAll(context);
             writer.endElement(HtmlConstants.DIV_ELEM);
 
             encoderVariance.encodeEndUpdate(context);
         }
     }
 
     @Override
     protected Class<? extends UIComponent> getComponentClass() {
         return AbstractExtendedDataTable.class;
     }
 
     public void encodeMetaComponent(FacesContext context, UIComponent componentString metaComponentIdthrows IOException {
         AbstractExtendedDataTable table = (AbstractExtendedDataTablecomponent;
         if (..equals(metaComponentId)) {
             final PartialResponseWriter writer = context.getPartialViewContext().getPartialResponseWriter();
             int clientFirst = table.getClientFirst();
             Integer oldClientFirst = (Integertable.getAttributes().remove(.);
             if (oldClientFirst == null) {
                 oldClientFirst = clientFirst;
             }
             int clientRows = ((SequenceRange) table.getComponentState().getRange()).getRows();
             int difference = clientFirst - oldClientFirst;
             SequenceRange addRange = null;
             SequenceRange removeRange = null;
             if (Math.abs(difference) >= clientRows) {
                 difference = 0;
                 addRange = new SequenceRange(clientFirstclientRows);
                 removeRange = new SequenceRange(oldClientFirstclientRows);
             } else if (difference < 0) {
                 clientFirst += table.getFirst();
                 addRange = new SequenceRange(clientFirst, -difference);
                 removeRange = new SequenceRange(clientFirst + clientRows, -difference);
             } else if (difference > 0) {
                 oldClientFirst += table.getFirst();
                 removeRange = new SequenceRange(oldClientFirstdifference);
                 int last = oldClientFirst + clientRows;
                 addRange = new SequenceRange(lastdifference);
             }
             if (addRange != null) {
                 Object key = table.getRowKey();
                 table.captureOrigValue(context);
                 table.setRowKey(contextnull);
                 final RendererState state = createRowHolder(contexttablenull);
                 state.setCurrentRow(addRange.getFirstRow());
                 String clientId = table.getClientId(context);
                 // TODO 1. Encode fixed children
                 for (state.startIterate(); state.hasNextPart();) {
                     String partId = state.nextPart().getName().getId();
                     final List<Stringids = new LinkedList<String>();
                     table.walk(contextnew DataVisitor() {
                         public DataVisitResult process(FacesContext contextObject rowKeyObject argument) {
                             UIDataTableBase dataTable = state.getRow();
                             dataTable.setRowKey(contextrowKey);
                             ids.add(dataTable.getContainerClientId(context) + ":" + state.getPart().getName().getId());
                             return DataVisitResult.CONTINUE;
                         }
                     }, removeRangenull);
                     table.walk(contextnew DataVisitor() {
                         public DataVisitResult process(FacesContext contextObject rowKeyObject argument) {
                             UIDataTableBase dataTable = state.getRow();
                             dataTable.setRowKey(contextrowKey);
                             HashMap<StringStringattributes = new HashMap<StringString>(1);
                             String id = dataTable.getContainerClientId(context) + ":" + state.getPart().getName().getId();
                             attributes.put("id"id);
                             try {
                                 writer.updateAttributes(ids.remove(0), attributes);
                                 writer.startUpdate(id);
                                 encodeRow(writercontextstate);
                                 writer.endUpdate();
                             } catch (IOException e) {
                                 throw new FacesException(e);
                             }
                             RowHolderBase holder = (RowHolderBaseargument;
                             holder.nextRow();
                             return DataVisitResult.CONTINUE;
                         }
                     }, addRangestate);
                     writer.startEval();
                     if (difference < 0) {
                         difference += clientRows;
                     }
 
                     // TODO nick - move this to external JavaScript file
                     writer.write("var richTBody = document.getElementById('" + clientId + ":tb" + partId + "');");
                     writer.write("var richRows = richTBody.rows;");
                     writer.write("for (var i = 0; i < " + difference
                         + "; i++ ) richTBody.appendChild(richTBody.removeChild(richRows[0]));");
                     writer.endEval();
                 }
                 writer.startUpdate(clientId + ":si");
                 encodeSelectionInput(writercontextcomponent);
                 writer.endUpdate();
                 writer.startEval();
                 writer.write("jQuery(" + ScriptUtils.toScript('#' + ScriptUtils.escapeCSSMetachars(clientId))
                     + ").triggerHandler('rich:onajaxcomplete', {first: " + table.getClientFirst() + "});");
                 writer.endEval();
                 table.setRowKey(contextkey);
                 table.restoreOrigValue(context);
             }
         } else {
 
             ResponseWriter initialWriter = context.getResponseWriter();
             assert !(initialWriter instanceof OnOffResponseWriter);
 
             try {
                 context.setResponseWriter(new OnOffResponseWriter(initialWriter));
 
                 RendererState state = createRowHolder(contextcomponentnull);
                 state.setEncoderVariance(.);
 
                 PartialResponseWriter writer = context.getPartialViewContext().getPartialResponseWriter();
 
                 if (..equals(metaComponentId)) {
                     encodeHeader(state);
                     writer.startEval();
                     writer.write("jQuery("
                         + ScriptUtils.toScript('#' + ScriptUtils.escapeCSSMetachars(table.getClientId(context)))
                         + ").triggerHandler('rich:onajaxcomplete', {reinitializeHeader: true});");
                     writer.endEval();
                 } else if (..equals(metaComponentId)) {
                     encodeFooter(state);
                 } else if (..equals(metaComponentId)) {
                     encodeBody(state);
                     String clientId = table.getClientId(context);
                     writer.startUpdate(clientId + ":si");
                     encodeSelectionInput(writercontextcomponent);
                     writer.endUpdate();
                     writer.startEval();
                     writer.write("jQuery(" + ScriptUtils.toScript('#' + ScriptUtils.escapeCSSMetachars(clientId))
                         + ").triggerHandler('rich:onajaxcomplete', {first: " + table.getClientFirst() + ", rowCount: "
                         + getRowCount(component) + ", reinitializeBody: true});");
                     writer.endEval();
                 } else {
                     throw new IllegalArgumentException("Unsupported metaComponentIdentifier: " + metaComponentId);
                 }
             } finally {
                 context.setResponseWriter(initialWriter);
             }
         }
     }
 
     public void decodeMetaComponent(FacesContext context, UIComponent componentString metaComponentId) {
         throw new UnsupportedOperationException();
     }
 
     protected void doEncodeBegin(ResponseWriter writer, FacesContext context, UIComponent componentthrows IOException {
         String savedTableState = (Stringcomponent.getAttributes().get("tableState");
         if (savedTableState != null && ! savedTableState.isEmpty()) { // retrieve table state
             ExtendedDataTableState tableState = new ExtendedDataTableState(savedTableState);
             consumeTableState(context, (UIDataTableBasecomponenttableState);
         }
 
         Map<StringObjectattributes = component.getAttributes();
         writer.startElement(HtmlConstants.DIV_ELEM, component);
         writer.writeAttribute(HtmlConstants.ID_ATTRIBUTE, component.getClientId(context), null);
         writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE,
             HtmlUtil.concatClasses("rf-edt", (Stringattributes.get("styleClass")), null);
         renderAttribute(context, HtmlConstants.STYLE_ATTRIBUTE, attributes.get("style"));
     }
 
     public RendererState createRowHolder(FacesContext context, UIComponent componentObject[] options) {
         return new RendererState(context, (UIDataTableBasecomponent);
     }
 
     protected void doEncodeChildren(ResponseWriter writer, FacesContext context, UIComponent componentthrows IOException {
 
         UIDataTableBase table = (UIDataTableBasecomponent;
         Object key = table.getRowKey();
         table.captureOrigValue(context);
         table.setRowKey(contextnull);
         RendererState state = createRowHolder(contexttablenull);
         encodeStyle(state);
         encodeHeader(state);
         encodeBody(state);
         encodeFooter(state);
         table.setRowKey(contextkey);
         table.restoreOrigValue(context);
     }
 
     protected void doEncodeEnd(ResponseWriter writer, FacesContext context, UIComponent componentthrows IOException {
         writer.startElement(HtmlConstants.TABLE_ELEMENT, component);
         String clientId = component.getClientId(context);
         writer.writeAttribute(HtmlConstants.ID_ATTRIBUTE, clientId + ":r"null);
         writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, "rf-edt-rord rf-edt-tbl"null);
         writer.startElement(HtmlConstants.TR_ELEMENT, component);
         writer.startElement(HtmlConstants.TH_ELEM, component);
         writer.write("&#160;");
         writer.endElement(HtmlConstants.TH_ELEM);
         writer.endElement(HtmlConstants.TR_ELEMENT);
         for (int i = 0; i < 6; i++) {
             writer.startElement(HtmlConstants.TR_ELEMENT, component);
             writer.startElement(HtmlConstants.TD_ELEM, component);
             writer.write("&#160;");
             writer.endElement(HtmlConstants.TD_ELEM);
             writer.endElement(HtmlConstants.TR_ELEMENT);
         }
         writer.endElement(HtmlConstants.TABLE_ELEMENT);
         writer.startElement(HtmlConstants.DIV_ELEM, component);
         writer.writeAttribute(HtmlConstants.ID_ATTRIBUTE, clientId + ":d"null);
         writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, "rf-edt-rsz-mkr"null);
         writer.endElement(HtmlConstants.DIV_ELEM);
         writer.startElement(HtmlConstants.DIV_ELEM, component);
         writer.writeAttribute(HtmlConstants.ID_ATTRIBUTE, clientId + ":rm"null);
         writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, "rf-edt-rord-mkr"null);
         writer.endElement(HtmlConstants.DIV_ELEM);
         writer.startElement(HtmlConstants.INPUT_ELEM, component);
         writer.writeAttribute(HtmlConstants.ID_ATTRIBUTE, clientId + ":wi"null);
         writer.writeAttribute(HtmlConstants.NAME_ATTRIBUTE, clientId + ":wi"null);
         writer.writeAttribute(HtmlConstants.TYPE_ATTR, HtmlConstants.INPUT_TYPE_HIDDEN, null);
         writer.endElement(HtmlConstants.INPUT_ELEM);
         encodeSelectionInput(writercontextcomponent);
         AjaxFunction ajaxFunction = buildAjaxFunction(contextcomponent);
         ajaxFunction.getOptions().setClientParameters();
 
         Map<StringObjectattributes = component.getAttributes();
         Map<StringObjectoptions = new HashMap<StringObject>();
         addToScriptHash(options"selectionMode"attributes.get("selectionMode"), SelectionMode.multiple);
         addToScriptHash(options"onbeforeselectionchange",
             RenderKitUtils.getAttributeAndBehaviorsValue(contextcomponent.get("onbeforeselectionchange")),
             null.);
         addToScriptHash(options"onselectionchange",
             RenderKitUtils.getAttributeAndBehaviorsValue(contextcomponent.get("onselectionchange")),
             null.);
         addToScriptHash(options"onready",
             RenderKitUtils.getAttributeAndBehaviorsValue(contextcomponent.get("onready")),
             null.);
         StringBuilder builder = new StringBuilder("new RichFaces.ui.ExtendedDataTable('");
         builder.append(clientId).append("', ").append(getRowCount(component)).append(", function(event, clientParams) {")
             .append(ajaxFunction.toScript()).append(";}");
         if (!options.isEmpty()) {
             builder.append(",").append(ScriptUtils.toScript(options));
         }
         builder.append(");");
         getUtils().writeScript(contextcomponentbuilder.toString());
         writer.endElement(HtmlConstants.DIV_ELEM);
     }
 
     private int getRowCount(UIComponent component) {
         UIDataTableBase table = (UIDataTableBasecomponent;
         int rows = table.getRows();
         int rowCount = table.getRowCount() - table.getFirst();
         if (rows > 0) {
             rows = Math.min(rowsrowCount);
         } else {
             rows = rowCount;
         }
 
         return rows;
     }
 
     private void encodeStyle(RendererState statethrows IOException {
         FacesContext context = state.getContext();
         ResponseWriter writer = context.getResponseWriter();
         UIDataTableBase table = state.getRow();
 
         PartialViewContext pvc = context.getPartialViewContext();
         if (!pvc.isAjaxRequest()) {
             writer.startElement("style"table);
             writer.writeAttribute(HtmlConstants.TYPE_ATTR, "text/css"null);
             writer.writeText(getCSSText(contexttable), null);
             writer.endElement("style");
         } else {
             writer.startElement(HtmlConstants.SCRIPT_ELEM, table);
             writer.writeAttribute(HtmlConstants.TYPE_ATTR, HtmlConstants.TEXT_JAVASCRIPT_TYPE, null);
 
             String cssText = getCSSText(contexttable);
             JSFunction function = new JSFunction("RichFaces.utils.addCSSText"cssTexttable.getClientId(context) + ":st");
 
             writer.writeText(function.toScript(), null);
 
             writer.endElement(HtmlConstants.SCRIPT_ELEM);
         }
     }
 
     protected String getCSSText(FacesContext contextUIDataTableBase tablethrows IOException {
         StringBuilder sb = new StringBuilder();
         String tableLocator = "div.rf-edt[id=\"" + table.getClientId() + "\"]";
 
         sb.append("div.rf-edt-cnt { width: 100%; }"); // TODO getNormalizedId(context, state.getGrid())
 
         Iterator<UIComponent> columns = table.columns();
         while (columns.hasNext()) {
             UIComponent column = columns.next();
             String id = column.getId();
             if (id == null) {
                 column.getClientId(context); // hack initialize id
                 id = column.getId();
             }
             String width = getColumnWidth(column);
             sb.append(tableLocator);
             sb.append(" .rf-edt-c-" + id + " {"); // TODO getNormalizedId(context,
             sb.append("width: " + width + ";");
             sb.append("}");
 
             sb.append(tableLocator);
             sb.append(" .rf-edt-td-" + id + " {"); // TODO getNormalizedId(context,
             sb.append("width: " + width + ";");
             sb.append("}");
         }
 
         return sb.toString();
     }
 
     public void encodeRow(ResponseWriter writer, FacesContext facesContextRowHolderBase rowHolderthrows IOException {
         RendererState state = (RendererStaterowHolder;
         AbstractExtendedDataTable table = (AbstractExtendedDataTablestate.getRow();
         writer.startElement(HtmlConstants.TR_ELEMENT, table);
 
         if (rowHolder.getRow() instanceof UIDataTableBase) {
             renderRowHandlers(facesContext, (UIDataTableBaserowHolder.getRow());
         }
 
         String rowClass = getRowClass(rowHolder);
 
         StringBuilder builder = new StringBuilder();
         Collection<Objectselection = table.getSelection();
         if (selection != null && selection.contains(table.getRowKey())) {
             builder.append("rf-edt-r-sel");
         }
         if (table.getRowKey().equals(table.getAttributes().get("activeRowKey"))) {
             if (builder.length() > 0) {
                 builder.append(' ');
             }
             builder.append("rf-edt-r-act");
         }
         if (table.getRowKey().equals(table.getAttributes().get("shiftRowKey"))) {
             if (builder.length() > 0) {
                 builder.append(' ');
             }
             builder.append("rf-edt-r-sht");
         }
         rowClass = concatClasses(builder.toString(), rowClass);
         if (rowClass.length() > 0) {
             writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, rowClassnull);
         }
         Iterator<UIComponent> columns = null;
         Part part = state.getPart();
         writer.writeAttribute(HtmlConstants.ID_ATTRIBUTE, table.getContainerClientId(facesContext) + ":"
             + part.getName().getId(), null);
         columns = part.getColumns().iterator();
         int columnNumber = 0;
         int lastColumnNumber = part.getColumns().size() - 1;
         while (columns.hasNext()) {
             UIComponent column = (UIComponent) columns.next();
             if (column.isRendered()) {
                 writer.startElement(HtmlConstants.TD_ELEM, table);
                 String columnClass = "";
                 if (columnNumber != lastColumnNumber) {
                     columnClass = "rf-edt-td-" + column.getId();
                 }
                 columnClass = concatClasses(
                         columnClass,
                         getColumnClass(rowHoldercolumnNumber),
                         column.getAttributes().get(HtmlConstants.STYLE_CLASS_ATTR));
                 if (!"".equals(columnClass)) {
                     writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, columnClassnull);
                 }
 
                 String columnStyle = (Stringcolumn.getAttributes().get(HtmlConstants.STYLE_ATTRIBUTE);
                 if (!"".equals(columnStyle)) {
                     writer.writeAttribute(HtmlConstants.STYLE_ATTRIBUTE, columnStylenull);
                 }
 
                 columnNumber++;
 
                 writer.startElement(HtmlConstants.DIV_ELEM, table);
                 writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, "rf-edt-c rf-edt-c-" + column.getId(), null);
                 writer.startElement(HtmlConstants.DIV_ELEM, column);
                 writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, "rf-edt-c-cnt"null);
                 renderChildren(facesContextcolumn);
                 writer.endElement(HtmlConstants.DIV_ELEM);
                 writer.endElement(HtmlConstants.DIV_ELEM);
                 writer.endElement(HtmlConstants.TD_ELEM);
             }
         }
         writer.endElement(HtmlConstants.TR_ELEMENT);
     }
 
     @Override
     protected void doDecode(FacesContext context, UIComponent component) {
         super.doDecode(contextcomponent);
         Map<StringStringmap = context.getExternalContext().getRequestParameterMap();
         String clientId = component.getClientId(context);
         updateWidthOfColumns(contextcomponentmap.get(clientId + ":wi"));
         if (map.get(clientId) != null) {
             updateColumnsOrder(contextcomponentmap.get("rich:columnsOrder"));
         }
         if (map.get(clientId) != null) {
             updateClientFirst(contextcomponentmap.get("rich:clientFirst"));
         }
         decodeSortingFiltering(contextcomponent);
 
         if (component.getAttributes().get("tableState") != null) {
             ExtendedDataTableState tableState = new ExtendedDataTableState((UIDataTableBasecomponent);
             updateAttribute(contextcomponent"tableState"tableState.toString());
         }
     }
 
     private void updateWidthOfColumns(FacesContext context, UIComponent componentString widthString) {
         if (widthString != null && widthString.length() > 0) {
             String[] widthArray = widthString.split(",");
             for (int i = 0; i < widthArray.lengthi++) {
                 String[] widthEntry = widthArray[i].split(":");
                 UIComponent column = component.findComponent(widthEntry[0]);
                 updateAttribute(contextcolumn"width"widthEntry[1]);
             }
         }
     }
 
     private void updateColumnsOrder(FacesContext context, UIComponent componentString columnsOrderString) {
         if (columnsOrderString != null && columnsOrderString.length() > 0) {
             String[] columnsOrder = columnsOrderString.split(",");
             updateAttribute(contextcomponent"columnsOrder"columnsOrder);
             context.getPartialViewContext().getRenderIds().add(component.getClientId(context)); // TODO Use partial re-rendering here.
         }
     }
 
     private void updateClientFirst(FacesContext context, UIComponent componentString clientFirst) {
         if (