View Javadoc
1   /*
2    * Copyright (c) 2011-2024 PrimeFaces Extensions
3    *
4    *  Permission is hereby granted, free of charge, to any person obtaining a copy
5    *  of this software and associated documentation files (the "Software"), to deal
6    *  in the Software without restriction, including without limitation the rights
7    *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    *  copies of the Software, and to permit persons to whom the Software is
9    *  furnished to do so, subject to the following conditions:
10   *
11   *  The above copyright notice and this permission notice shall be included in
12   *  all copies or substantial portions of the Software.
13   *
14   *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20   *  THE SOFTWARE.
21   */
22  package org.primefaces.extensions.component.fluidgrid;
23  
24  import java.io.IOException;
25  import java.util.Collection;
26  
27  import javax.faces.FacesException;
28  import javax.faces.component.UIComponent;
29  import javax.faces.context.FacesContext;
30  import javax.faces.context.ResponseWriter;
31  
32  import org.primefaces.expression.SearchExpressionUtils;
33  import org.primefaces.extensions.model.fluidgrid.FluidGridItem;
34  import org.primefaces.extensions.util.Attrs;
35  import org.primefaces.renderkit.CoreRenderer;
36  import org.primefaces.util.WidgetBuilder;
37  
38  /**
39   * Renderer for {@link FluidGrid} component.
40   *
41   * @author Oleg Varaksin / last modified by Melloware
42   * @since 0.5
43   */
44  public class FluidGridRenderer extends CoreRenderer {
45  
46      private static final String GRID_CLASS = "pe-fluidgrid";
47      private static final String GRID_ITEM_CLASS = "pe-fluidgrid-item";
48  
49      private static final String LIST_ROLE = "list";
50      private static final String LIST_ITEM_ROLE = "listitem";
51  
52      @Override
53      public void decode(final FacesContext context, final UIComponent component) {
54          decodeBehaviors(context, component);
55      }
56  
57      @Override
58      public void encodeEnd(final FacesContext fc, final UIComponent component) throws IOException {
59          final FluidGrid fluidGrid = (FluidGrid) component;
60  
61          encodeMarkup(fc, fluidGrid);
62          encodeScript(fc, fluidGrid);
63      }
64  
65      protected void encodeMarkup(final FacesContext fc, final FluidGrid fluidGrid) throws IOException {
66          final ResponseWriter writer = fc.getResponseWriter();
67          final String clientId = fluidGrid.getClientId(fc);
68          final String styleClass = getStyleClassBuilder(fc)
69                      .add(GRID_CLASS)
70                      .add(fluidGrid.getStyleClass())
71                      .build();
72  
73          writer.startElement("div", fluidGrid);
74          writer.writeAttribute("id", clientId, "id");
75          writer.writeAttribute(Attrs.CLASS, styleClass, "styleClass");
76          if (fluidGrid.getStyle() != null) {
77              writer.writeAttribute(Attrs.STYLE, fluidGrid.getStyle(), Attrs.STYLE);
78          }
79  
80          writer.writeAttribute("role", LIST_ROLE, null);
81  
82          if (fluidGrid.getVar() != null) {
83              // dynamic items
84              final Object value = fluidGrid.getValue();
85              if (value != null) {
86                  if (!(value instanceof Collection<?>)) {
87                      throw new FacesException("Value in FluidGrid must be of type Collection / List");
88                  }
89  
90                  for (final UIComponent kid : fluidGrid.getChildren()) {
91                      if (kid.isRendered() && !(kid instanceof UIFluidGridItem)) {
92                          // first render children like stamped elements, etc.
93                          renderChild(fc, kid);
94                      }
95                  }
96  
97                  final Collection<FluidGridItem> col = (Collection<FluidGridItem>) value;
98                  for (final FluidGridItem fluidGridItem : col) {
99                      // find ui item by type
100                     final UIFluidGridItem uiItem = fluidGrid.getItem(fluidGridItem.getType());
101 
102                     if (uiItem.isRendered()) {
103                         // set data in request scope
104                         fluidGrid.setData(fluidGridItem);
105 
106                         // render item
107                         renderItem(fc, writer, fluidGrid, uiItem);
108                     }
109                 }
110             }
111         }
112         else {
113             // static items
114             for (final UIComponent kid : fluidGrid.getChildren()) {
115                 if (kid.isRendered()) {
116                     if (kid instanceof UIFluidGridItem) {
117                         // render item
118                         renderItem(fc, writer, fluidGrid, (UIFluidGridItem) kid);
119                     }
120                     else {
121                         // render a child like stamped element, etc.
122                         renderChild(fc, kid);
123                     }
124                 }
125             }
126         }
127 
128         writer.endElement("div");
129     }
130 
131     protected void encodeScript(final FacesContext fc, final FluidGrid fluidGrid) throws IOException {
132         final WidgetBuilder wb = getWidgetBuilder(fc);
133         wb.init("ExtFluidGrid", fluidGrid);
134         wb.append(",opts:{");
135         wb.append("isFitWidth:" + fluidGrid.isFitWidth());
136         wb.append(",isOriginLeft:" + fluidGrid.isOriginLeft());
137         wb.append(",isOriginTop:" + fluidGrid.isOriginTop());
138         wb.append(",isResizeBound:" + fluidGrid.isResizeBound());
139         wb.append(",hasImages:" + fluidGrid.isHasImages());
140 
141         if (fluidGrid.gethGutter() != 0) {
142             wb.append(",gutter:" + fluidGrid.gethGutter());
143         }
144 
145         final String stamp = SearchExpressionUtils.resolveClientIdsForClientSide(fc, fluidGrid, fluidGrid.getStamp());
146         if (stamp != null) {
147             wb.append(",stamp:'" + stamp + "'");
148         }
149 
150         if (fluidGrid.getTransitionDuration() != null) {
151             wb.append(",transitionDuration:'" + fluidGrid.getTransitionDuration() + "'");
152         }
153         else {
154             wb.append(",transitionDuration:0");
155         }
156 
157         wb.append("}");
158 
159         encodeClientBehaviors(fc, fluidGrid);
160         wb.finish();
161     }
162 
163     protected void renderItem(final FacesContext fc, final ResponseWriter writer, final FluidGrid fluidGrid,
164                 final UIFluidGridItem uiItem)
165                 throws IOException {
166         writer.startElement("div", null);
167 
168         if (uiItem.getStyleClass() != null) {
169             writer.writeAttribute(Attrs.CLASS, GRID_ITEM_CLASS + " " + uiItem.getStyleClass(), null);
170         }
171         else {
172             writer.writeAttribute(Attrs.CLASS, GRID_ITEM_CLASS, null);
173         }
174 
175         if (fluidGrid.getvGutter() != 0) {
176             writer.writeAttribute(Attrs.STYLE, "margin-bottom: " + fluidGrid.getvGutter() + "px", null);
177         }
178 
179         writer.writeAttribute("role", LIST_ITEM_ROLE, null);
180 
181         // encode content of pe:fluidGridItem
182         uiItem.encodeAll(fc);
183 
184         writer.endElement("div");
185     }
186 
187     @Override
188     public void encodeChildren(final FacesContext context, final UIComponent component) {
189         // Rendering happens on encodeEnd
190     }
191 
192     @Override
193     public boolean getRendersChildren() {
194         return true;
195     }
196 }