/**
* OLAT - Online Learning and Training<br>
* http://www.olat.org
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); <br>
* you may not use this file except in compliance with the License.<br>
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing,<br>
* software distributed under the License is distributed on an "AS IS" BASIS, <br>
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
* See the License for the specific language governing permissions and <br>
* limitations under the License.
* <p>
* Copyright (c) 1999-2006 at Multimedia- & E-Learning Services (MELS),<br>
* University of Zurich, Switzerland.
* <p>
*/
package org.olat.core.gui.control.generic.ajax.autocompletion;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import org.olat.core.dispatcher.mapper.Mapper;
import org.olat.core.gui.UserRequest;
import org.olat.core.gui.components.Component;
import org.olat.core.gui.components.htmlheader.jscss.JSAndCSSComponent;
import org.olat.core.gui.components.velocity.VelocityContainer;
import org.olat.core.gui.control.Controller;
import org.olat.core.gui.control.Event;
import org.olat.core.gui.control.WindowControl;
import org.olat.core.gui.control.controller.BasicController;
import org.olat.core.gui.media.MediaResource;
import org.olat.core.gui.media.StringMediaResource;
import org.olat.core.logging.AssertException;
/**
*
* Description:<br>
* is a input-field autocompleter, using the scriptaculous javascript library.<br>
* fires: an EntriesChosenEvent which contain the chosen entry/entries as strings
* <P>
* Initial Date: 06.10.2006 <br>
*
* @author Felix Jost
*/
public class AutoCompleterController extends BasicController {
private VelocityContainer myContent;
private Mapper mapper;
private final ListProvider gprovider;
/**
*
* @param ureq
* @param wControl
* @param provider the provider that can be called to return the searchresults for a given search query
* @param noresults the value to display when no results are found, e.g. "no matches found" or "-no users found-". A message must be provided, since otherwise there is no visual difference between a slow server and a search with 0 hits.
* @param allowMultipleEntries if true, the autocompleter accepts several entries on one line being separated by "," or ";"
*/
public AutoCompleterController(UserRequest ureq, WindowControl wControl, ListProvider provider, final String noresults, boolean allowMultipleEntries, String label) {
super(ureq, wControl);
this.gprovider = provider;
myContent = createVelocityContainer("autocomplete");
// let the scripts (.js files) and css files be included when this controller's main component is rendered
JSAndCSSComponent jscss = new JSAndCSSComponent("jac", this.getClass(), null, "autocompleter.css", false);
myContent.put("jac", jscss); // we include it in the render tree (but we do not need $r.render(...)), so that the custom js and css are included
if (label != null) {
myContent.contextPut("autocompleter_label", label);
}
// configure the autocompleter whether to accept "," or ";" as separating tokens in case of allowMultipleEntries
if (allowMultipleEntries) {
myContent.contextPut("tokenlist", "',',';'"); // else tokenlist is empty -> tokens: []
myContent.contextPut("afterUpdateElement","dhk123"); // TODO:cg, 10.12.2009: dhk123 does not work !!!
throw new AssertException("Sorry, allowMultipleEntries=true is currently NOT supported!");
} else {
// for single entry, define the behaviour to automatically submit after choosing an entry
myContent.contextPut("afterUpdateElement","afterUpdateElement");
}
// create a mapper for the server responses for a given input
mapper = new Mapper() {
public MediaResource handle(String relPath, HttpServletRequest request) {
String lastN = request.getParameter("qs");
AutoCompleterListReceiver receiver = new AutoCompleterListReceiver(noresults);
gprovider.getResult(lastN, receiver);
String html = receiver.getResult();
StringMediaResource smr = new StringMediaResource();
smr.setContentType("text/html");
smr.setEncoding("utf-8");
smr.setData(html);
return smr;
}
};
String fetchUri = registerMapper(mapper);
final String fulluri = fetchUri; // + "/" + fileName;
myContent.contextPut("mapuri", fulluri+"/");
putInitialPanel(myContent);
}
public AutoCompleterController(UserRequest ureq, WindowControl wControl, ListProvider provider, final String noresults, boolean allowMultipleEntries) {
this(ureq, wControl, provider, noresults, allowMultipleEntries, null);
}
/**
* This dispatches component events...
*
* @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest,
* org.olat.core.gui.components.Component, org.olat.core.gui.control.Event)
*/
public void event(UserRequest ureq, Component source, Event event) {
if (source == myContent) {
if (event.getCommand().equals("ch")) {
String res = ureq.getParameter("qs");
if (res == null) throw new AssertException("form should always post 'ch' input field");
//res.split()
if (res.equals("")) {
// empty entry list
fireEvent(ureq, new EntriesChosenEvent(new ArrayList()));
return;
}
Pattern p = Pattern.compile(",|;");
List entries = Arrays.asList(p.split(res));
if (entries.size() > 0) {
fireEvent(ureq, new EntriesChosenEvent(entries));
}
}
}
}
/**
* This dispatches controller events...
*
* @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest,
* org.olat.core.gui.control.Controller, org.olat.core.gui.control.Event)
*/
public void event(UserRequest ureq, Controller source, Event event) {
}
protected void doDispose() {
// mapper autodisposed by basic controller
}
}
class AutoCompleterListReceiver implements ListReceiver {
private StringBuilder sb;
private int cnt = 0;
private final String noresults;
AutoCompleterListReceiver(String noresults) {
this.noresults = noresults;
sb = new StringBuilder(512);
sb.append("<ul>");
}
/* (non-Javadoc)
* @see org.olat.core.gui.control.generic.ajax.autocompletion.ListReceiver#addEntry(java.lang.String, java.lang.String)
* @param value could be null
*/
public void addEntry(String key, String value) {
sb.append("<li>");
if (value != null) {
sb.append("<span class=\"informal\">");
sb.append(value);
sb.append(" </span>");
}
sb.append(key).append("</li>");
cnt++;
}
public String getResult() {
if (cnt ==0) sb.append("<li><span class=\"informal\">").append(noresults).append("<span></li>");
sb.append("</ul>");
return sb.toString();
}
}