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("Wicket.DOM.get('street').value ='" + address.getStreet() + "';"); 111 * js.append("Wicket.DOM.get('zipcode').value ='" + address.getZipCode() + "';"); 112 * js.append("Wicket.DOM.get('city').value ='" + address.getCity() + "';"); 113 * js.append("arguments[0]"); // <-- 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("val rate = ajaxGetExchangeRateForCurrency(currencySymbol);"); 125 * js.append("if(rate == null) alert('exchange rate service currently not available');"); 126 * js.append("rate"); 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}