001    package org.apache.myfaces.tobago.renderkit.html.sandbox.standard.tag;
002    
003    /*
004     * Licensed to the Apache Software Foundation (ASF) under one or more
005     * contributor license agreements.  See the NOTICE file distributed with
006     * this work for additional information regarding copyright ownership.
007     * The ASF licenses this file to You under the Apache License, Version 2.0
008     * (the "License"); you may not use this file except in compliance with
009     * the License.  You may obtain a copy of the License at
010     *
011     *      http://www.apache.org/licenses/LICENSE-2.0
012     *
013     * Unless required by applicable law or agreed to in writing, software
014     * distributed under the License is distributed on an "AS IS" BASIS,
015     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016     * See the License for the specific language governing permissions and
017     * limitations under the License.
018     */
019    
020    import org.apache.myfaces.tobago.TobagoConstants;
021    import org.apache.myfaces.tobago.util.ComponentUtil;
022    import static org.apache.myfaces.tobago.TobagoConstants.ATTR_DISABLED;
023    import static org.apache.myfaces.tobago.TobagoConstants.ATTR_READONLY;
024    import static org.apache.myfaces.tobago.TobagoConstants.ATTR_STYLE;
025    import org.apache.myfaces.tobago.config.ThemeConfig;
026    import org.apache.myfaces.tobago.context.ResourceManager;
027    import org.apache.myfaces.tobago.context.ResourceManagerFactory;
028    import org.apache.myfaces.tobago.context.TobagoFacesContext;
029    import org.apache.myfaces.tobago.renderkit.LayoutableRendererBase;
030    import org.apache.myfaces.tobago.renderkit.html.HtmlAttributes;
031    import org.apache.myfaces.tobago.renderkit.html.HtmlConstants;
032    import org.apache.myfaces.tobago.renderkit.html.util.HtmlRendererUtil;
033    import org.apache.myfaces.tobago.renderkit.html.HtmlStyleMap;
034    import org.apache.myfaces.tobago.renderkit.html.StyleClasses;
035    import org.apache.myfaces.tobago.webapp.TobagoResponseWriter;
036    
037    import javax.faces.component.UIComponent;
038    import javax.faces.component.UIInput;
039    import javax.faces.component.UIViewRoot;
040    import javax.faces.context.FacesContext;
041    import java.io.IOException;
042    import java.util.Map;
043    
044    public class InputNumberSliderRenderer extends LayoutableRendererBase {
045    
046      private static final String SLIDER_WIDTH_PERCENT = "sliderWidthPercent";
047    
048      public void prepareRender(FacesContext facesContext, UIComponent component) throws IOException {
049        super.prepareRender(facesContext, component);
050        if (facesContext instanceof TobagoFacesContext) {
051          final String[] scripts = new String[]{"script/scriptaculous.js"};
052          ((TobagoFacesContext) facesContext).getScriptFiles().add(scripts[0]);
053        }
054      }
055    
056      public void encodeEnd(FacesContext facesContext, UIComponent component) throws IOException {
057    
058        String id = component.getClientId(facesContext);
059        String currentValue = getCurrentValue(facesContext, component);
060        boolean readonly = ComponentUtil.getBooleanAttribute(component, ATTR_READONLY);
061        boolean disabled = ComponentUtil.getBooleanAttribute(component, ATTR_DISABLED);
062        Integer min = ComponentUtil.getIntAttribute(component, "min");
063        Integer max = ComponentUtil.getIntAttribute(component, "max");
064        TobagoResponseWriter writer = HtmlRendererUtil.getTobagoResponseWriter(facesContext);
065    
066    
067        HtmlStyleMap style = (HtmlStyleMap) component.getAttributes().get(ATTR_STYLE);
068        int width = -1;
069        int sliderWidthPerc = 33;
070        if (ThemeConfig.hasValue(facesContext, component, SLIDER_WIDTH_PERCENT)) {
071          sliderWidthPerc = getConfiguredValue(facesContext, component, SLIDER_WIDTH_PERCENT);
072          if (sliderWidthPerc <= 25) {
073            sliderWidthPerc = 25;
074          }
075          if (sliderWidthPerc >= 75) {
076            sliderWidthPerc = 75;
077          }
078        }
079        int sliderWidth = 100; // fixme
080        int inputWidth = 50; // fixme;
081        if (style != null && style.containsKey("width")) {
082          width = style.getInt("width");
083        }
084        if (width >= 0) {
085          sliderWidth = (width * sliderWidthPerc) / 100;
086          inputWidth = (width * (100 - sliderWidthPerc)) / 100;
087        }
088    
089        writer.startElement(HtmlConstants.TABLE, component);
090        writer.writeIdAttribute(id);
091        writer.writeClassAttribute();
092        writer.writeStyleAttribute();
093        //writer.writeAttribute("border","1",false);
094    
095        StyleClasses styleClasses = new StyleClasses();
096        styleClasses.addAspectClass("inputNumberSlider", "min", StyleClasses.Aspect.DEFAULT);
097    
098        writer.startElement(HtmlConstants.TR, null);
099        writer.startElement(HtmlConstants.TD, null);
100        writer.writeClassAttribute(styleClasses);
101    
102        HtmlStyleMap widthStyle = new HtmlStyleMap();
103        widthStyle.put("width", sliderWidth / 2);
104        writer.writeStyleAttribute(widthStyle);
105        writer.startElement(HtmlConstants.SPAN, null);
106        writer.writeClassAttribute(styleClasses);
107        writer.write(Integer.toString(min));
108        writer.endElement(HtmlConstants.SPAN);
109    
110        styleClasses = new StyleClasses();
111        styleClasses.addAspectClass("inputNumberSlider", "max", StyleClasses.Aspect.DEFAULT);
112    
113        writer.endElement(HtmlConstants.TD);
114        writer.startElement(HtmlConstants.TD, null);
115        writer.writeClassAttribute(styleClasses);
116        writer.writeStyleAttribute(widthStyle);
117        writer.startElement(HtmlConstants.SPAN, null);
118        writer.writeClassAttribute(styleClasses);
119        writer.write(Integer.toString(max));
120        writer.endElement(HtmlConstants.SPAN);
121        writer.endElement(HtmlConstants.TD);
122    
123        // the input field starts here
124        writer.startElement(HtmlConstants.TD, null);
125        writer.writeAttribute("rowspan", "2", false);
126        writer.writeClassAttribute("tobago-inputNumberSlider-input-default");
127    
128        writer.startElement(HtmlConstants.INPUT, null);
129        writer.writeClassAttribute("tobago-in-default");
130        widthStyle.put("width", inputWidth);
131        writer.writeStyleAttribute(widthStyle);
132        String inputIdAndName = getIdForInputField(facesContext, component);
133        writer.writeNameAttribute(inputIdAndName);
134        writer.writeIdAttribute(inputIdAndName);
135        if (currentValue != null) {
136          writer.writeAttribute(HtmlAttributes.VALUE, currentValue, false);
137        }
138        writer.writeAttribute(HtmlAttributes.READONLY, readonly);
139        writer.writeAttribute(HtmlAttributes.DISABLED, disabled);
140        //writer.writeAttribute(HtmlAttributes.STYLE, null, ATTR_STYLE);
141        writer.endElement(HtmlConstants.INPUT);
142        writer.endElement(HtmlConstants.TD);
143    
144        writer.endElement(HtmlConstants.TR);
145        writer.startElement(HtmlConstants.TR, null);
146        writer.startElement(HtmlConstants.TD, null);
147        writer.writeAttribute("colspan", 2);
148    
149        //track
150        writer.startElement(HtmlConstants.DIV, null);
151        writer.writeClassAttribute("tobago-inputNumberSlider-slider-default");
152        writer.writeIdAttribute(getIdForSliderTrack(facesContext, component));
153    
154        // handle
155        writer.startElement(HtmlConstants.DIV, null);
156        writer.writeIdAttribute(getIdForSliderHandle(facesContext, component));
157        writer.writeStyleAttribute("position:relative; top:-6px; width:12px; height:6px");
158        writer.startElement(HtmlConstants.IMG, null);
159        writer.writeAttribute(HtmlAttributes.SRC, getAbsoluteImagePath(facesContext, "image/sliderTriangle.gif"), true);
160        writer.endElement(HtmlConstants.IMG);
161        writer.endElement(HtmlConstants.DIV);
162        writer.endElement(HtmlConstants.DIV);
163        writer.endElement(HtmlConstants.TD);
164        writer.endElement(HtmlConstants.TR);
165        writer.endElement(HtmlConstants.TABLE);
166    
167        writeSliderJavaScript(facesContext, component, writer);
168        //HtmlRendererUtil.renderFocusId(facesContext, component);
169      }
170    
171      public void decode(FacesContext context, UIComponent component) {
172        UIInput uiInput;
173        if (component instanceof UIInput && !ComponentUtil.isOutputOnly(component)) {
174          uiInput = (UIInput) component;
175        } else {
176          return;
177        }
178        String inputId = getIdForInputField(context, component);
179        Map requestParameterMap = context.getExternalContext().getRequestParameterMap();
180        if (requestParameterMap.containsKey(inputId)) {
181          String newValue = (String) requestParameterMap.get(inputId);
182          uiInput.setSubmittedValue(newValue);
183        }
184      }
185    
186      private String getAbsoluteImagePath(FacesContext facesContext, String relativeImagePath) {
187        ResourceManager resourceManager = ResourceManagerFactory.getResourceManager(facesContext);
188        UIViewRoot viewRoot = facesContext.getViewRoot();
189        String contextPath = facesContext.getExternalContext().getRequestContextPath();
190        return contextPath + resourceManager.getImage(viewRoot, relativeImagePath);
191      }
192    
193      private String getIdForInputField(FacesContext context,
194          UIComponent component) {
195        String id = component.getClientId(context);
196        return id + TobagoConstants.SUBCOMPONENT_SEP + "input";
197      }
198    
199      private String getIdForSliderTrack(FacesContext context,
200          UIComponent component) {
201        String id = component.getClientId(context);
202        return id + TobagoConstants.SUBCOMPONENT_SEP + "track";
203      }
204    
205      private String getIdForSliderHandle(FacesContext context,
206          UIComponent component) {
207        String id = component.getClientId(context);
208        return id + TobagoConstants.SUBCOMPONENT_SEP + "handle";
209      }
210    
211      private void writeSliderJavaScript(FacesContext context, UIComponent component,
212          TobagoResponseWriter writer) throws IOException {
213        String trackId = getIdForSliderTrack(context, component);
214        String handleId = getIdForSliderHandle(context, component);
215        String inputId = getIdForInputField(context, component);
216        String jsId = component.getClientId(context).replace(":", "_");
217        Integer min = ComponentUtil.getIntAttribute(component, "min");
218        Integer max = ComponentUtil.getIntAttribute(component, "max");
219        String script = "    var slider_" + jsId + " = new Control.Slider('" + handleId + "', '" + trackId + "', {\n"
220            + "        sliderValue:$('" + inputId + "').value,\n"
221            + "        range : $R(" + min + ", " + max + "),\n"
222            + "        values: $R(" + min + ", " + max + ").toArray(),\n"
223            + "        onSlide:function(v) {\n"
224            + "            $('" + inputId + "').value = v;\n"
225            + "        },\n"
226            + "        onChange:function(v) {\n"
227            + "            $('" + inputId + "').value = v;\n"
228            + "        }\n"
229            + "    });\n"
230            + "\n"
231            + "    Event.observe('value', 'change', function() {\n"
232            + "        slider_" + jsId + ".setValue($('" + inputId + "').value);\n"
233            + "    });\n";
234        writer.writeJavascript(script);
235      }
236    
237    }