Added custom search controller
Cleaned custom search controller Autoselect hits per page from query. Moved template change to VIVO branch Split search services
This commit is contained in:
parent
bc10e79f92
commit
6b7092a4d5
11 changed files with 7878 additions and 2 deletions
|
@ -37,6 +37,7 @@ public class UrlBuilder {
|
||||||
LOGIN("/login"),
|
LOGIN("/login"),
|
||||||
LOGOUT("/logout"),
|
LOGOUT("/logout"),
|
||||||
OBJECT_PROPERTY_EDIT("/propertyEdit"),
|
OBJECT_PROPERTY_EDIT("/propertyEdit"),
|
||||||
|
EXTENDED_SEARCH("/extendedsearch"),
|
||||||
SEARCH("/search"),
|
SEARCH("/search"),
|
||||||
SITE_ADMIN("/siteAdmin"),
|
SITE_ADMIN("/siteAdmin"),
|
||||||
TERMS_OF_USE("/termsOfUse"),
|
TERMS_OF_USE("/termsOfUse"),
|
||||||
|
|
|
@ -304,6 +304,7 @@ public class FreemarkerConfigurationImpl extends Configuration {
|
||||||
urls.put("home", UrlBuilder.getHomeUrl());
|
urls.put("home", UrlBuilder.getHomeUrl());
|
||||||
urls.put("about", UrlBuilder.getUrl(Route.ABOUT));
|
urls.put("about", UrlBuilder.getUrl(Route.ABOUT));
|
||||||
urls.put("search", UrlBuilder.getUrl(Route.SEARCH));
|
urls.put("search", UrlBuilder.getUrl(Route.SEARCH));
|
||||||
|
urls.put("extendedsearch", UrlBuilder.getUrl(Route.EXTENDED_SEARCH));
|
||||||
urls.put("termsOfUse", UrlBuilder.getUrl(Route.TERMS_OF_USE));
|
urls.put("termsOfUse", UrlBuilder.getUrl(Route.TERMS_OF_USE));
|
||||||
urls.put("login", UrlBuilder.getLoginUrl());
|
urls.put("login", UrlBuilder.getLoginUrl());
|
||||||
urls.put("logout", UrlBuilder.getLogoutUrl());
|
urls.put("logout", UrlBuilder.getLogoutUrl());
|
||||||
|
|
|
@ -0,0 +1,767 @@
|
||||||
|
/* $This file is distributed under the terms of the license in LICENSE$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.search.controller;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.annotation.WebServlet;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.application.ApplicationUtils;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.beans.ApplicationBean;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.beans.Individual;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.beans.VClass;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.beans.VClassGroup;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerHttpServlet;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.ParamMap;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ExceptionResponseValues;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.dao.IndividualDao;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.dao.VClassDao;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.dao.VClassGroupDao;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.dao.VClassGroupsForRequest;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.dao.jena.VClassGroupCache;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.i18n.I18n;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchEngine;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchFacetField;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchFacetField.Count;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchQuery;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchResponse;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchResultDocument;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.modules.searchEngine.SearchResultDocumentList;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.search.VitroSearchTermNames;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.LinkTemplateModel;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.searchresult.IndividualSearchResult;
|
||||||
|
import edu.ucsf.vitro.opensocial.OpenSocialManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Paged search controller that uses the search engine
|
||||||
|
*/
|
||||||
|
|
||||||
|
@WebServlet(name = "ExtendedSearchController", urlPatterns = {"/extendedsearch","/extendedsearch.jsp","/extendedfedsearch","/extendedsearchcontroller"} )
|
||||||
|
public class ExtendedSearchController extends FreemarkerHttpServlet {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
private static final Log log = LogFactory.getLog(ExtendedSearchController.class);
|
||||||
|
|
||||||
|
protected static final int DEFAULT_HITS_PER_PAGE = 25;
|
||||||
|
protected static final int DEFAULT_MAX_HIT_COUNT = 1000;
|
||||||
|
|
||||||
|
private static final String PARAM_XML_REQUEST = "xml";
|
||||||
|
private static final String PARAM_CSV_REQUEST = "csv";
|
||||||
|
private static final String PARAM_START_INDEX = "startIndex";
|
||||||
|
private static final String PARAM_HITS_PER_PAGE = "hitsPerPage";
|
||||||
|
private static final String PARAM_CLASSGROUP = "classgroup";
|
||||||
|
private static final String PARAM_RDFTYPE = "type";
|
||||||
|
private static final String PARAM_QUERY_TEXT = "querytext";
|
||||||
|
private static final String EXTENDEDSEARCH = "/extendedsearch";
|
||||||
|
|
||||||
|
protected static final Map<Format,Map<Result,String>> templateTable;
|
||||||
|
|
||||||
|
protected enum Format {
|
||||||
|
HTML, XML, CSV;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected enum Result {
|
||||||
|
PAGED, ERROR, BAD_QUERY
|
||||||
|
}
|
||||||
|
|
||||||
|
static{
|
||||||
|
templateTable = setupTemplateTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overriding doGet from FreemarkerHttpController to do a page template (as
|
||||||
|
* opposed to body template) style output for XML requests.
|
||||||
|
*
|
||||||
|
* This follows the pattern in AutocompleteController.java.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void doGet(HttpServletRequest request, HttpServletResponse response)
|
||||||
|
throws IOException, ServletException {
|
||||||
|
VitroRequest vreq = new VitroRequest(request);
|
||||||
|
boolean wasXmlRequested = isRequestedFormatXml(vreq);
|
||||||
|
boolean wasCSVRequested = isRequestedFormatCSV(vreq);
|
||||||
|
if( !wasXmlRequested && !wasCSVRequested){
|
||||||
|
super.doGet(vreq,response);
|
||||||
|
}else if (wasXmlRequested){
|
||||||
|
try {
|
||||||
|
ResponseValues rvalues = processRequest(vreq);
|
||||||
|
|
||||||
|
response.setCharacterEncoding("UTF-8");
|
||||||
|
response.setContentType("text/xml;charset=UTF-8");
|
||||||
|
response.setHeader("Content-Disposition", "attachment; filename=search.xml");
|
||||||
|
writeTemplate(rvalues.getTemplateName(), rvalues.getMap(), request, response);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e, e);
|
||||||
|
}
|
||||||
|
}else if (wasCSVRequested){
|
||||||
|
try {
|
||||||
|
ResponseValues rvalues = processRequest(vreq);
|
||||||
|
|
||||||
|
response.setCharacterEncoding("UTF-8");
|
||||||
|
response.setContentType("text/csv;charset=UTF-8");
|
||||||
|
response.setHeader("Content-Disposition", "attachment; filename=search.csv");
|
||||||
|
writeTemplate(rvalues.getTemplateName(), rvalues.getMap(), request, response);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doPost(HttpServletRequest request, HttpServletResponse response)
|
||||||
|
throws IOException, ServletException {
|
||||||
|
VitroRequest vreq = new VitroRequest(request);
|
||||||
|
boolean wasXmlRequested = isRequestedFormatXml(vreq);
|
||||||
|
boolean wasCSVRequested = isRequestedFormatCSV(vreq);
|
||||||
|
if( !wasXmlRequested && !wasCSVRequested){
|
||||||
|
super.doGet(vreq,response);
|
||||||
|
}else if (wasXmlRequested){
|
||||||
|
try {
|
||||||
|
ResponseValues rvalues = processRequest(vreq);
|
||||||
|
|
||||||
|
response.setCharacterEncoding("UTF-8");
|
||||||
|
response.setContentType("text/xml;charset=UTF-8");
|
||||||
|
response.setHeader("Content-Disposition", "attachment; filename=search.xml");
|
||||||
|
writeTemplate(rvalues.getTemplateName(), rvalues.getMap(), request, response);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e, e);
|
||||||
|
}
|
||||||
|
}else if (wasCSVRequested){
|
||||||
|
try {
|
||||||
|
ResponseValues rvalues = processRequest(vreq);
|
||||||
|
|
||||||
|
response.setCharacterEncoding("UTF-8");
|
||||||
|
response.setContentType("text/csv;charset=UTF-8");
|
||||||
|
response.setHeader("Content-Disposition", "attachment; filename=search.csv");
|
||||||
|
writeTemplate(rvalues.getTemplateName(), rvalues.getMap(), request, response);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ResponseValues processRequest(VitroRequest vreq) {
|
||||||
|
|
||||||
|
//There may be other non-html formats in the future
|
||||||
|
Format format = getFormat(vreq);
|
||||||
|
boolean wasXmlRequested = Format.XML == format;
|
||||||
|
boolean wasCSVRequested = Format.CSV == format;
|
||||||
|
log.debug("Requested format was " + (wasXmlRequested ? "xml" : "html"));
|
||||||
|
boolean wasHtmlRequested = ! (wasXmlRequested || wasCSVRequested);
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
//make sure an IndividualDao is available
|
||||||
|
if( vreq.getWebappDaoFactory() == null
|
||||||
|
|| vreq.getWebappDaoFactory().getIndividualDao() == null ){
|
||||||
|
log.error("Could not get webappDaoFactory or IndividualDao");
|
||||||
|
throw new Exception("Could not access model.");
|
||||||
|
}
|
||||||
|
IndividualDao iDao = vreq.getWebappDaoFactory().getIndividualDao();
|
||||||
|
VClassGroupDao grpDao = vreq.getWebappDaoFactory().getVClassGroupDao();
|
||||||
|
VClassDao vclassDao = vreq.getWebappDaoFactory().getVClassDao();
|
||||||
|
|
||||||
|
ApplicationBean appBean = vreq.getAppBean();
|
||||||
|
|
||||||
|
log.debug("IndividualDao is " + iDao.toString() + " Public classes in the classgroup are " + grpDao.getPublicGroupsWithVClasses().toString());
|
||||||
|
log.debug("VClassDao is "+ vclassDao.toString() );
|
||||||
|
|
||||||
|
int startIndex = getStartIndex(vreq);
|
||||||
|
int hitsPerPage = getHitsPerPage( vreq );
|
||||||
|
String queryBuilderRules = getQueryBuilderRules(vreq);
|
||||||
|
|
||||||
|
|
||||||
|
String queryText = vreq.getParameter(PARAM_QUERY_TEXT);
|
||||||
|
log.debug("Query text is \""+ queryText + "\"");
|
||||||
|
|
||||||
|
|
||||||
|
String badQueryMsg = badQueryText( queryText, vreq );
|
||||||
|
if( badQueryMsg != null ){
|
||||||
|
return doFailedSearch(badQueryMsg, queryText, format, vreq);
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchQuery query = getQuery(queryText, hitsPerPage, startIndex, vreq);
|
||||||
|
SearchEngine search = ApplicationUtils.instance().getSearchEngine();
|
||||||
|
SearchResponse response = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
response = search.query(query);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
String msg = makeBadSearchMessage(queryText, ex.getMessage(), vreq);
|
||||||
|
log.error("could not run search query",ex);
|
||||||
|
return doFailedSearch(msg, queryText, format, vreq);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response == null) {
|
||||||
|
log.error("Search response was null");
|
||||||
|
return doFailedSearch(I18n.text(vreq, "error_in_search_request"), queryText, format, vreq);
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchResultDocumentList docs = response.getResults();
|
||||||
|
if (docs == null) {
|
||||||
|
log.error("Document list for a search was null");
|
||||||
|
return doFailedSearch(I18n.text(vreq, "error_in_search_request"), queryText,format, vreq);
|
||||||
|
}
|
||||||
|
|
||||||
|
long hitCount = docs.getNumFound();
|
||||||
|
log.debug("Number of hits = " + hitCount);
|
||||||
|
if ( hitCount < 1 ) {
|
||||||
|
return doNoHits(queryText,format, vreq);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Individual> individuals = new ArrayList<Individual>(docs.size());
|
||||||
|
for (SearchResultDocument doc : docs) {
|
||||||
|
try {
|
||||||
|
String uri = doc.getStringValue(VitroSearchTermNames.URI);
|
||||||
|
Individual ind = iDao.getIndividualByURI(uri);
|
||||||
|
if (ind != null) {
|
||||||
|
ind.setSearchSnippet(getSnippet(doc, response));
|
||||||
|
individuals.add(ind);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Problem getting usable individuals from search hits. ", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ParamMap pagingLinkParams = new ParamMap();
|
||||||
|
pagingLinkParams.put(PARAM_QUERY_TEXT, queryText);
|
||||||
|
pagingLinkParams.put(PARAM_HITS_PER_PAGE, String.valueOf(hitsPerPage));
|
||||||
|
|
||||||
|
if( wasXmlRequested ){
|
||||||
|
pagingLinkParams.put(PARAM_XML_REQUEST,"1");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compile the data for the templates */
|
||||||
|
|
||||||
|
Map<String, Object> body = new HashMap<String, Object>();
|
||||||
|
|
||||||
|
String classGroupParam = vreq.getParameter(PARAM_CLASSGROUP);
|
||||||
|
log.debug("ClassGroupParam is \""+ classGroupParam + "\"");
|
||||||
|
boolean classGroupFilterRequested = false;
|
||||||
|
if (!StringUtils.isEmpty(classGroupParam)) {
|
||||||
|
VClassGroup grp = grpDao.getGroupByURI(classGroupParam);
|
||||||
|
classGroupFilterRequested = true;
|
||||||
|
if (grp != null && grp.getPublicName() != null)
|
||||||
|
body.put("classGroupName", grp.getPublicName());
|
||||||
|
}
|
||||||
|
|
||||||
|
String typeParam = vreq.getParameter(PARAM_RDFTYPE);
|
||||||
|
boolean typeFilterRequested = false;
|
||||||
|
if (!StringUtils.isEmpty(typeParam)) {
|
||||||
|
VClass type = vclassDao.getVClassByURI(typeParam);
|
||||||
|
typeFilterRequested = true;
|
||||||
|
if (type != null && type.getName() != null)
|
||||||
|
body.put("typeName", type.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add ClassGroup and type refinement links to body */
|
||||||
|
if( wasHtmlRequested ){
|
||||||
|
if ( !classGroupFilterRequested && !typeFilterRequested ) {
|
||||||
|
// Search request includes no ClassGroup and no type, so add ClassGroup search refinement links.
|
||||||
|
body.put("classGroupLinks", getClassGroupsLinks(vreq, grpDao, docs, response, queryText));
|
||||||
|
} else if ( classGroupFilterRequested && !typeFilterRequested ) {
|
||||||
|
// Search request is for a ClassGroup, so add rdf:type search refinement links
|
||||||
|
// but try to filter out classes that are subclasses
|
||||||
|
body.put("classLinks", getVClassLinks(vclassDao, docs, response, queryText));
|
||||||
|
pagingLinkParams.put(PARAM_CLASSGROUP, classGroupParam);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
//search request is for a class so there are no more refinements
|
||||||
|
pagingLinkParams.put(PARAM_RDFTYPE, typeParam);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
body.put("individuals", IndividualSearchResult
|
||||||
|
.getIndividualTemplateModels(individuals, vreq));
|
||||||
|
|
||||||
|
body.put("querytext", queryText);
|
||||||
|
body.put("title", new StringBuilder().append(appBean.getApplicationName()).append(" - ").
|
||||||
|
append(I18n.text(vreq, "search_results_for")).append(" '").append(queryText).append("'").toString());
|
||||||
|
|
||||||
|
body.put("hitCount", hitCount);
|
||||||
|
body.put("startIndex", startIndex);
|
||||||
|
body.put(PARAM_HITS_PER_PAGE, hitsPerPage);
|
||||||
|
|
||||||
|
body.put("pagingLinks",
|
||||||
|
getPagingLinks(startIndex, hitsPerPage, hitCount,
|
||||||
|
vreq.getServletPath(),
|
||||||
|
pagingLinkParams, vreq));
|
||||||
|
|
||||||
|
if (startIndex != 0) {
|
||||||
|
body.put("prevPage", getPreviousPageLink(startIndex,
|
||||||
|
hitsPerPage, vreq.getServletPath(), pagingLinkParams));
|
||||||
|
}
|
||||||
|
if (startIndex < (hitCount - hitsPerPage)) {
|
||||||
|
body.put("nextPage", getNextPageLink(startIndex, hitsPerPage,
|
||||||
|
vreq.getServletPath(), pagingLinkParams));
|
||||||
|
}
|
||||||
|
if (queryBuilderRules != null) {
|
||||||
|
body.put("queryBuilderRules", queryBuilderRules);
|
||||||
|
}
|
||||||
|
body.put(PARAM_HITS_PER_PAGE, hitsPerPage);
|
||||||
|
|
||||||
|
// VIVO OpenSocial Extension by UCSF
|
||||||
|
try {
|
||||||
|
OpenSocialManager openSocialManager = new OpenSocialManager(vreq, "search");
|
||||||
|
// put list of people found onto pubsub channel
|
||||||
|
// only turn this on for a people only search
|
||||||
|
if ("http://vivoweb.org/ontology#vitroClassGrouppeople".equals(vreq.getParameter(PARAM_CLASSGROUP))) {
|
||||||
|
List<String> ids = OpenSocialManager.getOpenSocialId(individuals);
|
||||||
|
openSocialManager.setPubsubData(OpenSocialManager.JSON_PERSONID_CHANNEL,
|
||||||
|
OpenSocialManager.buildJSONPersonIds(ids, "" + ids.size() + " people found"));
|
||||||
|
}
|
||||||
|
// TODO put this in a better place to guarantee that it gets called at the proper time!
|
||||||
|
openSocialManager.removePubsubGadgetsWithoutData();
|
||||||
|
body.put("openSocial", openSocialManager);
|
||||||
|
if (openSocialManager.isVisible()) {
|
||||||
|
body.put("bodyOnload", "my.init();");
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("IOException in doTemplate()", e);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
log.error("SQLException in doTemplate()", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
String template = templateTable.get(format).get(Result.PAGED);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return new TemplateResponseValues(template, body);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
return doSearchError(e,format);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getQueryBuilderRules(VitroRequest vreq) {
|
||||||
|
String rules = null;
|
||||||
|
try {
|
||||||
|
rules = vreq.getParameter("queryBuilderRules");
|
||||||
|
} catch (Throwable e) {
|
||||||
|
log.error(e);
|
||||||
|
}
|
||||||
|
return rules;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getHitsPerPage(VitroRequest vreq) {
|
||||||
|
int hitsPerPage = DEFAULT_HITS_PER_PAGE;
|
||||||
|
try{
|
||||||
|
hitsPerPage = Integer.parseInt(vreq.getParameter(PARAM_HITS_PER_PAGE));
|
||||||
|
} catch (Throwable e) {
|
||||||
|
hitsPerPage = DEFAULT_HITS_PER_PAGE;
|
||||||
|
}
|
||||||
|
log.debug("hitsPerPage is " + hitsPerPage);
|
||||||
|
return hitsPerPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getStartIndex(VitroRequest vreq) {
|
||||||
|
int startIndex = 0;
|
||||||
|
try{
|
||||||
|
startIndex = Integer.parseInt(vreq.getParameter(PARAM_START_INDEX));
|
||||||
|
}catch (Throwable e) {
|
||||||
|
startIndex = 0;
|
||||||
|
}
|
||||||
|
log.debug("startIndex is " + startIndex);
|
||||||
|
return startIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String badQueryText(String qtxt, VitroRequest vreq) {
|
||||||
|
if( qtxt == null || "".equals( qtxt.trim() ) )
|
||||||
|
return I18n.text(vreq, "enter_search_term");
|
||||||
|
|
||||||
|
if( qtxt.equals("*:*") )
|
||||||
|
return I18n.text(vreq, "invalid_search_term") ;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the class groups represented for the individuals in the documents.
|
||||||
|
*/
|
||||||
|
private List<VClassGroupSearchLink> getClassGroupsLinks(VitroRequest vreq, VClassGroupDao grpDao, SearchResultDocumentList docs, SearchResponse rsp, String qtxt) {
|
||||||
|
Map<String,Long> cgURItoCount = new HashMap<String,Long>();
|
||||||
|
|
||||||
|
List<VClassGroup> classgroups = new ArrayList<VClassGroup>( );
|
||||||
|
List<SearchFacetField> ffs = rsp.getFacetFields();
|
||||||
|
for(SearchFacetField ff : ffs){
|
||||||
|
if(VitroSearchTermNames.CLASSGROUP_URI.equals(ff.getName())){
|
||||||
|
List<Count> counts = ff.getValues();
|
||||||
|
for( Count ct: counts){
|
||||||
|
VClassGroup vcg = grpDao.getGroupByURI( ct.getName() );
|
||||||
|
if( vcg == null ){
|
||||||
|
log.debug("could not get classgroup for URI " + ct.getName());
|
||||||
|
}else{
|
||||||
|
classgroups.add(vcg);
|
||||||
|
cgURItoCount.put(vcg.getURI(), ct.getCount());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
grpDao.sortGroupList(classgroups);
|
||||||
|
|
||||||
|
VClassGroupsForRequest vcgfr = VClassGroupCache.getVClassGroups(vreq);
|
||||||
|
List<VClassGroupSearchLink> classGroupLinks = new ArrayList<VClassGroupSearchLink>(classgroups.size());
|
||||||
|
for (VClassGroup vcg : classgroups) {
|
||||||
|
String groupURI = vcg.getURI();
|
||||||
|
VClassGroup localizedVcg = vcgfr.getGroup(groupURI);
|
||||||
|
long count = cgURItoCount.get( groupURI );
|
||||||
|
if (localizedVcg.getPublicName() != null && count > 0 ) {
|
||||||
|
classGroupLinks.add(new VClassGroupSearchLink(qtxt, localizedVcg, count));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return classGroupLinks;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<VClassSearchLink> getVClassLinks(VClassDao vclassDao, SearchResultDocumentList docs, SearchResponse rsp, String qtxt){
|
||||||
|
HashSet<String> typesInHits = getVClassUrisForHits(docs);
|
||||||
|
List<VClass> classes = new ArrayList<VClass>(typesInHits.size());
|
||||||
|
Map<String,Long> typeURItoCount = new HashMap<String,Long>();
|
||||||
|
|
||||||
|
List<SearchFacetField> ffs = rsp.getFacetFields();
|
||||||
|
for(SearchFacetField ff : ffs){
|
||||||
|
if(VitroSearchTermNames.RDFTYPE.equals(ff.getName())){
|
||||||
|
List<Count> counts = ff.getValues();
|
||||||
|
for( Count ct: counts){
|
||||||
|
String typeUri = ct.getName();
|
||||||
|
long count = ct.getCount();
|
||||||
|
try{
|
||||||
|
if( VitroVocabulary.OWL_THING.equals(typeUri) ||
|
||||||
|
count == 0 )
|
||||||
|
continue;
|
||||||
|
VClass type = vclassDao.getVClassByURI(typeUri);
|
||||||
|
if( type != null &&
|
||||||
|
! type.isAnonymous() &&
|
||||||
|
type.getName() != null && !"".equals(type.getName()) &&
|
||||||
|
type.getGroupURI() != null ){ //don't display classes that aren't in classgroups
|
||||||
|
typeURItoCount.put(typeUri,count);
|
||||||
|
classes.add(type);
|
||||||
|
}
|
||||||
|
}catch(Exception ex){
|
||||||
|
if( log.isDebugEnabled() )
|
||||||
|
log.debug("could not add type " + typeUri, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
classes.sort(new Comparator<VClass>() {
|
||||||
|
public int compare(VClass o1, VClass o2) {
|
||||||
|
return o1.compareTo(o2);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
List<VClassSearchLink> vClassLinks = new ArrayList<VClassSearchLink>(classes.size());
|
||||||
|
for (VClass vc : classes) {
|
||||||
|
long count = typeURItoCount.get(vc.getURI());
|
||||||
|
vClassLinks.add(new VClassSearchLink(qtxt, vc, count ));
|
||||||
|
}
|
||||||
|
|
||||||
|
return vClassLinks;
|
||||||
|
}
|
||||||
|
|
||||||
|
private HashSet<String> getVClassUrisForHits(SearchResultDocumentList docs){
|
||||||
|
HashSet<String> typesInHits = new HashSet<String>();
|
||||||
|
for (SearchResultDocument doc : docs) {
|
||||||
|
try {
|
||||||
|
Collection<Object> types = doc.getFieldValues(VitroSearchTermNames.RDFTYPE);
|
||||||
|
if (types != null) {
|
||||||
|
for (Object o : types) {
|
||||||
|
String typeUri = o.toString();
|
||||||
|
typesInHits.add(typeUri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("problems getting rdf:type for search hits",e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return typesInHits;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getSnippet(SearchResultDocument doc, SearchResponse response) {
|
||||||
|
String docId = doc.getStringValue(VitroSearchTermNames.DOCID);
|
||||||
|
StringBuilder text = new StringBuilder();
|
||||||
|
Map<String, Map<String, List<String>>> highlights = response.getHighlighting();
|
||||||
|
if (highlights != null && highlights.get(docId) != null) {
|
||||||
|
List<String> snippets = highlights.get(docId).get(VitroSearchTermNames.ALLTEXT);
|
||||||
|
if (snippets != null && snippets.size() > 0) {
|
||||||
|
text.append("... ").append(snippets.get(0)).append(" ...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return text.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private SearchQuery getQuery(String queryText, int hitsPerPage, int startIndex, VitroRequest vreq) {
|
||||||
|
// Lowercase the search term to support wildcard searches: The search engine applies no text
|
||||||
|
// processing to a wildcard search term.
|
||||||
|
SearchQuery query = ApplicationUtils.instance().getSearchEngine().createQuery(queryText);
|
||||||
|
|
||||||
|
query.setStart( startIndex )
|
||||||
|
.setRows(hitsPerPage);
|
||||||
|
|
||||||
|
// ClassGroup filtering param
|
||||||
|
String classgroupParam = vreq.getParameter(PARAM_CLASSGROUP);
|
||||||
|
|
||||||
|
// rdf:type filtering param
|
||||||
|
String typeParam = vreq.getParameter(PARAM_RDFTYPE);
|
||||||
|
|
||||||
|
if ( ! StringUtils.isBlank(classgroupParam) ) {
|
||||||
|
// ClassGroup filtering
|
||||||
|
log.debug("Firing classgroup query ");
|
||||||
|
log.debug("request.getParameter(classgroup) is "+ classgroupParam);
|
||||||
|
query.addFilterQuery(VitroSearchTermNames.CLASSGROUP_URI + ":\"" + classgroupParam + "\"");
|
||||||
|
|
||||||
|
//with ClassGroup filtering we want type facets
|
||||||
|
query.addFacetFields(VitroSearchTermNames.RDFTYPE).setFacetLimit(-1);
|
||||||
|
|
||||||
|
}else if ( ! StringUtils.isBlank(typeParam) ) {
|
||||||
|
// rdf:type filtering
|
||||||
|
log.debug("Firing type query ");
|
||||||
|
log.debug("request.getParameter(type) is "+ typeParam);
|
||||||
|
query.addFilterQuery(VitroSearchTermNames.RDFTYPE + ":\"" + typeParam + "\"");
|
||||||
|
//with type filtering we don't have facets.
|
||||||
|
}else{
|
||||||
|
//When no filtering is set, we want ClassGroup facets
|
||||||
|
query.addFacetFields(VitroSearchTermNames.CLASSGROUP_URI).setFacetLimit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug("Query = " + query.toString());
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class VClassGroupSearchLink extends LinkTemplateModel {
|
||||||
|
long count = 0;
|
||||||
|
VClassGroupSearchLink(String querytext, VClassGroup classgroup, long count) {
|
||||||
|
super(classgroup.getPublicName(), EXTENDEDSEARCH, PARAM_QUERY_TEXT, querytext, PARAM_CLASSGROUP, classgroup.getURI());
|
||||||
|
this.count = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCount() { return Long.toString(count); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class VClassSearchLink extends LinkTemplateModel {
|
||||||
|
long count = 0;
|
||||||
|
VClassSearchLink(String querytext, VClass type, long count) {
|
||||||
|
super(type.getName(), EXTENDEDSEARCH, PARAM_QUERY_TEXT, querytext, PARAM_RDFTYPE, type.getURI());
|
||||||
|
this.count = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCount() { return Long.toString(count); }
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static List<PagingLink> getPagingLinks(int startIndex, int hitsPerPage, long hitCount, String baseUrl, ParamMap params, VitroRequest vreq) {
|
||||||
|
|
||||||
|
List<PagingLink> pagingLinks = new ArrayList<PagingLink>();
|
||||||
|
|
||||||
|
// No paging links if only one page of results
|
||||||
|
if (hitCount <= hitsPerPage) {
|
||||||
|
return pagingLinks;
|
||||||
|
}
|
||||||
|
|
||||||
|
int maxHitCount = DEFAULT_MAX_HIT_COUNT ;
|
||||||
|
if( startIndex >= DEFAULT_MAX_HIT_COUNT - hitsPerPage )
|
||||||
|
maxHitCount = startIndex + DEFAULT_MAX_HIT_COUNT ;
|
||||||
|
|
||||||
|
for (int i = 0; i < hitCount; i += hitsPerPage) {
|
||||||
|
params.put(PARAM_START_INDEX, String.valueOf(i));
|
||||||
|
if ( i < maxHitCount - hitsPerPage) {
|
||||||
|
int pageNumber = i/hitsPerPage + 1;
|
||||||
|
boolean iIsCurrentPage = (i >= startIndex && i < (startIndex + hitsPerPage));
|
||||||
|
if ( iIsCurrentPage ) {
|
||||||
|
pagingLinks.add(new PagingLink(pageNumber));
|
||||||
|
} else {
|
||||||
|
pagingLinks.add(new PagingLink(pageNumber, baseUrl, params));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pagingLinks.add(new PagingLink(I18n.text(vreq, "paging_link_more"), baseUrl, params));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pagingLinks;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getPreviousPageLink(int startIndex, int hitsPerPage, String baseUrl, ParamMap params) {
|
||||||
|
params.put(PARAM_START_INDEX, String.valueOf(startIndex-hitsPerPage));
|
||||||
|
return UrlBuilder.getUrl(baseUrl, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getNextPageLink(int startIndex, int hitsPerPage, String baseUrl, ParamMap params) {
|
||||||
|
params.put(PARAM_START_INDEX, String.valueOf(startIndex+hitsPerPage));
|
||||||
|
return UrlBuilder.getUrl(baseUrl, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static class PagingLink extends LinkTemplateModel {
|
||||||
|
|
||||||
|
PagingLink(int pageNumber, String baseUrl, ParamMap params) {
|
||||||
|
super(String.valueOf(pageNumber), baseUrl, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructor for current page item: not a link, so no url value.
|
||||||
|
PagingLink(int pageNumber) {
|
||||||
|
setText(String.valueOf(pageNumber));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructor for "more..." item
|
||||||
|
PagingLink(String text, String baseUrl, ParamMap params) {
|
||||||
|
super(text, baseUrl, params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ExceptionResponseValues doSearchError(Throwable e, Format f) {
|
||||||
|
Map<String, Object> body = new HashMap<String, Object>();
|
||||||
|
body.put("message", "Search failed: " + e.getMessage());
|
||||||
|
return new ExceptionResponseValues(getTemplate(f,Result.ERROR), body, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TemplateResponseValues doFailedSearch(String message, String querytext, Format f, VitroRequest vreq) {
|
||||||
|
Map<String, Object> body = new HashMap<String, Object>();
|
||||||
|
body.put("title", I18n.text(vreq, "search_for", querytext));
|
||||||
|
if ( StringUtils.isEmpty(message) ) {
|
||||||
|
message = I18n.text(vreq, "search_failed");
|
||||||
|
}
|
||||||
|
body.put("message", message);
|
||||||
|
return new TemplateResponseValues(getTemplate(f,Result.ERROR), body);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TemplateResponseValues doNoHits(String querytext, Format f, VitroRequest vreq) {
|
||||||
|
Map<String, Object> body = new HashMap<String, Object>();
|
||||||
|
body.put("title", I18n.text(vreq, "search_for", querytext));
|
||||||
|
body.put("message", I18n.text(vreq, "no_matching_results"));
|
||||||
|
return new TemplateResponseValues(getTemplate(f,Result.ERROR), body);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes a message to display to user for a bad search term.
|
||||||
|
*/
|
||||||
|
private String makeBadSearchMessage(String querytext, String exceptionMsg, VitroRequest vreq){
|
||||||
|
String rv = "";
|
||||||
|
try{
|
||||||
|
//try to get the column in the search term that is causing the problems
|
||||||
|
int coli = exceptionMsg.indexOf("column");
|
||||||
|
if( coli == -1) return "";
|
||||||
|
int numi = exceptionMsg.indexOf(".", coli+7);
|
||||||
|
if( numi == -1 ) return "";
|
||||||
|
String part = exceptionMsg.substring(coli+7,numi );
|
||||||
|
int i = Integer.parseInt(part) - 1;
|
||||||
|
|
||||||
|
// figure out where to cut preview and post-view
|
||||||
|
int errorWindow = 5;
|
||||||
|
int pre = i - errorWindow;
|
||||||
|
if (pre < 0)
|
||||||
|
pre = 0;
|
||||||
|
int post = i + errorWindow;
|
||||||
|
if (post > querytext.length())
|
||||||
|
post = querytext.length();
|
||||||
|
// log.warn("pre: " + pre + " post: " + post + " term len:
|
||||||
|
// " + term.length());
|
||||||
|
|
||||||
|
// get part of the search term before the error and after
|
||||||
|
String before = querytext.substring(pre, i);
|
||||||
|
String after = "";
|
||||||
|
if (post > i)
|
||||||
|
after = querytext.substring(i + 1, post);
|
||||||
|
|
||||||
|
rv = I18n.text(vreq, "search_term_error_near") +
|
||||||
|
" <span class='searchQuote'>"
|
||||||
|
+ before + "<span class='searchError'>" + querytext.charAt(i)
|
||||||
|
+ "</span>" + after + "</span>";
|
||||||
|
} catch (Throwable ex) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final int MAX_QUERY_LENGTH = 500;
|
||||||
|
|
||||||
|
protected boolean isRequestedFormatXml(VitroRequest req){
|
||||||
|
if( req != null ){
|
||||||
|
String param = req.getParameter(PARAM_XML_REQUEST);
|
||||||
|
return param != null && "1".equals(param);
|
||||||
|
}else{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isRequestedFormatCSV(VitroRequest req){
|
||||||
|
if( req != null ){
|
||||||
|
String param = req.getParameter(PARAM_CSV_REQUEST);
|
||||||
|
return param != null && "1".equals(param);
|
||||||
|
}else{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Format getFormat(VitroRequest req){
|
||||||
|
if( req != null && req.getParameter("xml") != null && "1".equals(req.getParameter("xml")))
|
||||||
|
return Format.XML;
|
||||||
|
else if ( req != null && req.getParameter("csv") != null && "1".equals(req.getParameter("csv")))
|
||||||
|
return Format.CSV;
|
||||||
|
else
|
||||||
|
return Format.HTML;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static String getTemplate(Format format, Result result){
|
||||||
|
if( format != null && result != null)
|
||||||
|
return templateTable.get(format).get(result);
|
||||||
|
else{
|
||||||
|
log.error("getTemplate() must not have a null format or result.");
|
||||||
|
return templateTable.get(Format.HTML).get(Result.ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static Map<Format,Map<Result,String>> setupTemplateTable(){
|
||||||
|
Map<Format,Map<Result,String>> table = new HashMap<>();
|
||||||
|
|
||||||
|
HashMap<Result,String> resultsToTemplates = new HashMap<Result,String>();
|
||||||
|
|
||||||
|
// set up HTML format
|
||||||
|
resultsToTemplates.put(Result.PAGED, "extendedsearch-pagedResults.ftl");
|
||||||
|
resultsToTemplates.put(Result.ERROR, "extendedsearch-error.ftl");
|
||||||
|
// resultsToTemplates.put(Result.BAD_QUERY, "search-badQuery.ftl");
|
||||||
|
table.put(Format.HTML, Collections.unmodifiableMap(resultsToTemplates));
|
||||||
|
|
||||||
|
// set up XML format
|
||||||
|
resultsToTemplates = new HashMap<Result,String>();
|
||||||
|
resultsToTemplates.put(Result.PAGED, "extendedsearch-xmlResults.ftl");
|
||||||
|
resultsToTemplates.put(Result.ERROR, "extendedsearch-xmlError.ftl");
|
||||||
|
|
||||||
|
// resultsToTemplates.put(Result.BAD_QUERY, "search-xmlBadQuery.ftl");
|
||||||
|
table.put(Format.XML, Collections.unmodifiableMap(resultsToTemplates));
|
||||||
|
|
||||||
|
|
||||||
|
// set up CSV format
|
||||||
|
resultsToTemplates = new HashMap<Result,String>();
|
||||||
|
resultsToTemplates.put(Result.PAGED, "extendedsearch-csvResults.ftl");
|
||||||
|
resultsToTemplates.put(Result.ERROR, "extendedsearch-csvError.ftl");
|
||||||
|
|
||||||
|
// resultsToTemplates.put(Result.BAD_QUERY, "search-xmlBadQuery.ftl");
|
||||||
|
table.put(Format.CSV, Collections.unmodifiableMap(resultsToTemplates));
|
||||||
|
|
||||||
|
|
||||||
|
return Collections.unmodifiableMap(table);
|
||||||
|
}
|
||||||
|
}
|
77
webapp/src/main/webapp/js/search/query-builder.ru.js
Normal file
77
webapp/src/main/webapp/js/search/query-builder.ru.js
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
/*!
|
||||||
|
* jQuery QueryBuilder 2.5.2
|
||||||
|
* Locale: Russian (ru)
|
||||||
|
* Licensed under MIT (https://opensource.org/licenses/MIT)
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function(root, factory) {
|
||||||
|
if (typeof define == 'function' && define.amd) {
|
||||||
|
define(['jquery', 'query-builder'], factory);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
factory(root.jQuery);
|
||||||
|
}
|
||||||
|
}(this, function($) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var QueryBuilder = $.fn.queryBuilder;
|
||||||
|
|
||||||
|
QueryBuilder.regional['ru'] = {
|
||||||
|
"__locale": "Russian (ru)",
|
||||||
|
"add_rule": "Добавить условие",
|
||||||
|
"add_group": "Добавить группу",
|
||||||
|
"delete_rule": "Удалить",
|
||||||
|
"delete_group": "Удалить",
|
||||||
|
"conditions": {
|
||||||
|
"AND": "И",
|
||||||
|
"OR": "ИЛИ"
|
||||||
|
},
|
||||||
|
"operators": {
|
||||||
|
"equal": "равно",
|
||||||
|
"not_equal": "не равно",
|
||||||
|
"in": "из указанных",
|
||||||
|
"not_in": "не из указанных",
|
||||||
|
"less": "меньше",
|
||||||
|
"less_or_equal": "меньше или равно",
|
||||||
|
"greater": "больше",
|
||||||
|
"greater_or_equal": "больше или равно",
|
||||||
|
"between": "между",
|
||||||
|
"begins_with": "начинается с",
|
||||||
|
"not_begins_with": "не начинается с",
|
||||||
|
"contains": "содержит",
|
||||||
|
"not_contains": "не содержит",
|
||||||
|
"ends_with": "оканчивается на",
|
||||||
|
"not_ends_with": "не оканчивается на",
|
||||||
|
"is_empty": "пустая строка",
|
||||||
|
"is_not_empty": "не пустая строка",
|
||||||
|
"is_null": "пусто",
|
||||||
|
"is_not_null": "не пусто"
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"no_filter": "Фильтр не выбран",
|
||||||
|
"empty_group": "Группа пуста",
|
||||||
|
"radio_empty": "Не выбранно значение",
|
||||||
|
"checkbox_empty": "Не выбранно значение",
|
||||||
|
"select_empty": "Не выбранно значение",
|
||||||
|
"string_empty": "Не заполненно",
|
||||||
|
"string_exceed_min_length": "Должен содержать больше {0} символов",
|
||||||
|
"string_exceed_max_length": "Должен содержать меньше {0} символов",
|
||||||
|
"string_invalid_format": "Неверный формат ({0})",
|
||||||
|
"number_nan": "Не число",
|
||||||
|
"number_not_integer": "Не число",
|
||||||
|
"number_not_double": "Не число",
|
||||||
|
"number_exceed_min": "Должно быть больше {0}",
|
||||||
|
"number_exceed_max": "Должно быть меньше, чем {0}",
|
||||||
|
"number_wrong_step": "Должно быть кратно {0}",
|
||||||
|
"datetime_empty": "Не заполненно",
|
||||||
|
"datetime_invalid": "Неверный формат даты ({0})",
|
||||||
|
"datetime_exceed_min": "Должно быть, после {0}",
|
||||||
|
"datetime_exceed_max": "Должно быть, до {0}",
|
||||||
|
"boolean_not_valid": "Не логическое",
|
||||||
|
"operator_not_multiple": "Оператор \"{1}\" не поддерживает много значений"
|
||||||
|
},
|
||||||
|
"invert": "Инвертировать"
|
||||||
|
};
|
||||||
|
|
||||||
|
QueryBuilder.defaults({ lang_code: 'ru' });
|
||||||
|
}));
|
6477
webapp/src/main/webapp/js/search/query-builder.standalone.js
Normal file
6477
webapp/src/main/webapp/js/search/query-builder.standalone.js
Normal file
File diff suppressed because it is too large
Load diff
7
webapp/src/main/webapp/js/search/query-builder.standalone.min.js
vendored
Normal file
7
webapp/src/main/webapp/js/search/query-builder.standalone.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,16 @@
|
||||||
|
<#-- $This file is distributed under the terms of the license in LICENSE$ -->
|
||||||
|
|
||||||
|
<#-- Template for displaying search error message -->
|
||||||
|
<#include "queryBuilder.ftl">
|
||||||
|
|
||||||
|
<#if title??>
|
||||||
|
<div class="errorPageTitle">
|
||||||
|
<h2>${title?html}</h2>
|
||||||
|
</div>
|
||||||
|
</#if>
|
||||||
|
<div id="nomatchingTitle">
|
||||||
|
<p>
|
||||||
|
${message?html}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<#include "search-help.ftl" >
|
|
@ -0,0 +1,251 @@
|
||||||
|
<#-- $This file is distributed under the terms of the license in LICENSE$ -->
|
||||||
|
|
||||||
|
<#-- Template for displaying paged search results -->
|
||||||
|
<#include "queryBuilder.ftl">
|
||||||
|
|
||||||
|
<h2 class="searchResultsHeader">
|
||||||
|
|
||||||
|
<#escape x as x?html>
|
||||||
|
<div id='searchQueryResults'> ${i18n().search_results_for} '${querytext}'</div>
|
||||||
|
<div id='limitedToClassGroup'> <#if classGroupName?has_content>${i18n().limited_to_type} '${classGroupName}'</#if> </div>
|
||||||
|
<div id='limitedToType'> <#if typeName?has_content>${i18n().limited_to_type} '${typeName}'</#if> </div>
|
||||||
|
</#escape>
|
||||||
|
<script type="text/javascript">
|
||||||
|
var url = window.location.toString();
|
||||||
|
if (url.indexOf("?") == -1){
|
||||||
|
var queryText = 'querytext=${querytext}';
|
||||||
|
} else {
|
||||||
|
var urlArray = url.split("?");
|
||||||
|
var queryText = urlArray[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
var urlsBase = '${urls.base}';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<img id="downloadIcon" src="images/download-icon.png" alt="${i18n().download_results}" title="${i18n().download_results}" />
|
||||||
|
<#-- <span id="downloadResults" style="float:left"></span> -->
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<span id="searchHelp"><a href="${urls.base}/searchHelp" title="${i18n().search_help}">${i18n().not_expected_results}</a></span>
|
||||||
|
<div class="contentsBrowseGroup">
|
||||||
|
|
||||||
|
<#-- Refinement links -->
|
||||||
|
<#if classGroupLinks?has_content && classGroupLinks?size gt 1>
|
||||||
|
<div class="searchTOC">
|
||||||
|
<h4>${i18n().display_only}</h4>
|
||||||
|
<ul>
|
||||||
|
<#list classGroupLinks as link>
|
||||||
|
<li><a href="${link.url}" title="${i18n().class_group_link}">${link.text}</a><span>(${link.count})</span></li>
|
||||||
|
</#list>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#if classLinks?has_content && classLinks?size gt 1 >
|
||||||
|
<div class="searchTOC">
|
||||||
|
<#if classGroupName?has_content>
|
||||||
|
<h4>${i18n().limit} ${classGroupName} ${i18n().to}</h4>
|
||||||
|
<#else>
|
||||||
|
<h4>${i18n().limit_to}</h4>
|
||||||
|
</#if>
|
||||||
|
<ul>
|
||||||
|
<#list classLinks as link>
|
||||||
|
<li><a href="${link.url}" title="${i18n().class_link}">${link.text}</a><span>(${link.count})</span></li>
|
||||||
|
</#list>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="virtualArticleSwitch">
|
||||||
|
<label class="switch">${i18n().show_virtual_article}
|
||||||
|
<input id="virtualArticleCheck" type="checkbox" checked="false" onclick="showVirtualArticles();">
|
||||||
|
</label>
|
||||||
|
<#if user.loggedIn>
|
||||||
|
<button onclick="createNewCompilation()">${i18n().create_compilation_button}</button>
|
||||||
|
</#if>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<#-- Search results -->
|
||||||
|
<ul class="searchhits">
|
||||||
|
<#list individuals as individual>
|
||||||
|
<li>
|
||||||
|
<@shortView uri=individual.uri viewContext="search" />
|
||||||
|
</li>
|
||||||
|
</#list>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
<#-- Paging controls -->
|
||||||
|
<#if (pagingLinks?size > 0)>
|
||||||
|
<div class="searchpages">
|
||||||
|
${i18n().pages}:
|
||||||
|
<#if prevPage??><a class="prev" href="${prevPage}" title="${i18n().previous}">${i18n().previous}</a></#if>
|
||||||
|
<#list pagingLinks as link>
|
||||||
|
<#if link.url??>
|
||||||
|
<a href="${link.url}" title="${i18n().page_link}">${link.text}</a>
|
||||||
|
<#else>
|
||||||
|
<span>${link.text}</span> <#-- no link if current page -->
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
<#if nextPage??><a class="next" href="${nextPage}" title="${i18n().next_capitalized}">${i18n().next_capitalized}</a></#if>
|
||||||
|
</div>
|
||||||
|
</#if>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<#-- VIVO OpenSocial Extension by UCSF -->
|
||||||
|
<#if openSocial??>
|
||||||
|
<#if openSocial.visible>
|
||||||
|
<h3>OpenSocial</h3>
|
||||||
|
<script type="text/javascript" language="javascript">
|
||||||
|
// find the 'Search' gadget(s).
|
||||||
|
var searchGadgets = my.findGadgetsAttachingTo("gadgets-search");
|
||||||
|
var keyword = '${querytext}';
|
||||||
|
// add params to these gadgets
|
||||||
|
if (keyword) {
|
||||||
|
for (var i = 0; i < searchGadgets.length; i++) {
|
||||||
|
var searchGadget = searchGadgets[i];
|
||||||
|
searchGadget.additionalParams = searchGadget.additionalParams || {};
|
||||||
|
searchGadget.additionalParams["keyword"] = keyword;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else { // remove these gadgets
|
||||||
|
my.removeGadgets(searchGadgets);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div id="gadgets-search" class="gadgets-gadget-parent" style="display:inline-block"></div>
|
||||||
|
</#if>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
</div> <!-- end contentsBrowseGroup -->
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', createVirtualCompilation(), false);
|
||||||
|
|
||||||
|
$('input[type=checkbox]').removeAttr('checked');
|
||||||
|
function showVirtualArticles(){
|
||||||
|
var checkBox = document.getElementById("virtualArticleCheck");
|
||||||
|
if (checkBox.checked == true){
|
||||||
|
$('.searchResult').hide();
|
||||||
|
$('.virtualArticlePart').show();
|
||||||
|
} else {
|
||||||
|
$('.searchResult').show();
|
||||||
|
$('.virtualArticlePart').hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createNewCompilation() {
|
||||||
|
var excerpts = $('.compilationDraftExcerpt').toArray();
|
||||||
|
if (excerpts.length == 0){
|
||||||
|
alert("${i18n().create_compilation_no_excerpts}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var compilationName = window.prompt("${i18n().create_compilation_enter_name_notification}");
|
||||||
|
if (!compilationName){
|
||||||
|
alert("${i18n().create_compilation_no_name_entered_error}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var iframe = document.createElement("iframe");
|
||||||
|
var excerptsCounter = $('.compilationDraftExcerpt').length;
|
||||||
|
iframe.setAttribute("src", "${urls.base}/editRequestDispatch?typeOfNew=https%3A%2F%2Flitvinovg.pro%2Ftext_structures%23compilation&editForm=edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.generators.CompilationGenerator&excerptsCount=" + excerptsCounter);
|
||||||
|
iframe.style.width = "1px";
|
||||||
|
iframe.style.height = "1px";
|
||||||
|
iframe.id="newCompilationIframe";
|
||||||
|
//iframe.style.display="none";
|
||||||
|
document.body.appendChild(iframe);
|
||||||
|
$('#newCompilationIframe').on('load', function(){
|
||||||
|
fillOutForm(compilationName);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function fillOutForm(compilationName){
|
||||||
|
var iframeDoc = document.getElementById('newCompilationIframe').contentWindow.document;
|
||||||
|
var rules = $('#builder').queryBuilder('getRules', { get_flags: true });
|
||||||
|
var query = format_query_string(rules, "", false);
|
||||||
|
iframeDoc.getElementById('queryBuilderRules').value = JSON.stringify(rules);
|
||||||
|
iframeDoc.getElementById('rawQueryString').value = query;
|
||||||
|
|
||||||
|
|
||||||
|
iframeDoc.getElementById('newCompilationLabel').value = compilationName;
|
||||||
|
var excerpts = $('.compilationDraftExcerpt').toArray();
|
||||||
|
for (i = 0;i < excerpts.length;i++){
|
||||||
|
var excerptUri = excerpts[i].getAttribute('partUri');
|
||||||
|
var excerptName = excerpts[i].getAttribute('partName');
|
||||||
|
var number = i + 1;
|
||||||
|
iframeDoc.getElementById("tocLevel" + number + "Name").value = excerptName + " (" + compilationName + ")";
|
||||||
|
iframeDoc.getElementById("tocItem" + number + "Name").value = excerptName + " (" + compilationName + ")";
|
||||||
|
iframeDoc.getElementById("excerpt" + number).value = excerptUri;
|
||||||
|
}
|
||||||
|
$('#newCompilationIframe').off('load');
|
||||||
|
iframeDoc.getElementById('submit').click();
|
||||||
|
$('#newCompilationIframe').on('load', function(){
|
||||||
|
redirectToNewCompilation();
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
function redirectToNewCompilation(){
|
||||||
|
var newURL = document.getElementById('newCompilationIframe').contentWindow.location.href;
|
||||||
|
window.open(newURL,"_self");
|
||||||
|
}
|
||||||
|
|
||||||
|
function createVirtualCompilation(){
|
||||||
|
let workSet = new Set();
|
||||||
|
let biblioSet = new Set();
|
||||||
|
var workDivs = $('.virtualArticleWork');
|
||||||
|
var biblioDivs = $('.virtualArticleBibliography');
|
||||||
|
biblioDivs.each(function() {
|
||||||
|
biblioSet.add($(this).html());
|
||||||
|
});
|
||||||
|
workDivs.each(function() {
|
||||||
|
workSet.add($(this).html());
|
||||||
|
});
|
||||||
|
var workArr = Array.from(workSet);
|
||||||
|
workArr.sort();
|
||||||
|
var biblioArr = Array.from(biblioSet);
|
||||||
|
biblioArr.sort();
|
||||||
|
if (workArr.length > 0 ) {
|
||||||
|
$('<div class="virtualWorks virtualArticlePart"><button type="button" style="border:none;width: 100%; text-align:left;" class="collapsible">${i18n().sources_excerpt_button_text}</button><div class="virtualWorks"></div></div>').insertAfter($('.virtualArticlePart').last());
|
||||||
|
for (let value of workArr){
|
||||||
|
$('.virtualWorks').last().append( '<div class="work"><p>' + value + '</p></div>' );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (biblioArr.length > 0 ) {
|
||||||
|
$('<div class="virtualBibliography virtualArticlePart"><button type="button" style="border:none;width: 100%; text-align:left;" class="collapsible">${i18n().literature_excerpt_button_text}</button><div class="virtualBibliography"></div></div>').insertAfter($('.virtualArticlePart').last());
|
||||||
|
for (let value of biblioArr){
|
||||||
|
$('.virtualBibliography').last().append( '<div class="bibliography"><p>' + value + '</p></div>' );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$('.virtualWorks').hide();
|
||||||
|
$('.virtualBibliography').hide();
|
||||||
|
$('.virtualArticlePart').hide();
|
||||||
|
var coll = document.getElementsByClassName("collapsible");
|
||||||
|
var i;
|
||||||
|
for (i = 0; i < coll.length; i++) {
|
||||||
|
coll[i].addEventListener("click", function() {
|
||||||
|
this.classList.toggle("active");
|
||||||
|
var content = this.nextElementSibling;
|
||||||
|
if (content.style.display === "block") {
|
||||||
|
content.style.display = "none";
|
||||||
|
} else {
|
||||||
|
content.style.display = "block";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
createRemoveButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
${stylesheets.add('<link rel="stylesheet" href="//code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" />',
|
||||||
|
'<link rel="stylesheet" href="${urls.base}/css/search.css" />',
|
||||||
|
'<link rel="stylesheet" type="text/css" href="${urls.base}/css/jquery_plugins/qtip/jquery.qtip.min.css" />')}
|
||||||
|
|
||||||
|
${headScripts.add('<script src="//code.jquery.com/ui/1.10.3/jquery-ui.js"></script>',
|
||||||
|
'<script type="text/javascript" src="${urls.base}/js/jquery_plugins/qtip/jquery.qtip.min.js"></script>',
|
||||||
|
'<script type="text/javascript" src="${urls.base}/js/tiny_mce/tiny_mce.js"></script>'
|
||||||
|
)}
|
||||||
|
|
||||||
|
${scripts.add('<script type="text/javascript" src="${urls.base}/js/searchDownload.js"></script>')}
|
|
@ -0,0 +1,279 @@
|
||||||
|
<div id="querybuilder-container">
|
||||||
|
<div id="CounterSearchWrapper">
|
||||||
|
<div id="builder">
|
||||||
|
<div id="SearchTitle">${i18n().extended_search_label}</div>
|
||||||
|
</div>
|
||||||
|
<div class="btn-group-bottom">
|
||||||
|
<div id="settingsButtons">
|
||||||
|
<div id="OuterWrapperButtons">
|
||||||
|
<div id="wrapperButtons">
|
||||||
|
<button id="btn-set" class="btn btn-success set-json" data-target="basic">${i18n().extended_search_example}</button>
|
||||||
|
<button id="btn-reset-button" class="btn btn-warning reset" data-target="basic">${i18n().extended_search_clean}</button>
|
||||||
|
<!-- <button id="btn-get" class="btn btn-primary parse-json" data-target="basic">Get rules</button> -->
|
||||||
|
<div id="SelectResults">
|
||||||
|
<label style="display:inline;" for="hitsPerPage">${i18n().extended_search_results_on_page}</label>
|
||||||
|
<@selectHitsPerPage/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button id="btn-search-expand" class="btn btn-warning reset" data-target="basic">${i18n().extended_search_execute_search}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src= "js/search/query-builder.standalone.min.js"></script>
|
||||||
|
<script src= "js/search/query-builder.ru.js"></script>
|
||||||
|
<script>
|
||||||
|
var rules_example =
|
||||||
|
<#if searchFields?has_content>
|
||||||
|
{
|
||||||
|
"condition": "AND",
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"id": "titles",
|
||||||
|
"field": "titles",
|
||||||
|
"type": "string",
|
||||||
|
"input": "text",
|
||||||
|
"operator": "not_contains",
|
||||||
|
"value": "постмодернизм"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"condition": "OR",
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"id": "keywords",
|
||||||
|
"field": "keywords",
|
||||||
|
"type": "string",
|
||||||
|
"input": "text",
|
||||||
|
"operator": "contains",
|
||||||
|
"value": "постмодернизм"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bibliography",
|
||||||
|
"field": "bibliography",
|
||||||
|
"type": "string",
|
||||||
|
"input": "text",
|
||||||
|
"operator": "contains",
|
||||||
|
"value": "постмодернизм"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"valid": true
|
||||||
|
};
|
||||||
|
<#else>
|
||||||
|
{
|
||||||
|
"condition": "AND",
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"id": "ALLTEXT",
|
||||||
|
"field": "everywhere",
|
||||||
|
"type": "string",
|
||||||
|
"input": "text",
|
||||||
|
"operator": "contains",
|
||||||
|
"value": "publication"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"valid": true
|
||||||
|
};
|
||||||
|
</#if>
|
||||||
|
var rules_start;
|
||||||
|
<#if queryBuilderRules??>
|
||||||
|
rules_start = ${queryBuilderRules};
|
||||||
|
<#else>
|
||||||
|
if (localStorage.getItem('queryBuilderFormSaved') === true || localStorage.getItem('queryBuilderFormSaved') === 'true') {
|
||||||
|
rules_start = JSON.parse(localStorage.getItem('queryBuilderForm'));
|
||||||
|
} else {
|
||||||
|
rules_start = rules_example;
|
||||||
|
}
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
|
||||||
|
$('#builder').queryBuilder({
|
||||||
|
filters: [
|
||||||
|
<#if searchFields?has_content>
|
||||||
|
<#list searchFields as field>
|
||||||
|
<#if field.hasFilters == "true">
|
||||||
|
<@multivalueField field=field />
|
||||||
|
<#else>
|
||||||
|
<@freeField field=field />
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
<#else>
|
||||||
|
{
|
||||||
|
id: 'ALLTEXT',
|
||||||
|
label: 'Everywhere',
|
||||||
|
type: 'string',
|
||||||
|
operators: ['contains', 'not_contains']
|
||||||
|
},
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
],
|
||||||
|
lang_code: 'ru',
|
||||||
|
rules: rules_start
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#btn-reset-button').on('click', function() {
|
||||||
|
$('#builder').queryBuilder('reset');
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#btn-set').on('click', function() {
|
||||||
|
$('#builder').queryBuilder('setRules', rules_example);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
$('#btn-search-expand').on('click', function() {
|
||||||
|
var json_result = $('#builder').queryBuilder('getRules', { get_flags: true });
|
||||||
|
var query_string = format_query_string(json_result,"");
|
||||||
|
var hits = $("#hitsPerPageSelect :selected");
|
||||||
|
if (!$.isEmptyObject(query_string)) {
|
||||||
|
localStorage.setItem('queryBuilderForm',JSON.stringify(json_result));
|
||||||
|
localStorage.setItem('queryBuilderFormSaved',true);
|
||||||
|
var queryURL = "${urls.extendedsearch}?querytext=" + query_string;
|
||||||
|
if (hits !== null){
|
||||||
|
queryURL = queryURL.concat("&hitsPerPage=",hits.text());
|
||||||
|
}
|
||||||
|
window.open(queryURL,"_self")
|
||||||
|
}
|
||||||
|
//if (!$.isEmptyObject(json_result)) {
|
||||||
|
// alert(JSON.stringify(json_result, null, 2));
|
||||||
|
// alert(query_string);
|
||||||
|
//}
|
||||||
|
});
|
||||||
|
|
||||||
|
function format_query_string(json_query, string_query, htmlEncode = true){
|
||||||
|
if ('condition' in json_query && 'rules' in json_query ){
|
||||||
|
if (json_query.rules.length > 1 ) {
|
||||||
|
string_query +=" ( ";
|
||||||
|
var i;
|
||||||
|
for (i = 0; i < json_query.rules.length; i++) {
|
||||||
|
string_query = format_query_string(json_query.rules[i], string_query, htmlEncode);
|
||||||
|
if (i + 1 < json_query.rules.length){
|
||||||
|
string_query += " " + json_query.condition + " ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
string_query +=" ) ";
|
||||||
|
} else {
|
||||||
|
string_query = format_query_string(json_query.rules[0], string_query, htmlEncode);
|
||||||
|
}
|
||||||
|
} else if ( 'field' in json_query && 'value' in json_query ){
|
||||||
|
if ('operator' in json_query && json_query.operator.startsWith("not_")){
|
||||||
|
string_query += "NOT ";
|
||||||
|
}
|
||||||
|
if (json_query.hasOwnProperty('data') && json_query.data.hasOwnProperty('value')){
|
||||||
|
var value = "\"" + json_query.data.value.toString()+ "\"";
|
||||||
|
} else {
|
||||||
|
var value = json_query.value.toString();
|
||||||
|
}
|
||||||
|
if (htmlEncode){
|
||||||
|
string_query += json_query.field + ":" + value.replace(/[']+/g,'').replace(/#/g,'%23') ;
|
||||||
|
} else {
|
||||||
|
string_query += json_query.field + ":" + value.replace(/[']+/g,'');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return string_query;
|
||||||
|
}
|
||||||
|
|
||||||
|
function excludeDocByURI(name, uri){
|
||||||
|
var allRules = $('#builder').queryBuilder('getRules', { get_flags: true });
|
||||||
|
var excludeRuleString = '{ "id": "URI", "field": "URI", "type": "string", "flags":{}, "input": "text", "operator": "not_contains", "data":{} }';
|
||||||
|
var excludeRule = JSON.parse(excludeRuleString);
|
||||||
|
excludeRule.data.value = uri;
|
||||||
|
excludeRule.flags.value_readonly = true;
|
||||||
|
excludeRule.flags.filter_readonly = true;
|
||||||
|
excludeRule.flags.operator_readonly = true;
|
||||||
|
excludeRule.value = name;
|
||||||
|
if (allRules !== null){
|
||||||
|
if (allRules.condition === "AND"){
|
||||||
|
allRules.rules.push(excludeRule);
|
||||||
|
} else {
|
||||||
|
var outerRulesString = '{ "condition": "AND", "rules": [] }';
|
||||||
|
var outerRules = JSON.parse(outerRulesString);
|
||||||
|
outerRules.rules.push(allRules);
|
||||||
|
outerRules.rules.push(excludeRule);
|
||||||
|
allRules = outerRules;
|
||||||
|
}
|
||||||
|
$('#builder').queryBuilder('setRules', allRules);
|
||||||
|
var elements = document.querySelectorAll('[parturi="' + uri + '"]');
|
||||||
|
var i;
|
||||||
|
for (i = 0; i < elements.length; i++) {
|
||||||
|
elements[i].parentElement.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createRemoveButtons(){
|
||||||
|
$('.compilationDraftExcerpt').each(function(index){ createRemoveButton(this)});
|
||||||
|
}
|
||||||
|
|
||||||
|
function createRemoveButton(element){
|
||||||
|
var uri = element.getAttribute('parturi');
|
||||||
|
var button = element.querySelector('button');
|
||||||
|
var name = button.textContent;
|
||||||
|
var a = document.createElement('a');
|
||||||
|
a.setAttribute('href',"javascript:excludeDocByURI(\'" + escapeQutes(name) + "\',\'" + escapeQutes(uri) + "\');");
|
||||||
|
a.setAttribute('class',"removeDocFromSearch");
|
||||||
|
|
||||||
|
a.textContent = "${i18n().remove_doc_from_search_results}" ;
|
||||||
|
|
||||||
|
button.appendChild(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
function escapeQutes(input) {
|
||||||
|
return input
|
||||||
|
.replace(/"/g, """)
|
||||||
|
.replace(/'/g, "'")
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<#macro freeField field >
|
||||||
|
{
|
||||||
|
id: '${field.field}',
|
||||||
|
label: '${field.name}',
|
||||||
|
type: 'string',
|
||||||
|
operators: ['contains', 'not_contains']
|
||||||
|
},
|
||||||
|
</#macro>
|
||||||
|
|
||||||
|
<#macro multivalueField field >
|
||||||
|
{
|
||||||
|
id: '${field.field}',
|
||||||
|
label: '${field.name}',
|
||||||
|
type: 'string',
|
||||||
|
input: 'select',
|
||||||
|
values: {
|
||||||
|
|
||||||
|
<#if searchFields??>
|
||||||
|
<#list searchFilters as filter>
|
||||||
|
<#if filter.field == field.field>
|
||||||
|
'"${filter.id}"':'${filter.name}',
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
<#else>
|
||||||
|
{
|
||||||
|
id: 'ALLTEXT',
|
||||||
|
label: 'Everywhere',
|
||||||
|
type: 'string',
|
||||||
|
operators: ['contains', 'not_contains']
|
||||||
|
},
|
||||||
|
</#if>
|
||||||
|
},
|
||||||
|
operators: ['contains', 'not_contains']
|
||||||
|
},
|
||||||
|
</#macro>
|
||||||
|
|
||||||
|
<#macro selectHitsPerPage>
|
||||||
|
<#if !hitsPerPage?? >
|
||||||
|
<#assign hitsPerPage = 20 >
|
||||||
|
</#if>
|
||||||
|
<#assign hitsValues= [20,40,60,80,100]>
|
||||||
|
<select name="hitsPerPage" id="hitsPerPageSelect">
|
||||||
|
<option value="${hitsPerPage}" selected="selected">${hitsPerPage}</option>
|
||||||
|
<#list hitsValues as hppValue>
|
||||||
|
<#if hppValue != hitsPerPage>
|
||||||
|
<option value="${hppValue}">${hppValue}</option>
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
|
||||||
|
</select>
|
||||||
|
</#macro>
|
|
@ -31,7 +31,7 @@
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>${i18n().search_form}</legend>
|
<legend>${i18n().search_form}</legend>
|
||||||
|
|
||||||
<form id="search-form" action="${urls.search}" name="search" role="search" accept-charset="UTF-8" method="POST">
|
<form id="search-form" action="${urls.customsearch}" name="search" role="search" accept-charset="UTF-8" method="POST">
|
||||||
<div id="search-field">
|
<div id="search-field">
|
||||||
<input type="text" name="querytext" class="search-vitro" value="${querytext!}" autocapitalize="off" />
|
<input type="text" name="querytext" class="search-vitro" value="${querytext!}" autocapitalize="off" />
|
||||||
<input type="submit" value="${i18n().search_button}" class="submit">
|
<input type="submit" value="${i18n().search_button}" class="submit">
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<#-- $This file is distributed under the terms of the license in LICENSE$ -->
|
<#-- $This file is distributed under the terms of the license in LICENSE$ -->
|
||||||
|
|
||||||
<div id="searchBlock">
|
<div id="searchBlock">
|
||||||
<form id="searchForm" action="${urls.search}" accept-charset="UTF-8" method="POST">
|
<form id="searchForm" action="${urls.customsearch}" accept-charset="UTF-8" method="POST">
|
||||||
<label for="search">${i18n().search_button}</label>
|
<label for="search">${i18n().search_button}</label>
|
||||||
<input type="text" name="querytext" id="search" class="search-form-item" value="${querytext!}" size="20" autocapitalize="off" />
|
<input type="text" name="querytext" id="search" class="search-form-item" value="${querytext!}" size="20" autocapitalize="off" />
|
||||||
<input class="search-form-submit" name="submit" type="submit" value="${i18n().search_button}" />
|
<input class="search-form-submit" name="submit" type="submit" value="${i18n().search_button}" />
|
||||||
|
|
Loading…
Add table
Reference in a new issue