View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.myfaces.tobago.internal.renderkit.renderer;
21  
22  import org.apache.myfaces.tobago.context.Markup;
23  import org.apache.myfaces.tobago.internal.component.AbstractUISelectManyShuttle;
24  import org.apache.myfaces.tobago.internal.util.HtmlRendererUtils;
25  import org.apache.myfaces.tobago.internal.util.SelectItemUtils;
26  import org.apache.myfaces.tobago.renderkit.css.BootstrapClass;
27  import org.apache.myfaces.tobago.renderkit.css.Icons;
28  import org.apache.myfaces.tobago.renderkit.css.TobagoClass;
29  import org.apache.myfaces.tobago.renderkit.html.HtmlAttributes;
30  import org.apache.myfaces.tobago.renderkit.html.HtmlButtonTypes;
31  import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
32  import org.apache.myfaces.tobago.util.ComponentUtils;
33  import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
34  
35  import javax.faces.component.UIComponent;
36  import javax.faces.context.FacesContext;
37  import javax.faces.model.SelectItem;
38  import java.io.IOException;
39  import java.util.List;
40  
41  public class SelectManyShuttleRenderer<T extends AbstractUISelectManyShuttle> extends SelectManyRendererBase<T> {
42  
43    @Override
44    public HtmlElements getComponentTag() {
45      return HtmlElements.TOBAGO_SELECT_MANY_SHUTTLE;
46    }
47  
48    @Override
49    public void encodeBeginField(final FacesContext facesContext, final T component) throws IOException {
50  
51      final TobagoResponseWriter writer = getResponseWriter(facesContext);
52      final String clientId = component.getClientId(facesContext);
53      final Markup markup = component.getMarkup();
54  
55      writer.startElement(HtmlElements.DIV);
56      writer.writeClassAttribute(
57          TobagoClass.SELECT_MANY_SHUTTLE,
58          TobagoClass.SELECT_MANY_SHUTTLE.createMarkup(markup),
59          component.getCustomClass(),
60          markup != null && markup.contains(Markup.SPREAD) ? TobagoClass.SPREAD : null);
61      HtmlRendererUtils.writeDataAttributes(facesContext, writer, component);
62      final String title = HtmlRendererUtils.getTitleFromTipAndMessages(facesContext, component);
63      if (title != null) {
64        writer.writeAttribute(HtmlAttributes.TITLE, title, true);
65      }
66  //    final boolean hasLabel = component.hasLabel(); // XXX is needed?
67      final List<SelectItem> items = SelectItemUtils.getItemList(facesContext, component);
68      final boolean disabled = !items.iterator().hasNext() || component.isDisabled();
69      final boolean readonly = component.isReadonly();
70  
71      final String unselectedLabel = component.getUnselectedLabel();
72      if (unselectedLabel != null) {
73        writer.startElement(HtmlElements.DIV);
74        writer.writeClassAttribute(TobagoClass.SELECT_MANY_SHUTTLE__UNSELECTED_LABEL);
75        writer.write(unselectedLabel);
76        writer.endElement(HtmlElements.DIV);
77      }
78      Integer size = component.getSize();
79      size = Math.max(size != null ? size : items.size(), 2); // must be > 1
80  
81      writer.startElement(HtmlElements.SELECT);
82      final String unselectedClientId = clientId + ComponentUtils.SUB_SEPARATOR + "unselected";
83      writer.writeIdAttribute(unselectedClientId);
84      writer.writeAttribute(HtmlAttributes.DISABLED, disabled);
85      writer.writeAttribute(HtmlAttributes.READONLY, readonly);
86  
87      // TODO tabIndex
88      writer.writeAttribute(HtmlAttributes.TABINDEX, component.getTabIndex());
89  
90      writer.writeClassAttribute(TobagoClass.SELECT_MANY_SHUTTLE__UNSELECTED, BootstrapClass.FORM_CONTROL);
91  
92      writer.writeAttribute(HtmlAttributes.MULTIPLE, true);
93      writer.writeAttribute(HtmlAttributes.SIZE, size);
94  
95      final Object[] values = component.getSelectedValues();
96      final String[] submittedValues = getSubmittedValues(component);
97      HtmlRendererUtils.renderSelectItems(
98          component, TobagoClass.SELECT_MANY_SHUTTLE__OPTION, items, values, submittedValues, false, writer,
99          facesContext);
100 
101     writer.endElement(HtmlElements.SELECT);
102     writer.startElement(HtmlElements.DIV);
103     writer.writeClassAttribute(TobagoClass.SELECT_MANY_SHUTTLE__TOOL_BAR, BootstrapClass.BTN_GROUP_VERTICAL);
104     createButton(facesContext, component, writer, disabled | readonly,
105         Icons.ANGLE_DOUBLE_RIGHT, "addAll", TobagoClass.SELECT_MANY_SHUTTLE__ADD_ALL);
106     createButton(facesContext, component, writer, disabled | readonly,
107         Icons.ANGLE_RIGHT, "add", TobagoClass.SELECT_MANY_SHUTTLE__ADD);
108     createButton(facesContext, component, writer, disabled | readonly,
109         Icons.ANGLE_LEFT, "remove", TobagoClass.SELECT_MANY_SHUTTLE__REMOVE);
110     createButton(facesContext, component, writer, disabled | readonly,
111         Icons.ANGLE_DOUBLE_LEFT, "removeAll", TobagoClass.SELECT_MANY_SHUTTLE__REMOVE_ALL);
112     writer.endElement(HtmlElements.DIV);
113     final String selectedLabel = component.getSelectedLabel();
114     if (selectedLabel != null) {
115       writer.startElement(HtmlElements.DIV);
116       writer.writeClassAttribute(TobagoClass.SELECT_MANY_SHUTTLE__SELECTED_LABEL);
117       writer.write(selectedLabel);
118       writer.endElement(HtmlElements.DIV);
119     }
120 
121     writer.startElement(HtmlElements.SELECT);
122     final String selectedClientId = clientId + ComponentUtils.SUB_SEPARATOR + "selected";
123     writer.writeIdAttribute(selectedClientId);
124 
125     writer.writeAttribute(HtmlAttributes.DISABLED, disabled);
126     writer.writeAttribute(HtmlAttributes.READONLY, readonly);
127     writer.writeAttribute(HtmlAttributes.TABINDEX, component.getTabIndex());
128     writer.writeClassAttribute(
129         TobagoClass.SELECT_MANY_SHUTTLE__SELECTED,
130         BootstrapClass.borderColor(ComponentUtils.getMaximumSeverity(component)),
131         BootstrapClass.FORM_CONTROL);
132     writer.writeAttribute(HtmlAttributes.MULTIPLE, true);
133     writer.writeAttribute(HtmlAttributes.SIZE, size);
134     HtmlRendererUtils.renderSelectItems(
135         component, TobagoClass.SELECT_MANY_SHUTTLE__OPTION, items, values, submittedValues, true, writer,
136         facesContext);
137 
138     writer.endElement(HtmlElements.SELECT);
139     writer.startElement(HtmlElements.SELECT);
140     writer.writeClassAttribute(TobagoClass.SELECT_MANY_SHUTTLE__HIDDEN);
141     final String hiddenClientId = clientId + ComponentUtils.SUB_SEPARATOR + "hidden";
142     writer.writeIdAttribute(hiddenClientId);
143     writer.writeNameAttribute(clientId);
144     writer.writeAttribute(HtmlAttributes.MULTIPLE, true);
145     writer.writeAttribute(HtmlAttributes.REQUIRED, component.isRequired());
146     HtmlRendererUtils.renderSelectItems(
147         component, TobagoClass.SELECT_MANY_SHUTTLE__OPTION, items, values, submittedValues, writer, facesContext);
148     writer.endElement(HtmlElements.SELECT);
149   }
150 
151   @Override
152   public void encodeEndField(final FacesContext facesContext, final T component) throws IOException {
153     final TobagoResponseWriter writer = getResponseWriter(facesContext);
154     writer.endElement(HtmlElements.DIV);
155 
156     encodeBehavior(writer, facesContext, component);
157   }
158 
159   private void createButton(
160       final FacesContext context, final UIComponent component, final TobagoResponseWriter writer,
161       final boolean disabled, final Icons icon, final String sub, final TobagoClass cssClass) throws IOException {
162     writer.startElement(HtmlElements.BUTTON);
163     writer.writeAttribute(HtmlAttributes.TYPE, HtmlButtonTypes.BUTTON);
164     writer.writeClassAttribute(cssClass, BootstrapClass.BTN, BootstrapClass.BTN_SECONDARY);
165     writer.writeIdAttribute(component.getClientId(context) + ComponentUtils.SUB_SEPARATOR + sub);
166     writer.writeAttribute(HtmlAttributes.DISABLED, disabled);
167     writer.startElement(HtmlElements.I);
168     writer.writeClassAttribute(Icons.FA, icon);
169     writer.endElement(HtmlElements.I);
170     writer.endElement(HtmlElements.BUTTON);
171   }
172 
173   @Override
174   protected String getFieldId(final FacesContext facesContext, final T component) {
175     return component.getClientId(facesContext) + ComponentUtils.SUB_SEPARATOR + "unselected";
176   }
177 }