001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.wicket.extensions.ajax.markup.html.autocomplete;
018
019import org.apache.wicket.request.Response;
020import org.apache.wicket.util.string.Strings;
021
022/**
023 * A renderer that abstracts auto-assist specific details and allows subclasses to only render the
024 * visual part of the assist instead of having to also render the necessary auto-assist javascript
025 * hooks.
026 * 
027 * @param <T>
028 * 
029 * @since 1.2
030 * 
031 * @author Igor Vaynberg (ivaynberg)
032 */
033public abstract class AbstractAutoCompleteRenderer<T> implements IAutoCompleteRenderer<T>
034{
035        private static final long serialVersionUID = 1L;
036
037        @Override
038        public void render(final T object, final Response response, final String criteria)
039        {
040                String textValue = getTextValue(object);
041                if (textValue == null)
042                {
043                        throw new IllegalStateException(
044                                "A call to textValue(Object) returned an illegal value: null for object: " +
045                                        object.toString());
046                }
047                textValue = Strings.escapeMarkup(textValue).toString();
048
049                response.write("<li textvalue=\"" + textValue + "\"");
050                final CharSequence handler = getOnSelectJavaScriptExpression(object);
051                if (handler != null)
052                {
053                        response.write(" onselect=\"" + handler + '"');
054                }
055                response.write(">");
056                renderChoice(object, response, criteria);
057                response.write("</li>");
058        }
059
060        @Override
061        public void renderHeader(final Response response)
062        {
063                response.write("<ul>");
064        }
065
066        @Override
067        public void renderFooter(final Response response, int count)
068        {
069                response.write("</ul>");
070        }
071
072        /**
073         * Render the visual portion of the assist. Usually the html representing the assist choice
074         * object is written out to the response use {@link Response#write(CharSequence)}
075         * 
076         * @param object
077         *            current assist choice
078         * @param response
079         * @param criteria
080         */
081        protected abstract void renderChoice(T object, Response response, String criteria);
082
083        /**
084         * Retrieves the text value that will be set on the textbox if this assist is selected
085         * 
086         * @param object
087         *            assist choice object
088         * @return the text value that will be set on the textbox if this assist is selected
089         */
090        protected abstract String getTextValue(T object);
091
092        /**
093         * Allows the execution of a custom javascript expression when an item is selected in the
094         * autocompleter popup (either by clicking on it or hitting enter on the current selection).
095         * <p/>
096         * The javascript to execute must be a javascript expression that will be processed using
097         * javascript's eval(). The function should return the textvalue to copy it into the
098         * corresponding form input field (the default behavior).
099         * 
100         * the current text value will be in variable 'input'.
101         * 
102         * If the function returns <code>null</code> the chosen text value will be ignored.
103         * <p/>
104         * example 1:
105         * 
106         * <pre>
107         * protected CharSequence getOnSelectJavaScript(Address address)
108         * {
109         *      final StringBuilder js = new StringBuilder();
110         *      js.append(&quot;Wicket.DOM.get('street').value ='&quot; + address.getStreet() + &quot;';&quot;);
111         *      js.append(&quot;Wicket.DOM.get('zipcode').value ='&quot; + address.getZipCode() + &quot;';&quot;);
112         *      js.append(&quot;Wicket.DOM.get('city').value ='&quot; + address.getCity() + &quot;';&quot;);
113         *      js.append(&quot;arguments[0]&quot;); // &lt;-- do not use return statement here!
114         *      return js.toString();
115         * }
116         * </pre>
117         * 
118         * example 2:
119         * 
120         * <pre>
121         * protected CharSequence getOnSelectJavaScript(Currency currency)
122         * {
123         *      final StringBuilder js = new StringBuilder();
124         *      js.append(&quot;val rate = ajaxGetExchangeRateForCurrency(currencySymbol);&quot;);
125         *      js.append(&quot;if(rate == null) alert('exchange rate service currently not available');&quot;);
126         *      js.append(&quot;rate&quot;);
127         *      return js.toString();
128         * }
129         * </pre>
130         * 
131         * Then the autocompleter popup will be closed.
132         * 
133         * @param item
134         *            the autocomplete item to get a custom javascript expression for
135         * @return javascript to execute on selection or <code>null</code> if default behavior is
136         *         intented
137         */
138        protected CharSequence getOnSelectJavaScriptExpression(final T item)
139        {
140                return null;
141        }
142}