158 lines
5.1 KiB
Java
158 lines
5.1 KiB
Java
// Copyright (C) 2009 The Android Open Source Project
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package com.google.gwtexpui.safehtml.client;
|
|
|
|
import com.google.gwt.user.client.ui.SuggestOracle;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.Collections;
|
|
import java.util.Comparator;
|
|
import java.util.List;
|
|
|
|
/**
|
|
* A suggestion oracle that tries to highlight the matched text.
|
|
*
|
|
* <p>Suggestions supplied by the implementation of {@link #onRequestSuggestions(Request, Callback)}
|
|
* are modified to wrap all occurrences of the {@link
|
|
* com.google.gwt.user.client.ui.SuggestOracle.Request#getQuery()} substring in HTML {@code
|
|
* <strong>} tags, so they can be emphasized to the user.
|
|
*/
|
|
public abstract class HighlightSuggestOracle extends SuggestOracle {
|
|
private static String escape(String ds) {
|
|
return new SafeHtmlBuilder().append(ds).asString();
|
|
}
|
|
|
|
@Override
|
|
public final boolean isDisplayStringHTML() {
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public final void requestSuggestions(Request request, Callback cb) {
|
|
onRequestSuggestions(
|
|
request,
|
|
new Callback() {
|
|
@Override
|
|
public void onSuggestionsReady(Request request, Response response) {
|
|
final String qpat = getQueryPattern(request.getQuery());
|
|
final boolean html = isHTML();
|
|
final ArrayList<Suggestion> r = new ArrayList<>();
|
|
for (Suggestion s : response.getSuggestions()) {
|
|
r.add(new BoldSuggestion(qpat, s, html));
|
|
}
|
|
cb.onSuggestionsReady(request, new Response(r));
|
|
}
|
|
});
|
|
}
|
|
|
|
protected String getQueryPattern(String query) {
|
|
return query;
|
|
}
|
|
|
|
/**
|
|
* @return true if {@link
|
|
* com.google.gwt.user.client.ui.SuggestOracle.Suggestion#getDisplayString()} returns HTML;
|
|
* false if the text must be escaped before evaluating in an HTML like context.
|
|
*/
|
|
protected boolean isHTML() {
|
|
return false;
|
|
}
|
|
|
|
/** Compute the suggestions and return them for display. */
|
|
protected abstract void onRequestSuggestions(Request request, Callback done);
|
|
|
|
private static class BoldSuggestion implements Suggestion {
|
|
private final Suggestion suggestion;
|
|
private final String displayString;
|
|
|
|
BoldSuggestion(String qstr, Suggestion s, boolean html) {
|
|
suggestion = s;
|
|
|
|
String ds = s.getDisplayString();
|
|
if (!html) {
|
|
ds = escape(ds);
|
|
}
|
|
|
|
if (qstr != null && !qstr.isEmpty()) {
|
|
StringBuilder pattern = new StringBuilder();
|
|
for (String qterm : splitQuery(qstr)) {
|
|
qterm = escape(qterm);
|
|
// We now surround qstr by <strong>. But the chosen approach is not too
|
|
// smooth, if qstr is small (e.g.: "t") and this small qstr may occur in
|
|
// escapes (e.g.: "Tim <email@example.org>"). Those escapes will
|
|
// get <strong>-ed as well (e.g.: "<" -> "&<strong>l</strong>t;"). But
|
|
// as repairing those mangled escapes is easier than not mangling them in
|
|
// the first place, we repair them afterwards.
|
|
if (pattern.length() > 0) {
|
|
pattern.append("|");
|
|
}
|
|
pattern.append(qterm);
|
|
}
|
|
|
|
ds = sgi(ds, "(" + pattern.toString() + ")", "<strong>$1</strong>");
|
|
|
|
// Repairing <strong>-ed escapes.
|
|
ds = sgi(ds, "(&[a-z]*)<strong>([a-z]*)</strong>([a-z]*;)", "$1$2$3");
|
|
}
|
|
|
|
displayString = ds;
|
|
}
|
|
|
|
/**
|
|
* Split the query by whitespace and filter out query terms which are substrings of other query
|
|
* terms.
|
|
*/
|
|
private static List<String> splitQuery(String query) {
|
|
List<String> queryTerms = Arrays.asList(query.split("\\s+"));
|
|
Collections.sort(
|
|
queryTerms,
|
|
new Comparator<String>() {
|
|
@Override
|
|
public int compare(String s1, String s2) {
|
|
return Integer.compare(s2.length(), s1.length());
|
|
}
|
|
});
|
|
|
|
List<String> result = new ArrayList<>();
|
|
for (String s : queryTerms) {
|
|
boolean add = true;
|
|
for (String queryTerm : result) {
|
|
if (queryTerm.toLowerCase().contains(s.toLowerCase())) {
|
|
add = false;
|
|
break;
|
|
}
|
|
}
|
|
if (add) {
|
|
result.add(s);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private static native String sgi(String inString, String pat, String newHtml)
|
|
/*-{ return inString.replace(RegExp(pat, 'gi'), newHtml); }-*/ ;
|
|
|
|
@Override
|
|
public String getDisplayString() {
|
|
return displayString;
|
|
}
|
|
|
|
@Override
|
|
public String getReplacementString() {
|
|
return suggestion.getReplacementString();
|
|
}
|
|
}
|
|
}
|