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.core.util.string.JavaScriptUtils; 020import org.apache.wicket.request.Response; 021import org.apache.wicket.util.string.Strings; 022 023/** 024 * A renderer that abstracts auto-assist specific details and allows subclasses to only render the 025 * visual part of the assist instead of having to also render the necessary auto-assist javascript 026 * hooks. 027 * 028 * @param <T> 029 * 030 * @since 1.2 031 * 032 * @author Igor Vaynberg (ivaynberg) 033 */ 034public abstract class AbstractAutoCompleteRenderer<T> implements IAutoCompleteRenderer<T> 035{ 036 private static final long serialVersionUID = 1L; 037 038 @Override 039 public void render(final T object, final Response response, final String criteria) 040 { 041 String textValue = getTextValue(object); 042 if (textValue == null) 043 { 044 throw new IllegalStateException( 045 "A call to textValue(Object) returned an illegal value: null for object: " + 046 object.toString()); 047 } 048 textValue = Strings.escapeMarkup(textValue).toString(); 049 050 response.write("<li textvalue=\"" + textValue + "\""); 051 final CharSequence handler = getOnSelectJavaScriptExpression(object); 052 if (handler != null) 053 { 054 response.write(" onselect=\"" + Strings.escapeMarkup(handler) + '"'); 055 } 056 response.write(">"); 057 renderChoice(object, response, criteria); 058 response.write("</li>"); 059 } 060 061 @Override 062 public void renderHeader(final Response response) 063 { 064 response.write("<ul>"); 065 } 066 067 @Override 068 public void renderFooter(final Response response, int count) 069 { 070 response.write("</ul>"); 071 } 072 073 /** 074 * Render the visual portion of the assist. Usually the html representing the assist choice 075 * object is written out to the response use {@link Response#write(CharSequence)} 076 * 077 * <p> 078 * <b>Whatever is written to the response reaches the markup as is, without escaping.</b> 079 * Any part of it that comes from user input or other dynamic content must be escaped 080 * before it is written, with {@link Strings#escapeMarkup(CharSequence)}. 081 * </p> 082 * 083 * @param object 084 * current assist choice 085 * @param response 086 * @param criteria 087 */ 088 protected abstract void renderChoice(T object, Response response, String criteria); 089 090 /** 091 * Retrieves the text value that will be set on the textbox if this assist is selected 092 * 093 * @param object 094 * assist choice object 095 * @return the text value that will be set on the textbox if this assist is selected 096 */ 097 protected abstract String getTextValue(T object); 098 099 /** 100 * Allows the execution of a custom javascript expression when an item is selected in the 101 * autocompleter popup (either by clicking on it or hitting enter on the current selection). 102 * <p/> 103 * The javascript to execute must be a javascript expression that will be processed using 104 * javascript's eval(). The function should return the textvalue to copy it into the 105 * corresponding form input field (the default behavior). 106 * 107 * the current text value will be in variable 'input'. 108 * 109 * If the function returns <code>null</code> the chosen text value will be ignored. 110 * <p/> 111 * example 1: 112 * 113 * <pre> 114 * protected CharSequence getOnSelectJavaScript(Address address) 115 * { 116 * final StringBuilder js = new StringBuilder(); 117 * js.append("Wicket.DOM.get('street').value ='" + address.getStreet() + "';"); 118 * js.append("Wicket.DOM.get('zipcode').value ='" + address.getZipCode() + "';"); 119 * js.append("Wicket.DOM.get('city').value ='" + address.getCity() + "';"); 120 * js.append("arguments[0]"); // <-- do not use return statement here! 121 * return js.toString(); 122 * } 123 * </pre> 124 * 125 * example 2: 126 * 127 * <pre> 128 * protected CharSequence getOnSelectJavaScript(Currency currency) 129 * { 130 * final StringBuilder js = new StringBuilder(); 131 * js.append("val rate = ajaxGetExchangeRateForCurrency(currencySymbol);"); 132 * js.append("if(rate == null) alert('exchange rate service currently not available');"); 133 * js.append("rate"); 134 * return js.toString(); 135 * } 136 * </pre> 137 * 138 * Then the autocompleter popup will be closed. 139 * 140 * @param item 141 * the autocomplete item to get a custom javascript expression for 142 * @return javascript to execute on selection or <code>null</code> if default behavior is 143 * intended 144 */ 145 protected CharSequence getOnSelectJavaScriptExpression(final T item) 146 { 147 return null; 148 } 149}