diff --git a/htroot/yacysearchtrailer.java b/htroot/yacysearchtrailer.java index d7fc421e8..8edde837f 100644 --- a/htroot/yacysearchtrailer.java +++ b/htroot/yacysearchtrailer.java @@ -144,21 +144,22 @@ public class yacysearchtrailer { nav = "%2Flanguage%2F" + name; /* Avoid double percent encoding in QueryParams.navurl */ rawNav = "/language/" + name; + final String navUrl; if (theSearch.query.modifier.language == null || !theSearch.query.modifier.language.contains(name)) { pos++; prop.put("nav-languages_element_" + i + "_on", 1); prop.put(fileType, "nav-languages_element_" + i + "_modifier", nav); + navUrl = QueryParams.navurl(fileType, 0, theSearch.query, rawNav, false, authenticated).toString(); } else { neg++; prop.put("nav-languages_element_" + i + "_on", 0); prop.put(fileType, "nav-languages_element_" + i + "_modifier", "-" + nav); - nav=""; - rawNav = ""; + navUrl = QueryParams.navUrlWithSingleModifierRemoved(fileType, 0, theSearch.query, rawNav, + authenticated); } String longname = ISO639.country(name); prop.put(fileType, "nav-languages_element_" + i + "_name", longname == null ? name : longname); - prop.put(fileType, "nav-languages_element_" + i + "_url", - QueryParams.navurl(fileType, 0, theSearch.query, rawNav, false, authenticated).toString()); + prop.put(fileType, "nav-languages_element_" + i + "_url", navUrl); prop.put(fileType, "nav-languages_element_" + i + "_id", "languages_" + i); prop.put("nav-languages_element_" + i + "_count", count); prop.put("nav-languages_element_" + i + "_nl", 1); @@ -238,22 +239,23 @@ public class yacysearchtrailer { nav = "%2F" + name; /* Avoid double percent encoding in QueryParams.navurl */ rawNav = "/" + name; + final String url; if (oldProtocolModifier == null || !oldProtocolModifier.equals(name)) { pos++; prop.put("nav-protocols_element_" + i + "_on", 0); prop.put("nav-protocols_element_" + i + "_onclick", 0); prop.put(fileType, "nav-protocols_element_" + i + "_modifier", nav); + url = QueryParams.navurl(fileType, 0, theSearch.query, rawNav, false, authenticated).toString(); } else { neg++; prop.put("nav-protocols_element_" + i + "_on", 1); prop.put("nav-protocols_element_" + i + "_onclick", 1); prop.put(fileType, "nav-protocols_element_" + i + "_modifier", "-" + nav); - nav=""; - rawNav = ""; + url = QueryParams + .navUrlWithSingleModifierRemoved(fileType, 0, theSearch.query, rawNav, authenticated) + .toString(); } prop.put(fileType, "nav-protocols_element_" + i + "_name", name); - String url = QueryParams.navurl(fileType, 0, theSearch.query, rawNav, false, authenticated) - .toString(); prop.put("nav-protocols_element_" + i + "_onclick_url", url); prop.put(fileType, "nav-protocols_element_" + i + "_url", url); prop.put("nav-protocols_element_" + i + "_count", count); @@ -346,18 +348,18 @@ public class yacysearchtrailer { nav = "%2Fvocabulary%2F" + navname + "%2F" + MultiProtocolURL.escape(Tagging.encodePrintname(name)).toString(); /* Avoid double percent encoding in QueryParams.navurl */ rawNav = "/vocabulary/" + navname + "/" + MultiProtocolURL.escape(Tagging.encodePrintname(name)).toString(); + final String navUrl; if (!theSearch.query.modifier.toString().contains("/vocabulary/" + navname + "/" + name.replace(' ', '_'))) { prop.put("nav-vocabulary_" + navvoccount + "_element_" + i + "_on", 1); prop.put(fileType, "nav-vocabulary_" + navvoccount + "_element_" + i + "_modifier", nav); + navUrl = QueryParams.navurl(fileType, 0, theSearch.query, rawNav, false, authenticated).toString(); } else { prop.put("nav-vocabulary_" + navvoccount + "_element_" + i + "_on", 0); prop.put(fileType, "nav-vocabulary_" + navvoccount + "_element_" + i + "_modifier", "-" + nav); - nav=""; - rawNav = ""; + navUrl = QueryParams.navUrlWithSingleModifierRemoved(fileType, 0, theSearch.query, rawNav, authenticated); } prop.put(fileType, "nav-vocabulary_" + navvoccount + "_element_" + i + "_name", name); - prop.put(fileType, "nav-vocabulary_" + navvoccount + "_element_" + i + "_url", QueryParams - .navurl(fileType, 0, theSearch.query, rawNav, false, authenticated).toString()); + prop.put(fileType, "nav-vocabulary_" + navvoccount + "_element_" + i + "_url", navUrl); prop.put(fileType, "nav-vocabulary_" + navvoccount + "_element_" + i + "_id", "vocabulary_" + navname + "_" + i); prop.put("nav-vocabulary_" + navvoccount + "_element_" + i + "_count", count); prop.put("nav-vocabulary_" + navvoccount + "_element_" + i + "_nl", 1); @@ -404,20 +406,21 @@ public class yacysearchtrailer { nav = ""; } boolean isactive = navi.modifieractive(theSearch.query.modifier, name); + final String navUrl; if (!isactive) { pos++; prop.put("navs_" + ni + "_element_" + i + "_on", 1); prop.put(fileType, "navs_" + ni + "_element_" + i + "_modifier", nav); + navUrl = QueryParams.navurl(fileType, 0, theSearch.query, rawNav, false, authenticated).toString(); } else { neg++; prop.put("navs_" + ni + "_element_" + i + "_on", 0); prop.put(fileType, "navs_" + ni + "_element_" + i + "_modifier", "-" + nav); - nav = ""; - rawNav = ""; + navUrl = QueryParams.navUrlWithSingleModifierRemoved(fileType, 0, theSearch.query, rawNav, + authenticated); } prop.put(fileType, "navs_" + ni + "_element_" + i + "_name", navi.getElementDisplayName(name)); - prop.put(fileType, "navs_" + ni + "_element_" + i + "_url", QueryParams - .navurl(fileType, 0, theSearch.query, rawNav, false, authenticated).toString()); + prop.put(fileType, "navs_" + ni + "_element_" + i + "_url", navUrl); prop.put(fileType, "navs_" + ni + "_element_" + i + "_id", naviname + "_" + i); prop.put("navs_" + ni + "_element_" + i + "_count", count); prop.put("navs_" + ni + "_element_" + i + "_nl", 1); diff --git a/source/net/yacy/search/query/QueryParams.java b/source/net/yacy/search/query/QueryParams.java index 9500b84c9..913ed766d 100644 --- a/source/net/yacy/search/query/QueryParams.java +++ b/source/net/yacy/search/query/QueryParams.java @@ -44,6 +44,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; +import org.apache.commons.lang.StringUtils; import org.apache.lucene.util.automaton.Automata; import org.apache.lucene.util.automaton.Automaton; import org.apache.lucene.util.automaton.RegExp; @@ -907,6 +908,47 @@ public final class QueryParams { return sb; } + /** + * Build a search query URL from the given parameters, removing only the given single query modifier. + * + * @param ext extension of the servlet to request (e.g. "html", "rss", "json"...) + * @param page index of the wanted page (first page is zero) + * @param theQuery holds the main query parameters. Must not be null. + * @param modifierToRemove the query modifier to remove (e.g. "keyword:word", "/language/en", "site:example.org"...) + * @param authenticatedFeatures + * when true, access to authentication protected search features is + * wanted + * @return the URL to the new search result page + */ + public static String navUrlWithSingleModifierRemoved(final RequestHeader.FileType ext, final int page, final QueryParams theQuery, + final String modifierToRemove, final boolean authenticatedFeatures) { + + final StringBuilder sb = new StringBuilder(120); + sb.append("yacysearch."); + sb.append(ext.name().toLowerCase(Locale.ROOT)); + sb.append("?query="); + + sb.append(theQuery.getQueryGoal().getQueryString(true)); + + if (!theQuery.modifier.isEmpty()) { + String modifierString = theQuery.modifier.toString(); + if(StringUtils.isNotBlank(modifierToRemove)) { + if(modifierString.startsWith(modifierToRemove)) { + modifierString = modifierString.substring(modifierToRemove.length()); + } else { + modifierString = modifierString.replace(" " + modifierToRemove, ""); + } + } + if(StringUtils.isNotBlank(modifierString)) { + sb.append("+" + modifierString.trim()); + } + } + + appendNavUrlQueryParams(sb, theQuery, authenticatedFeatures); + + return sb.toString(); + } + /** * Build a search query URL with a new search query string, but keeping any already defined eventual modifiers. * @@ -927,7 +969,12 @@ public final class QueryParams { sb.append("?query="); sb.append(new QueryGoal(newQueryString).getQueryString(true)); - appendNavUrlQueryParams(sb, theQuery, null, false, authenticatedFeatures); + + if (!theQuery.modifier.isEmpty()) { + sb.append("+" + theQuery.modifier.toString()); + } + + appendNavUrlQueryParams(sb, theQuery, authenticatedFeatures); return sb.toString(); } @@ -958,27 +1005,7 @@ public final class QueryParams { sb.append("?query="); sb.append(theQuery.getQueryGoal().getQueryString(true)); - appendNavUrlQueryParams(sb, theQuery, newModifier, newModifierReplacesOld, authenticatedFeatures); - - return sb; - } - - /** - * Append search query parameters to the URL builder already filled with the beginning of the URL. - * - * @param sb the URL string builder to fill. Must not be null. - * @param theQuery holds the main query parameters. Must not be null. - * @param newModifier optional new modifier. - if null existing modifier(s) of theQuery are - * appended - if not null this new modifier is appended in addition - * to eventually existing modifier(s) - if isEmpty overwrites (clears) any eventual existing - * modifier(s) - * @param newModifierReplacesOld considered only when newModifier is not null and not empty. When true, any existing modifiers with the same name are replaced with the new one. - * @param authenticatedFeatures - * when true, access to authentication protected search features is - * wanted - */ - protected static void appendNavUrlQueryParams(final StringBuilder sb, final QueryParams theQuery, final String newModifier, - final boolean newModifierReplacesOld, final boolean authenticatedFeatures) { + if (newModifier == null) { if (!theQuery.modifier.isEmpty()) { sb.append("+" + theQuery.modifier.toString()); @@ -998,7 +1025,23 @@ public final class QueryParams { } } } + + appendNavUrlQueryParams(sb, theQuery, authenticatedFeatures); + return sb; + } + + /** + * Append search query parameters to the URL builder already filled with the beginning of the URL. + * + * @param sb the URL string builder to fill. Must not be null. + * @param theQuery holds the main query parameters. Must not be null. + * @param authenticatedFeatures + * when true, access to authentication protected search features is + * wanted + */ + protected static void appendNavUrlQueryParams(final StringBuilder sb, final QueryParams theQuery, + final boolean authenticatedFeatures) { sb.append("&maximumRecords="); sb.append(theQuery.itemsPerPage());