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 java.util.Iterator; 020 021import org.apache.wicket.Application; 022import org.apache.wicket.AttributeModifier; 023import org.apache.wicket.Component; 024import org.apache.wicket.request.IRequestCycle; 025import org.apache.wicket.request.IRequestHandler; 026import org.apache.wicket.request.cycle.RequestCycle; 027import org.apache.wicket.request.http.WebResponse; 028import org.apache.wicket.util.lang.Args; 029 030 031/** 032 * This behavior builds on top of {@link AbstractAutoCompleteBehavior} by introducing the concept of 033 * a {@link IAutoCompleteRenderer} to make response writing easier. 034 * 035 * @param <T> 036 * 037 * @see IAutoCompleteRenderer 038 * 039 * @since 1.2 040 * 041 * @author Igor Vaynberg (ivaynberg) 042 * @author Janne Hietamäki (jannehietamaki) 043 */ 044public abstract class AutoCompleteBehavior<T> extends AbstractAutoCompleteBehavior 045{ 046 private static final long serialVersionUID = 1L; 047 048 private final IAutoCompleteRenderer<T> renderer; 049 050 /** 051 * Constructor 052 * 053 * @param renderer 054 * renderer that will be used to generate output 055 */ 056 public AutoCompleteBehavior(final IAutoCompleteRenderer<T> renderer) 057 { 058 this(renderer, false); 059 } 060 061 /** 062 * Constructor 063 * 064 * @param renderer 065 * renderer that will be used to generate output 066 * @param preselect 067 * highlight/preselect the first item in the autocomplete list automatically 068 */ 069 public AutoCompleteBehavior(final IAutoCompleteRenderer<T> renderer, final boolean preselect) 070 { 071 this(renderer, new AutoCompleteSettings().setPreselect(preselect)); 072 } 073 074 /** 075 * Constructor 076 * 077 * @param renderer 078 * renderer that will be used to generate output 079 * @param settings 080 * settings for the autocomplete list 081 */ 082 public AutoCompleteBehavior(final IAutoCompleteRenderer<T> renderer, 083 final AutoCompleteSettings settings) 084 { 085 super(settings); 086 087 this.renderer = Args.notNull(renderer, "renderer"); 088 } 089 090 @Override 091 protected void onBind() { 092 super.onBind(); 093 094 getComponent().add(new AttributeModifier("aria-autocomplete", "list")); 095 } 096 097 @Override 098 protected final void onRequest(final String val, final RequestCycle requestCycle) 099 { 100 IRequestHandler target = new IRequestHandler() 101 { 102 @Override 103 public void respond(final IRequestCycle requestCycle) 104 { 105 WebResponse r = (WebResponse)requestCycle.getResponse(); 106 107 // Determine encoding 108 final String encoding = Application.get() 109 .getRequestCycleSettings() 110 .getResponseRequestEncoding(); 111 112 r.setContentType("text/xml; charset=" + encoding); 113 r.disableCaching(); 114 115 Iterator<T> comps = getChoices(val); 116 int count = 0; 117 renderer.renderHeader(r); 118 while (comps.hasNext()) 119 { 120 final T comp = comps.next(); 121 renderer.render(comp, r, val); 122 count += 1; 123 } 124 renderer.renderFooter(r, count); 125 } 126 }; 127 128 requestCycle.scheduleRequestHandlerAfterCurrent(target); 129 } 130 131 /** 132 * Callback method that should return an iterator over all possible choice objects. These 133 * objects will be passed to the renderer to generate output. Usually it is enough to return an 134 * iterator over strings. 135 * 136 * @param input 137 * current input 138 * @return iterator over all possible choice objects 139 */ 140 protected abstract Iterator<T> getChoices(String input); 141 142 @Override 143 public void detach(Component component) 144 { 145 renderer.detach(); 146 } 147}