Merge branch 'DS-1229'

Conflicts:
	dspace-xmlui/dspace-xmlui-webapp/src/main/webapp/themes/Mirage/lib/css/style.css
This commit is contained in:
kevin
2012-08-20 09:06:24 +02:00
87 changed files with 4455 additions and 4398 deletions

View File

@@ -490,6 +490,8 @@ public class AuthorizeManager
rp.setRpType(type); rp.setRpType(type);
rp.update(); rp.update();
o.updateLastModified();
} }
/** /**
@@ -543,6 +545,8 @@ public class AuthorizeManager
rp.setRpType(type); rp.setRpType(type);
rp.update(); rp.update();
o.updateLastModified();
} }
/** /**
@@ -805,6 +809,8 @@ public class AuthorizeManager
// and write out new policy // and write out new policy
drp.update(); drp.update();
} }
dest.updateLastModified();
} }
/** /**
@@ -820,6 +826,8 @@ public class AuthorizeManager
public static void removeAllPolicies(Context c, DSpaceObject o) public static void removeAllPolicies(Context c, DSpaceObject o)
throws SQLException throws SQLException
{ {
o.updateLastModified();
// FIXME: authorization check? // FIXME: authorization check?
DatabaseManager.updateQuery(c, "DELETE FROM resourcepolicy WHERE " DatabaseManager.updateQuery(c, "DELETE FROM resourcepolicy WHERE "
+ "resource_type_id= ? AND resource_id= ? ", + "resource_type_id= ? AND resource_id= ? ",
@@ -882,6 +890,7 @@ public class AuthorizeManager
public static void removePoliciesActionFilter(Context context, public static void removePoliciesActionFilter(Context context,
DSpaceObject dso, int actionID) throws SQLException DSpaceObject dso, int actionID) throws SQLException
{ {
dso.updateLastModified();
if (actionID == -1) if (actionID == -1)
{ {
// remove all policies from object // remove all policies from object
@@ -929,6 +938,8 @@ public class AuthorizeManager
public static void removeGroupPolicies(Context c, DSpaceObject o, Group g) public static void removeGroupPolicies(Context c, DSpaceObject o, Group g)
throws SQLException throws SQLException
{ {
o.updateLastModified();
DatabaseManager.updateQuery(c, "DELETE FROM resourcepolicy WHERE " DatabaseManager.updateQuery(c, "DELETE FROM resourcepolicy WHERE "
+ "resource_type_id= ? AND resource_id= ? AND epersongroup_id= ? ", + "resource_type_id= ? AND resource_id= ? AND epersongroup_id= ? ",
o.getType(), o.getID(), g.getID()); o.getType(), o.getID(), g.getID());
@@ -950,6 +961,7 @@ public class AuthorizeManager
public static void removeEPersonPolicies(Context c, DSpaceObject o, EPerson e) public static void removeEPersonPolicies(Context c, DSpaceObject o, EPerson e)
throws SQLException throws SQLException
{ {
o.updateLastModified();
DatabaseManager.updateQuery(c, "DELETE FROM resourcepolicy WHERE " DatabaseManager.updateQuery(c, "DELETE FROM resourcepolicy WHERE "
+ "resource_type_id= ? AND resource_id= ? AND eperson_id= ? ", + "resource_type_id= ? AND resource_id= ? AND eperson_id= ? ",
o.getType(), o.getID(), e.getID()); o.getType(), o.getID(), e.getID());

View File

@@ -180,6 +180,16 @@ public class ResourcePolicy
*/ */
public void delete() throws SQLException public void delete() throws SQLException
{ {
if(getResourceID() != -1 && getResourceType() != -1)
{
//A policy for a DSpace Object has been modified, fire a modify event on the DSpace object
DSpaceObject dso = DSpaceObject.find(myContext, getResourceType(), getResourceID());
if(dso != null)
{
dso.updateLastModified();
}
}
// FIXME: authorizations // FIXME: authorizations
// Remove ourself // Remove ourself
DatabaseManager.delete(myContext, myRow); DatabaseManager.delete(myContext, myRow);
@@ -455,8 +465,15 @@ public class ResourcePolicy
/** /**
* Update the ResourcePolicy * Update the ResourcePolicy
*/ */
public void update() throws SQLException public void update() throws SQLException, AuthorizeException {
{ if(getResourceID() != -1 && getResourceType() != -1){
//A policy for a DSpace Object has been modified, fire a modify event on the DSpace object
DSpaceObject dso = DSpaceObject.find(myContext, getResourceType(), getResourceID());
if(dso != null){
dso.updateLastModified();
}
}
// FIXME: Check authorisation // FIXME: Check authorisation
DatabaseManager.update(myContext, myRow); DatabaseManager.update(myContext, myRow);
} }

View File

@@ -384,6 +384,12 @@ public class BrowseItem extends DSpaceObject
} }
} }
@Override
public void updateLastModified()
{
}
public boolean isArchived() public boolean isArchived()
{ {
return in_archive; return in_archive;

View File

@@ -735,4 +735,11 @@ public class Bitstream extends DSpaceObject
} }
} }
} }
@Override
public void updateLastModified()
{
//Also fire a modified event since the bitstream HAS been modified
bContext.addEvent(new Event(Event.MODIFY, Constants.BITSTREAM, getID(), null));
}
} }

View File

@@ -811,4 +811,10 @@ public class Bundle extends DSpaceObject
return null; return null;
} }
} }
@Override
public void updateLastModified()
{
}
} }

View File

@@ -1487,4 +1487,11 @@ public class Collection extends DSpaceObject
return null; return null;
} }
} }
@Override
public void updateLastModified()
{
//Also fire a modified event since the collection HAS been modified
ourContext.addEvent(new Event(Event.MODIFY, Constants.COLLECTION, getID(), null));
}
} }

View File

@@ -1282,4 +1282,11 @@ public class Community extends DSpaceObject
return null; return null;
} }
} }
@Override
public void updateLastModified()
{
//Also fire a modified event since the community HAS been modified
ourContext.addEvent(new Event(Event.MODIFY, Constants.COMMUNITY, getID(), null));
}
} }

View File

@@ -161,4 +161,6 @@ public abstract class DSpaceObject
{ {
return null; return null;
} }
public abstract void updateLastModified();
} }

View File

@@ -10,6 +10,7 @@ package org.dspace.content;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Date; import java.util.Date;
@@ -326,11 +327,18 @@ public class Item extends DSpaceObject
/** /**
* Method that updates the last modified date of the item * Method that updates the last modified date of the item
* The modified boolean will be set to true and the actual date update will occur on item.update().
*/ */
void updateLastModified() public void updateLastModified()
{ {
modified = true; try {
Date lastModified = new Timestamp(new Date().getTime());
itemRow.setColumn("last_modified", lastModified);
DatabaseManager.updateQuery(ourContext, "UPDATE item SET last_modified = ? WHERE item_id= ? ", lastModified, getID());
//Also fire a modified event since the item HAS been modified
ourContext.addEvent(new Event(Event.MODIFY, Constants.ITEM, getID(), null));
} catch (SQLException e) {
log.error(LogManager.getHeader(ourContext, "Error while updating last modified timestamp", "Item: " + getID()));
}
} }
/** /**

View File

@@ -105,6 +105,12 @@ public class Site extends DSpaceObject
return ConfigurationManager.getProperty("dspace.name"); return ConfigurationManager.getProperty("dspace.name");
} }
@Override
public void updateLastModified()
{
}
public String getURL() public String getURL()
{ {
return ConfigurationManager.getProperty("dspace.url"); return ConfigurationManager.getProperty("dspace.url");

View File

@@ -1103,4 +1103,10 @@ public class EPerson extends DSpaceObject
return getEmail(); return getEmail();
} }
@Override
public void updateLastModified()
{
}
} }

View File

@@ -1419,4 +1419,10 @@ public class Group extends DSpaceObject
} }
return null; return null;
} }
@Override
public void updateLastModified()
{
}
} }

View File

@@ -0,0 +1,53 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.discovery;
/**
* Configuration for one field that is to be highlighted
* Giving 0 as max chars ensures that the entire field is returned !
*
* @author Kevin Van de Velde (kevin at atmire dot com)
* @author Ben Bosman (ben at atmire dot com)
* @author Mark Diggory (markd at atmire dot com)
*/
public class DiscoverHitHighlightingField {
public static final int UNLIMITED_FRAGMENT_LENGTH = 0;
private String field;
private int maxChars;
private int maxSnippets;
public DiscoverHitHighlightingField(String field, int maxChars, int maxSnippets)
{
this.field = field;
this.maxChars = maxChars;
this.maxSnippets = maxSnippets;
}
public String getField()
{
return field;
}
/**
* The max number of characters that should be shown for a
* field containing a matching hit. e.g. If maxChars = 200
* and a hit is found in the full-text the 200 chars
* surrounding the hit will be shown
*/
public int getMaxChars()
{
return maxChars;
}
public int getMaxSnippets()
{
return maxSnippets;
}
}

View File

@@ -40,6 +40,7 @@ public class DiscoverQuery {
private int facetLimit = -1; private int facetLimit = -1;
private int facetMinCount = -1; private int facetMinCount = -1;
private int facetOffset = 0; private int facetOffset = 0;
private Map<String, DiscoverHitHighlightingField> hitHighlighting;
/** Used when you want to search for a specific field value **/ /** Used when you want to search for a specific field value **/
private List<String> searchFields; private List<String> searchFields;
@@ -55,6 +56,7 @@ public class DiscoverQuery {
this.facetFields = new ArrayList<DiscoverFacetField>(); this.facetFields = new ArrayList<DiscoverFacetField>();
this.facetQueries = new ArrayList<String>(); this.facetQueries = new ArrayList<String>();
this.searchFields = new ArrayList<String>(); this.searchFields = new ArrayList<String>();
this.hitHighlighting = new HashMap<String, DiscoverHitHighlightingField>();
//Use a linked hashmap since sometimes insertion order might matter //Use a linked hashmap since sometimes insertion order might matter
this.properties = new LinkedHashMap<String, List<String>>(); this.properties = new LinkedHashMap<String, List<String>>();
} }
@@ -239,10 +241,27 @@ public class DiscoverQuery {
public void addProperty(String property, String value){ public void addProperty(String property, String value){
List<String> toAddList = properties.get(property); List<String> toAddList = properties.get(property);
if(toAddList == null) if(toAddList == null)
{
toAddList = new ArrayList<String>(); toAddList = new ArrayList<String>();
}
toAddList.add(value); toAddList.add(value);
properties.put(property, toAddList); properties.put(property, toAddList);
} }
public DiscoverHitHighlightingField getHitHighlightingField(String field)
{
return hitHighlighting.get(field);
}
public List<DiscoverHitHighlightingField> getHitHighlightingFields()
{
return new ArrayList<DiscoverHitHighlightingField>(hitHighlighting.values());
}
public void addHitHighlightingField(DiscoverHitHighlightingField hitHighlighting)
{
this.hitHighlighting.put(hitHighlighting.getField(), hitHighlighting);
}
} }

View File

@@ -25,12 +25,15 @@ public class DiscoverResult {
/** A map that contains all the documents sougth after, the key is a string representation of the DSpace object */ /** A map that contains all the documents sougth after, the key is a string representation of the DSpace object */
private Map<String, List<SearchDocument>> searchDocuments; private Map<String, List<SearchDocument>> searchDocuments;
private int maxResults = -1; private int maxResults = -1;
private int searchTime;
private Map<String, DSpaceObjectHighlightResult> highlightedResults;
public DiscoverResult() { public DiscoverResult() {
dspaceObjects = new ArrayList<DSpaceObject>(); dspaceObjects = new ArrayList<DSpaceObject>();
facetResults = new LinkedHashMap<String, List<FacetResult>>(); facetResults = new LinkedHashMap<String, List<FacetResult>>();
searchDocuments = new LinkedHashMap<String, List<SearchDocument>>(); searchDocuments = new LinkedHashMap<String, List<SearchDocument>>();
highlightedResults = new HashMap<String, DSpaceObjectHighlightResult>();
} }
@@ -66,6 +69,16 @@ public class DiscoverResult {
this.maxResults = maxResults; this.maxResults = maxResults;
} }
public int getSearchTime()
{
return searchTime;
}
public void setSearchTime(int searchTime)
{
this.searchTime = searchTime;
}
public void addFacetResult(String facetField, FacetResult ...facetResults){ public void addFacetResult(String facetField, FacetResult ...facetResults){
List<FacetResult> facetValues = this.facetResults.get(facetField); List<FacetResult> facetValues = this.facetResults.get(facetField);
if(facetValues == null) if(facetValues == null)
@@ -84,6 +97,16 @@ public class DiscoverResult {
return facetResults.get(facet) == null ? new ArrayList<FacetResult>() : facetResults.get(facet); return facetResults.get(facet) == null ? new ArrayList<FacetResult>() : facetResults.get(facet);
} }
public DSpaceObjectHighlightResult getHighlightedResults(DSpaceObject dso)
{
return highlightedResults.get(dso.getHandle());
}
public void addHighlightedResult(DSpaceObject dso, DSpaceObjectHighlightResult highlightedResult)
{
this.highlightedResults.put(dso.getHandle(), highlightedResult);
}
public static final class FacetResult{ public static final class FacetResult{
private String asFilterQuery; private String asFilterQuery;
private String displayedValue; private String displayedValue;
@@ -108,6 +131,28 @@ public class DiscoverResult {
} }
} }
public static final class DSpaceObjectHighlightResult
{
private DSpaceObject dso;
private Map<String, List<String>> highlightResults;
public DSpaceObjectHighlightResult(DSpaceObject dso, Map<String, List<String>> highlightResults)
{
this.dso = dso;
this.highlightResults = highlightResults;
}
public DSpaceObject getDso()
{
return dso;
}
public List<String> getHighlightResults(String metadataKey)
{
return highlightResults.get(metadataKey);
}
}
public void addSearchDocument(DSpaceObject dso, SearchDocument searchDocument){ public void addSearchDocument(DSpaceObject dso, SearchDocument searchDocument){
String dsoString = SearchDocument.getDspaceObjectStringRepresentation(dso); String dsoString = SearchDocument.getDspaceObjectStringRepresentation(dso);
List<SearchDocument> docs = searchDocuments.get(dsoString); List<SearchDocument> docs = searchDocuments.get(dsoString);

View File

@@ -8,8 +8,9 @@
package org.dspace.discovery; package org.dspace.discovery;
import org.dspace.content.DSpaceObject; import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
import org.dspace.core.Context; import org.dspace.core.Context;
import org.dspace.discovery.configuration.DiscoverySortConfiguration; import org.dspace.discovery.configuration.DiscoveryMoreLikeThisConfiguration;
import java.io.InputStream; import java.io.InputStream;
import java.sql.SQLException; import java.sql.SQLException;
@@ -28,23 +29,13 @@ public interface SearchService {
DiscoverResult search(Context context, DSpaceObject dso, DiscoverQuery query) throws SearchServiceException; DiscoverResult search(Context context, DSpaceObject dso, DiscoverQuery query) throws SearchServiceException;
InputStream searchJSON(DiscoverQuery query, String jsonIdentifier) throws SearchServiceException; InputStream searchJSON(Context context, DiscoverQuery query, String jsonIdentifier) throws SearchServiceException;
InputStream searchJSON(DiscoverQuery query, DSpaceObject dso, String jsonIdentifier) throws SearchServiceException; InputStream searchJSON(Context context, DiscoverQuery query, DSpaceObject dso, String jsonIdentifier) throws SearchServiceException;
List<DSpaceObject> search(Context context, String query, String orderfield, boolean ascending, int offset, int max, String... filterquery); List<DSpaceObject> search(Context context, String query, String orderfield, boolean ascending, int offset, int max, String... filterquery);
/**
* Transforms the given string into a filter query
* @param context the DSpace context
* @param filterQuery the filter query
* @return a filter query object
* @throws java.sql.SQLException ...
*/
DiscoverFilterQuery toFilterQuery(Context context, String filterQuery) throws SQLException;
/** /**
* Transforms the given string field and value into a filter query * Transforms the given string field and value into a filter query
* @param context the DSpace context * @param context the DSpace context
@@ -53,7 +44,9 @@ public interface SearchService {
* @return a filter query * @return a filter query
* @throws SQLException ... * @throws SQLException ...
*/ */
DiscoverFilterQuery toFilterQuery(Context context, String field, String value) throws SQLException; DiscoverFilterQuery toFilterQuery(Context context, String field, String operator, String value) throws SQLException;
List<Item> getRelatedItems(Context context, Item item, DiscoveryMoreLikeThisConfiguration moreLikeThisConfiguration);
/** /**
* Transforms the metadata field of the given sort configuration into the indexed field which we can then use in our solr queries * Transforms the metadata field of the given sort configuration into the indexed field which we can then use in our solr queries

View File

@@ -7,18 +7,21 @@
*/ */
package org.dspace.discovery.configuration; package org.dspace.discovery.configuration;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Required; import org.springframework.beans.factory.annotation.Required;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.List; import java.util.List;
/** /**
* @author Kevin Van de Velde (kevin at atmire dot com) * @author Kevin Van de Velde (kevin at atmire dot com)
*/ */
public class DiscoveryConfiguration { public class DiscoveryConfiguration implements InitializingBean{
/** The configuration for the sidebar facets **/ /** The configuration for the sidebar facets **/
private List<SidebarFacetConfiguration> sidebarFacets = new ArrayList<SidebarFacetConfiguration>(); private List<DiscoverySearchFilterFacet> sidebarFacets = new ArrayList<DiscoverySearchFilterFacet>();
/** The default filter queries which will be applied to any search & the recent submissions **/ /** The default filter queries which will be applied to any search & the recent submissions **/
private List<String> defaultFilterQueries; private List<String> defaultFilterQueries;
@@ -32,6 +35,8 @@ public class DiscoveryConfiguration {
private DiscoverySortConfiguration searchSortConfiguration; private DiscoverySortConfiguration searchSortConfiguration;
private String id; private String id;
private DiscoveryHitHighlightingConfiguration hitHighlightingConfiguration;
private DiscoveryMoreLikeThisConfiguration moreLikeThisConfiguration;
public String getId() { public String getId() {
return id; return id;
@@ -41,12 +46,12 @@ public class DiscoveryConfiguration {
this.id = id; this.id = id;
} }
public List<SidebarFacetConfiguration> getSidebarFacets() { public List<DiscoverySearchFilterFacet> getSidebarFacets() {
return sidebarFacets; return sidebarFacets;
} }
@Required @Required
public void setSidebarFacets(List<SidebarFacetConfiguration> sidebarFacets) { public void setSidebarFacets(List<DiscoverySearchFilterFacet> sidebarFacets) {
this.sidebarFacets = sidebarFacets; this.sidebarFacets = sidebarFacets;
} }
@@ -88,4 +93,46 @@ public class DiscoveryConfiguration {
public void setSearchSortConfiguration(DiscoverySortConfiguration searchSortConfiguration) { public void setSearchSortConfiguration(DiscoverySortConfiguration searchSortConfiguration) {
this.searchSortConfiguration = searchSortConfiguration; this.searchSortConfiguration = searchSortConfiguration;
} }
public void setHitHighlightingConfiguration(DiscoveryHitHighlightingConfiguration hitHighlightingConfiguration) {
this.hitHighlightingConfiguration = hitHighlightingConfiguration;
}
public DiscoveryHitHighlightingConfiguration getHitHighlightingConfiguration() {
return hitHighlightingConfiguration;
}
public void setMoreLikeThisConfiguration(DiscoveryMoreLikeThisConfiguration moreLikeThisConfiguration) {
this.moreLikeThisConfiguration = moreLikeThisConfiguration;
}
public DiscoveryMoreLikeThisConfiguration getMoreLikeThisConfiguration() {
return moreLikeThisConfiguration;
}
/**
* After all the properties are set check that the sidebar facets are a subset of our search filters
*
* @throws Exception throws an exception if this isn't the case
*/
@Override
public void afterPropertiesSet() throws Exception
{
Collection missingSearchFilters = CollectionUtils.subtract(getSidebarFacets(), getSearchFilters());
if(CollectionUtils.isNotEmpty(missingSearchFilters))
{
StringBuilder error = new StringBuilder();
error.append("The following sidebar facet configurations are not present in the search filters list: ");
for (Object missingSearchFilter : missingSearchFilters)
{
DiscoverySearchFilter searchFilter = (DiscoverySearchFilter) missingSearchFilter;
error.append(searchFilter.getIndexFieldName()).append(" ");
}
error.append("all the sidebar facets MUST be a part of the search filters list.");
throw new DiscoveryConfigurationException(error.toString());
}
}
} }

View File

@@ -0,0 +1,33 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.discovery.configuration;
/**
* Exception that can be thrown if there are issues with the discovery configuration
*
* @author Kevin Van de Velde (kevin at atmire dot com)
* @author Ben Bosman (ben at atmire dot com)
* @author Mark Diggory (markd at atmire dot com)
*/
public class DiscoveryConfigurationException extends Exception{
public DiscoveryConfigurationException() {
}
public DiscoveryConfigurationException(String message, Throwable cause) {
super(message, cause);
}
public DiscoveryConfigurationException(String message) {
super(message);
}
public DiscoveryConfigurationException(Throwable cause) {
super(cause);
}
}

View File

@@ -16,7 +16,8 @@ public class DiscoveryConfigurationParameters {
public static final String TYPE_TEXT = "text"; public static final String TYPE_TEXT = "text";
public static final String TYPE_DATE = "date"; public static final String TYPE_DATE = "date";
public static final String TYPE_AC = "date"; public static final String TYPE_HIERARCHICAL = "hierarchical";
public static final String TYPE_AC = "ac";
public static enum SORT {VALUE, COUNT} public static enum SORT {VALUE, COUNT}

View File

@@ -38,7 +38,7 @@ public class DiscoveryConfigurationService {
System.out.println("Facets:"); System.out.println("Facets:");
DiscoveryConfiguration discoveryConfiguration = mainService.getMap().get(key); DiscoveryConfiguration discoveryConfiguration = mainService.getMap().get(key);
for (int i = 0; i < discoveryConfiguration.getSidebarFacets().size(); i++) { for (int i = 0; i < discoveryConfiguration.getSidebarFacets().size(); i++) {
SidebarFacetConfiguration sidebarFacet = discoveryConfiguration.getSidebarFacets().get(i); DiscoverySearchFilterFacet sidebarFacet = discoveryConfiguration.getSidebarFacets().get(i);
System.out.println("\t" + sidebarFacet.getIndexFieldName()); System.out.println("\t" + sidebarFacet.getIndexFieldName());
for (int j = 0; j < sidebarFacet.getMetadataFields().size(); j++) { for (int j = 0; j < sidebarFacet.getMetadataFields().size(); j++) {
String metadataField = sidebarFacet.getMetadataFields().get(j); String metadataField = sidebarFacet.getMetadataFields().get(j);
@@ -49,7 +49,6 @@ public class DiscoveryConfigurationService {
System.out.println("Search filters"); System.out.println("Search filters");
List<DiscoverySearchFilter> searchFilters = discoveryConfiguration.getSearchFilters(); List<DiscoverySearchFilter> searchFilters = discoveryConfiguration.getSearchFilters();
for (DiscoverySearchFilter searchFilter : searchFilters) { for (DiscoverySearchFilter searchFilter : searchFilters) {
System.out.println("\t" + searchFilter.getIndexFieldName() + " full: " + searchFilter.isFullAutoComplete());
for (int i = 0; i < searchFilter.getMetadataFields().size(); i++) { for (int i = 0; i < searchFilter.getMetadataFields().size(); i++) {
String metadataField = searchFilter.getMetadataFields().get(i); String metadataField = searchFilter.getMetadataFields().get(i);
System.out.println("\t\t" + metadataField); System.out.println("\t\t" + metadataField);

View File

@@ -0,0 +1,63 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.discovery.configuration;
import org.springframework.beans.factory.annotation.Required;
/**
* Configuration class that holds hit highlighting configuration for a single metadata field
*
* @author Kevin Van de Velde (kevin at atmire dot com)
* @author Ben Bosman (ben at atmire dot com)
* @author Mark Diggory (markd at atmire dot com)
*/
public class DiscoveryHitHighlightFieldConfiguration
{
private String field;
private int maxSize = 0;
private int snippets = 3;
public String getField()
{
return field;
}
@Required
public void setField(String field)
{
this.field = field;
}
public int getMaxSize()
{
return maxSize;
}
public void setMaxSize(int maxSize)
{
this.maxSize = maxSize;
}
/**
* Set the maximum number of highlighted snippets to generate per field
* @param snippets the number of maximum snippets
*/
public void setSnippets(int snippets)
{
this.snippets = snippets;
}
/**
* Get the maximum number of highlighted snippets to generate per field
*/
public int getSnippets()
{
return snippets;
}
}

View File

@@ -0,0 +1,39 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.discovery.configuration;
import org.springframework.beans.factory.annotation.Required;
import java.util.List;
/**
* Class that contains all the configuration concerning the hit highlighting in search resutls
* This class can be configured in the [dspace.dir]/config/spring/discovery/spring-dspace-addon-discovery-configuration-services.xml
*
* @author Kevin Van de Velde (kevin at atmire dot com)
* @author Ben Bosman (ben at atmire dot com)
* @author Mark Diggory (markd at atmire dot com)
*/
public class DiscoveryHitHighlightingConfiguration
{
/* A list of metadata fields for which the hit highlighting is possible */
private List<DiscoveryHitHighlightFieldConfiguration> metadataFields;
@Required
public void setMetadataFields(List<DiscoveryHitHighlightFieldConfiguration> metadataFields)
{
this.metadataFields = metadataFields;
}
public List<DiscoveryHitHighlightFieldConfiguration> getMetadataFields()
{
return metadataFields;
}
}

View File

@@ -0,0 +1,69 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.discovery.configuration;
import org.springframework.beans.factory.annotation.Required;
import java.util.List;
/**
* Class that contains the more like this configuration on item pages
*
* @author Kevin Van de Velde (kevin at atmire dot com)
* @author Ben Bosman (ben at atmire dot com)
* @author Mark Diggory (markd at atmire dot com)
*/
public class DiscoveryMoreLikeThisConfiguration {
private List<String> similarityMetadataFields;
private int minTermFrequency;
private int max;
private int minWordLength;
@Required
public void setSimilarityMetadataFields(List<String> similarityMetadataFields)
{
this.similarityMetadataFields = similarityMetadataFields;
}
public List<String> getSimilarityMetadataFields()
{
return similarityMetadataFields;
}
@Required
public void setMinTermFrequency(int minTermFrequency)
{
this.minTermFrequency = minTermFrequency;
}
public int getMinTermFrequency()
{
return minTermFrequency;
}
@Required
public void setMax(int max)
{
this.max = max;
}
public int getMax()
{
return max;
}
public int getMinWordLength()
{
return minWordLength;
}
public void setMinWordLength(int minWordLength)
{
this.minWordLength = minWordLength;
}
}

View File

@@ -16,10 +16,10 @@ import java.util.List;
*/ */
public class DiscoverySearchFilter { public class DiscoverySearchFilter {
private String indexFieldName; protected String indexFieldName;
private List<String> metadataFields; protected List<String> metadataFields;
private boolean fullAutoComplete; protected String type = DiscoveryConfigurationParameters.TYPE_TEXT;
private String type = DiscoveryConfigurationParameters.TYPE_TEXT; public static final String FILTER_TYPE_DEFAULT = "default";
public String getIndexFieldName() { public String getIndexFieldName() {
return indexFieldName; return indexFieldName;
@@ -39,28 +39,29 @@ public class DiscoverySearchFilter {
this.metadataFields = metadataFields; this.metadataFields = metadataFields;
} }
public boolean isFullAutoComplete() {
return fullAutoComplete;
}
public void setFullAutoComplete(boolean fullAutoComplete) {
this.fullAutoComplete = fullAutoComplete;
}
public String getType() { public String getType() {
return type; return type;
} }
public void setType(String type) { public void setType(String type) throws DiscoveryConfigurationException {
if(type.equalsIgnoreCase(DiscoveryConfigurationParameters.TYPE_TEXT)){ if(type.equalsIgnoreCase(DiscoveryConfigurationParameters.TYPE_TEXT))
{
this.type = DiscoveryConfigurationParameters.TYPE_TEXT; this.type = DiscoveryConfigurationParameters.TYPE_TEXT;
} else } else
if(type.equalsIgnoreCase(DiscoveryConfigurationParameters.TYPE_DATE)){ if(type.equalsIgnoreCase(DiscoveryConfigurationParameters.TYPE_DATE))
{
this.type = DiscoveryConfigurationParameters.TYPE_DATE; this.type = DiscoveryConfigurationParameters.TYPE_DATE;
} else
if(type.equalsIgnoreCase(DiscoveryConfigurationParameters.TYPE_HIERARCHICAL))
{
throw new DiscoveryConfigurationException("The " + type + " can't be used with a default side bar facet use the \"HierarchicalSidebarFacetConfiguration\" class instead.");
}else{ }else{
this.type = type; this.type = type;
} }
}
public String getFilterType(){
return FILTER_TYPE_DEFAULT;
} }
} }

View File

@@ -0,0 +1,54 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.discovery.configuration;
/**
* An expanded class that allows a search filter to be used as a sidebar facet
*
* @author Kevin Van de Velde (kevin at atmire dot com)
* @author Ben Bosman (ben at atmire dot com)
* @author Mark Diggory (markd at atmire dot com)
*/
public class DiscoverySearchFilterFacet extends DiscoverySearchFilter {
private static final int DEFAULT_FACET_LIMIT = 10;
private int facetLimit = -1;
private DiscoveryConfigurationParameters.SORT sortOrder = DiscoveryConfigurationParameters.SORT.COUNT;
public static final String FILTER_TYPE_FACET = "facet";
public int getFacetLimit()
{
if(facetLimit == -1){
return DEFAULT_FACET_LIMIT;
}else{
return facetLimit;
}
}
public void setFacetLimit(int facetLimit)
{
this.facetLimit = facetLimit;
}
public DiscoveryConfigurationParameters.SORT getSortOrder()
{
return sortOrder;
}
public void setSortOrder(DiscoveryConfigurationParameters.SORT sortOrder)
{
this.sortOrder = sortOrder;
}
@Override
public String getFilterType()
{
return FILTER_TYPE_FACET;
}
}

View File

@@ -0,0 +1,56 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.discovery.configuration;
import org.springframework.beans.factory.annotation.Required;
/**
* Special sidebar facet configuration used for hierarchical facets
*
* @author Kevin Van de Velde (kevin at atmire dot com)
* @author Ben Bosman (ben at atmire dot com)
* @author Mark Diggory (markd at atmire dot com)
*/
public class HierarchicalSidebarFacetConfiguration extends DiscoverySearchFilterFacet{
private String splitter;
private boolean skipFirstNodeLevel = true;
public HierarchicalSidebarFacetConfiguration() {
//Our default type is the hieracrhical, can be overridden by the configuration
this.type = DiscoveryConfigurationParameters.TYPE_HIERARCHICAL;
}
public String getSplitter() {
return splitter;
}
@Required
public void setSplitter(String splitter) {
this.splitter = splitter;
}
public boolean isSkipFirstNodeLevel() {
return skipFirstNodeLevel;
}
public void setSkipFirstNodeLevel(boolean skipFirstNodeLevel) {
this.skipFirstNodeLevel = skipFirstNodeLevel;
}
@Override
public void setType(String type) throws DiscoveryConfigurationException {
if(type.equalsIgnoreCase(DiscoveryConfigurationParameters.TYPE_HIERARCHICAL)){
this.type = type;
}else{
throw new DiscoveryConfigurationException("The " + type + " can't be used with a hierarchical facet side bar facet use the \"DiscoverySearchFilterFacet\" class instead.");
}
}
}

View File

@@ -9,6 +9,7 @@ package org.dspace.discovery;
import org.apache.solr.common.SolrInputDocument; import org.apache.solr.common.SolrInputDocument;
import org.dspace.content.DSpaceObject; import org.dspace.content.DSpaceObject;
import org.dspace.core.Context;
/** /**
@@ -19,7 +20,7 @@ import org.dspace.content.DSpaceObject;
public class SolrServiceIndexOutputPlugin implements SolrServiceIndexPlugin{ public class SolrServiceIndexOutputPlugin implements SolrServiceIndexPlugin{
@Override @Override
public void additionalIndex(DSpaceObject dso, SolrInputDocument document) { public void additionalIndex(Context context, DSpaceObject dso, SolrInputDocument document) {
System.out.println("Currently indexing: " + dso.getHandle()); System.out.println("Currently indexing: " + dso.getHandle());
} }
} }

View File

@@ -9,13 +9,16 @@ package org.dspace.discovery;
import org.apache.solr.common.SolrInputDocument; import org.apache.solr.common.SolrInputDocument;
import org.dspace.content.DSpaceObject; import org.dspace.content.DSpaceObject;
import org.dspace.core.Context;
/** /**
* Indexing plugin used when indexing the communities/collections/items into DSpace * Indexing plugin used when indexing the communities/collections/items into DSpace
* *
* @author Kevin Van de Velde (kevin at atmire dot com) * @author Kevin Van de Velde (kevin at atmire dot com)
* @author Mark Diggory (markd at atmire dot com)
* @author Ben Bosman (ben at atmire dot com)
*/ */
public interface SolrServiceIndexPlugin { public interface SolrServiceIndexPlugin {
public void additionalIndex(DSpaceObject dso, SolrInputDocument document); public void additionalIndex(Context context, DSpaceObject dso, SolrInputDocument document);
} }

View File

@@ -0,0 +1,90 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.discovery;
import org.apache.log4j.Logger;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.common.SolrInputDocument;
import org.dspace.authorize.AuthorizeManager;
import org.dspace.authorize.ResourcePolicy;
import org.dspace.content.DSpaceObject;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.core.LogManager;
import org.dspace.eperson.EPerson;
import org.dspace.eperson.Group;
import java.sql.SQLException;
import java.util.List;
import java.util.Set;
/**
* Restriction plugin that ensures that indexes all the resource policies.
* When a search is performed extra filter queries are added to retrieve only results to which the user has READ access
*
* @author Kevin Van de Velde (kevin at atmire dot com)
* @author Mark Diggory (markd at atmire dot com)
* @author Ben Bosman (ben at atmire dot com)
*/
public class SolrServiceResourceRestrictionPlugin implements SolrServiceIndexPlugin, SolrServiceSearchPlugin{
private static final Logger log = Logger.getLogger(SolrServiceResourceRestrictionPlugin.class);
@Override
public void additionalIndex(Context context, DSpaceObject dso, SolrInputDocument document) {
try {
List<ResourcePolicy> policies = AuthorizeManager.getPoliciesActionFilter(context, dso, Constants.READ);
for (ResourcePolicy resourcePolicy : policies) {
String fieldValue;
if(resourcePolicy.getGroupID() != -1){
//We have a group add it to the value
fieldValue = "g" + resourcePolicy.getGroupID();
}else{
//We have an eperson add it to the value
fieldValue = "e" + resourcePolicy.getEPersonID();
}
document.addField("read", fieldValue);
}
} catch (SQLException e) {
log.error(LogManager.getHeader(context, "Error while indexing resource policies", "DSpace object: (id " + dso.getID() + " type " + dso.getType() + ")"));
}
}
@Override
public void additionalSearchParameters(Context context, DiscoverQuery discoveryQuery, SolrQuery solrQuery) {
StringBuilder resourceQuery = new StringBuilder();
//Always add the anonymous group id to the query
resourceQuery.append("read:(g0");
EPerson currentUser = context.getCurrentUser();
if(currentUser != null){
try {
resourceQuery.append(" OR e").append(currentUser.getID());
//Retrieve all the groups the current user is a member of !
Set<Integer> groupIds = Group.allMemberGroupIDs(context, currentUser);
for (Integer groupId : groupIds) {
resourceQuery.append(" OR g").append(groupId);
}
} catch (SQLException e) {
log.error(LogManager.getHeader(context, "Error while adding resource policy information to query", "") ,e);
}
}
resourceQuery.append(")");
try {
if(AuthorizeManager.isAdmin(context)){
//Admins always have read access even if no policies are present !
resourceQuery.append(" OR (!read[* TO *])");
}
} catch (SQLException e) {
log.error(LogManager.getHeader(context, "Error while verifying if current user is admin !", ""), e);
}
solrQuery.addFilterQuery(resourceQuery.toString());
}
}

View File

@@ -0,0 +1,23 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.discovery;
import org.apache.solr.client.solrj.SolrQuery;
import org.dspace.core.Context;
/**
* Plugin from which users can add additional search parameters for every search that occurs in discovery
*
* @author Kevin Van de Velde (kevin at atmire dot com)
* @author Mark Diggory (markd at atmire dot com)
* @author Ben Bosman (ben at atmire dot com)
*/
public interface SolrServiceSearchPlugin {
public void additionalSearchParameters(Context context, DiscoverQuery discoveryQuery, SolrQuery solrQuery);
}

View File

@@ -11,8 +11,12 @@ import org.apache.cocoon.caching.CacheableProcessingComponent;
import org.apache.cocoon.environment.ObjectModelHelper; import org.apache.cocoon.environment.ObjectModelHelper;
import org.apache.cocoon.environment.Request; import org.apache.cocoon.environment.Request;
import org.apache.cocoon.util.HashUtil; import org.apache.cocoon.util.HashUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.excalibur.source.SourceValidity; import org.apache.excalibur.source.SourceValidity;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.dspace.app.util.MetadataExposure;
import org.dspace.app.xmlui.cocoon.AbstractDSpaceTransformer; import org.dspace.app.xmlui.cocoon.AbstractDSpaceTransformer;
import org.dspace.app.xmlui.utils.DSpaceValidity; import org.dspace.app.xmlui.utils.DSpaceValidity;
import org.dspace.app.xmlui.utils.HandleUtil; import org.dspace.app.xmlui.utils.HandleUtil;
@@ -24,13 +28,14 @@ import org.dspace.authorize.AuthorizeException;
import org.dspace.content.*; import org.dspace.content.*;
import org.dspace.content.Collection; import org.dspace.content.Collection;
import org.dspace.content.Item; import org.dspace.content.Item;
import org.dspace.core.Constants;
import org.dspace.core.LogManager; import org.dspace.core.LogManager;
import org.dspace.discovery.*; import org.dspace.discovery.*;
import org.dspace.discovery.configuration.DiscoveryConfiguration; import org.dspace.discovery.configuration.DiscoveryConfiguration;
import org.dspace.discovery.configuration.DiscoveryHitHighlightFieldConfiguration;
import org.dspace.discovery.configuration.DiscoverySortConfiguration; import org.dspace.discovery.configuration.DiscoverySortConfiguration;
import org.dspace.discovery.configuration.DiscoverySortFieldConfiguration; import org.dspace.discovery.configuration.DiscoverySortFieldConfiguration;
import org.dspace.handle.HandleManager; import org.dspace.handle.HandleManager;
import org.dspace.sort.SortOption;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import java.io.IOException; import java.io.IOException;
@@ -54,22 +59,17 @@ public abstract class AbstractSearch extends AbstractDSpaceTransformer implement
private static final Logger log = Logger.getLogger(AbstractSearch.class); private static final Logger log = Logger.getLogger(AbstractSearch.class);
/** /**
* Language strings * Language strings
*/ */
private static final Message T_head1_community = private static final Message T_head1_community =
message("xmlui.ArtifactBrowser.AbstractSearch.head1_community"); message("xmlui.Discovery.AbstractSearch.head1_community");
private static final Message T_head1_collection = private static final Message T_head1_collection =
message("xmlui.ArtifactBrowser.AbstractSearch.head1_collection"); message("xmlui.Discovery.AbstractSearch.head1_collection");
private static final Message T_head1_none = private static final Message T_head1_none =
message("xmlui.ArtifactBrowser.AbstractSearch.head1_none"); message("xmlui.Discovery.AbstractSearch.head1_none");
private static final Message T_head2 =
message("xmlui.ArtifactBrowser.AbstractSearch.head2");
private static final Message T_no_results = private static final Message T_no_results =
message("xmlui.ArtifactBrowser.AbstractSearch.no_results"); message("xmlui.ArtifactBrowser.AbstractSearch.no_results");
@@ -78,19 +78,13 @@ public abstract class AbstractSearch extends AbstractDSpaceTransformer implement
message("xmlui.ArtifactBrowser.AbstractSearch.all_of_dspace"); message("xmlui.ArtifactBrowser.AbstractSearch.all_of_dspace");
private static final Message T_sort_by_relevance = private static final Message T_sort_by_relevance =
message("xmlui.ArtifactBrowser.AbstractSearch.sort_by.relevance"); message("xmlui.Discovery.AbstractSearch.sort_by.relevance");
private static final Message T_sort_by = message("xmlui.ArtifactBrowser.AbstractSearch.sort_by"); private static final Message T_sort_by = message("xmlui.Discovery.AbstractSearch.sort_by.head");
private static final Message T_order = message("xmlui.ArtifactBrowser.AbstractSearch.order"); private static final Message T_rpp = message("xmlui.Discovery.AbstractSearch.rpp");
private static final Message T_order_asc = message("xmlui.ArtifactBrowser.AbstractSearch.order.asc"); private static final Message T_result_head_3 = message("xmlui.Discovery.AbstractSearch.head3");
private static final Message T_order_desc = message("xmlui.ArtifactBrowser.AbstractSearch.order.desc"); private static final Message T_result_head_2 = message("xmlui.Discovery.AbstractSearch.head2");
private static final Message T_rpp = message("xmlui.ArtifactBrowser.AbstractSearch.rpp");
private static final Message T_sort_head = message("xmlui.Discovery.SimpleSearch.sort_head");
private static final Message T_sort_button = message("xmlui.Discovery.SimpleSearch.sort_apply");
/** /**
* Cached query results * Cached query results
@@ -180,7 +174,7 @@ public abstract class AbstractSearch extends AbstractDSpaceTransformer implement
List<DiscoverResult.FacetResult> facetValues = facetResults.get(facetField); List<DiscoverResult.FacetResult> facetValues = facetResults.get(facetField);
for (DiscoverResult.FacetResult facetResult : facetValues) for (DiscoverResult.FacetResult facetResult : facetValues)
{ {
validity.add(facetResult.getAsFilterQuery() + facetResult.getCount()); validity.add(facetField + facetResult.getAsFilterQuery() + facetResult.getCount());
} }
} }
@@ -206,6 +200,65 @@ public abstract class AbstractSearch extends AbstractDSpaceTransformer implement
public abstract void addBody(Body body) throws SAXException, WingException, public abstract void addBody(Body body) throws SAXException, WingException,
UIException, SQLException, IOException, AuthorizeException; UIException, SQLException, IOException, AuthorizeException;
/**
* Build the main form that should be the only form that the user interface requires
* This form will be used for all discovery queries, filters, ....
* At the moment however this form is only used to track search result hits
* @param searchDiv the division to add the form to
*/
protected void buildMainForm(Division searchDiv) throws WingException, SQLException {
Request request = ObjectModelHelper.getRequest(objectModel);
//We set our action to context path, since the eventual action will depend on which url we click on
Division mainForm = searchDiv.addInteractiveDivision("main-form", getBasicUrl(), Division.METHOD_POST, "");
String query = getQuery();
mainForm.addHidden("query").setValue(query);
Map<String, String[]> fqs = getParameterFilterQueries();
if (fqs != null)
{
for (String parameter : fqs.keySet())
{
String[] values = fqs.get(parameter);
if(values != null)
{
for (String value : values)
{
mainForm.addHidden(parameter).setValue(value);
}
}
}
}
mainForm.addHidden("rpp").setValue(getParameterRpp());
Hidden sort_by = mainForm.addHidden("sort_by");
if(!StringUtils.isBlank(request.getParameter("sort_by")))
{
sort_by.setValue(request.getParameter("sort_by"));
}else{
sort_by.setValue("score");
}
Hidden order = mainForm.addHidden("order");
if(getParameterOrder() != null)
{
order.setValue(request.getParameter("order"));
}else{
DSpaceObject dso = HandleUtil.obtainHandle(objectModel);
DiscoveryConfiguration discoveryConfiguration = SearchUtils.getDiscoveryConfiguration(dso);
order.setValue(discoveryConfiguration.getSearchSortConfiguration().getDefaultSortOrder().toString());
}
if(!StringUtils.isBlank(request.getParameter("page")))
{
mainForm.addHidden("page").setValue(request.getParameter("page"));
}
//Optional redirect url !
mainForm.addHidden("redirectUrl");
}
protected abstract String getBasicUrl() throws SQLException;
/** /**
* Attach a division to the given search division named "search-results" * Attach a division to the given search division named "search-results"
* which contains results for this search query. * which contains results for this search query.
@@ -232,22 +285,36 @@ public abstract class AbstractSearch extends AbstractDSpaceTransformer implement
} }
Division results = search.addDivision("search-results", "primary"); Division results = search.addDivision("search-results", "primary");
buildSearchControls(results);
DSpaceObject searchScope = getScope(); DSpaceObject searchScope = getScope();
if (searchScope instanceof Community) { int displayedResults;
Community community = (Community) searchScope; long totalResults;
String communityName = community.getMetadata("name"); float searchTime;
results.setHead(T_head1_community.parameterize(communityName));
} else if (searchScope instanceof Collection) { if(queryResults != null && 0 < queryResults.getTotalSearchResults())
Collection collection = (Collection) searchScope; {
String collectionName = collection.getMetadata("name"); displayedResults = queryResults.getDspaceObjects().size();
results.setHead(T_head1_collection.parameterize(collectionName)); totalResults = queryResults.getTotalSearchResults();
} else { searchTime = ((float) queryResults.getSearchTime() / 1000) % 60;
results.setHead(T_head1_none);
if (searchScope instanceof Community)
{
Community community = (Community) searchScope;
String communityName = community.getMetadata("name");
results.setHead(T_head1_community.parameterize(displayedResults, totalResults, communityName, searchTime));
} else if (searchScope instanceof Collection){
Collection collection = (Collection) searchScope;
String collectionName = collection.getMetadata("name");
results.setHead(T_head1_collection.parameterize(displayedResults, totalResults, collectionName, searchTime));
} else {
results.setHead(T_head1_none.parameterize(displayedResults, totalResults, searchTime));
}
} }
if (queryResults != null && 0< queryResults.getDspaceObjects().size()) if (queryResults != null && 0 < queryResults.getDspaceObjects().size())
{ {
// Pagination variables. // Pagination variables.
@@ -262,12 +329,20 @@ public abstract class AbstractSearch extends AbstractDSpaceTransformer implement
Map<String, String> parameters = new HashMap<String, String>(); Map<String, String> parameters = new HashMap<String, String>();
parameters.put("page", "{pageNum}"); parameters.put("page", "{pageNum}");
String pageURLMask = generateURL(parameters); String pageURLMask = generateURL(parameters);
//Check for facet queries ? If we have any add them Map<String, String[]> filterQueryParams = getParameterFilterQueries();
String[] fqs = getParameterFilterQueries(); if(filterQueryParams != null)
if(fqs != null) { {
StringBuilder maskBuilder = new StringBuilder(pageURLMask); StringBuilder maskBuilder = new StringBuilder(pageURLMask);
for (String fq : fqs) { for (String filterQueryParam : filterQueryParams.keySet())
maskBuilder.append("&fq=").append(fq); {
String[] filterQueryValues = filterQueryParams.get(filterQueryParam);
if(filterQueryValues != null)
{
for (String filterQueryValue : filterQueryValues)
{
maskBuilder.append("&").append(filterQueryParam).append("=").append(filterQueryValue);
}
}
} }
pageURLMask = maskBuilder.toString(); pageURLMask = maskBuilder.toString();
@@ -277,34 +352,62 @@ public abstract class AbstractSearch extends AbstractDSpaceTransformer implement
lastItemIndex, currentPage, pagesTotal, pageURLMask); lastItemIndex, currentPage, pagesTotal, pageURLMask);
// Look for any communities or collections in the mix // Look for any communities or collections in the mix
ReferenceSet referenceSet = null; org.dspace.app.xmlui.wing.element.List dspaceObjectsList = null;
// Put in palce top level search result list
dspaceObjectsList = results.addList("search-results-repository",
org.dspace.app.xmlui.wing.element.List.TYPE_DSO_LIST, "repository-search-results");
List<DSpaceObject> commCollList = new ArrayList<DSpaceObject>();
List<Item> itemList = new ArrayList<Item>();
for (DSpaceObject resultDso : queryResults.getDspaceObjects()) for (DSpaceObject resultDso : queryResults.getDspaceObjects())
{ {
if (resultDso instanceof Community || resultDso instanceof Collection) { if(resultDso.getType() == Constants.COMMUNITY || resultDso.getType() == Constants.COLLECTION)
if (referenceSet == null) { {
referenceSet = results.addReferenceSet("search-results-repository", commCollList.add(resultDso);
ReferenceSet.TYPE_SUMMARY_LIST, null, "repository-search-results"); }else
// Set a heading showing that we will be listing containers that matched: if(resultDso.getType() == Constants.ITEM)
referenceSet.setHead(T_head2); {
} itemList.add((Item) resultDso);
if(resultDso != null){ }
referenceSet.addReference(resultDso); }
if(CollectionUtils.isNotEmpty(commCollList))
{
org.dspace.app.xmlui.wing.element.List commCollWingList = dspaceObjectsList.addList("comm-coll-result-list");
commCollWingList.setHead(T_result_head_2);
for (DSpaceObject dso : commCollList)
{
DiscoverResult.DSpaceObjectHighlightResult highlightedResults = queryResults.getHighlightedResults(dso);
if(dso.getType() == Constants.COMMUNITY)
{
//Render our community !
org.dspace.app.xmlui.wing.element.List communityMetadata = commCollWingList.addList(dso.getHandle() + ":community");
renderCommunity((Community) dso, highlightedResults, communityMetadata);
}else
if(dso.getType() == Constants.COLLECTION)
{
//Render our collection !
org.dspace.app.xmlui.wing.element.List collectionMetadata = commCollWingList.addList(dso.getHandle() + ":collection");
renderCollection((Collection) dso, highlightedResults, collectionMetadata);
} }
} }
} }
if(CollectionUtils.isNotEmpty(itemList))
// Put in palce top level referenceset
referenceSet = results.addReferenceSet("search-results-repository",
ReferenceSet.TYPE_SUMMARY_LIST, null, "repository-search-results");
for (DSpaceObject resultDso : queryResults.getDspaceObjects())
{ {
if (resultDso instanceof Item) org.dspace.app.xmlui.wing.element.List itemWingList = dspaceObjectsList.addList("item-result-list");
if(CollectionUtils.isNotEmpty(commCollList))
{ {
referenceSet.addReference(resultDso); itemWingList.setHead(T_result_head_3);
}
for (Item resultDso : itemList)
{
DiscoverResult.DSpaceObjectHighlightResult highlightedResults = queryResults.getHighlightedResults(resultDso);
renderItem(itemWingList, resultDso, highlightedResults);
} }
} }
@@ -314,6 +417,239 @@ public abstract class AbstractSearch extends AbstractDSpaceTransformer implement
//}// Empty query //}// Empty query
} }
/**
* Render the given item, all metadata is added to the given list, which metadata will be rendered where depends on the xsl
* @param dspaceObjectsList a list of DSpace objects
* @param item the DSpace item to be rendered
* @param highlightedResults the highlighted results
* @throws WingException
* @throws SQLException Database failure in services this calls
*/
protected void renderItem(org.dspace.app.xmlui.wing.element.List dspaceObjectsList, Item item, DiscoverResult.DSpaceObjectHighlightResult highlightedResults) throws WingException, SQLException {
org.dspace.app.xmlui.wing.element.List itemList = dspaceObjectsList.addList(item.getHandle() + ":item");
MetadataField[] metadataFields = MetadataField.findAll(context);
for (MetadataField metadataField : metadataFields)
{
//Retrieve the schema for this field
String schema = MetadataSchema.find(context, metadataField.getSchemaID()).getName();
//Check if our field isn't hidden
if (!MetadataExposure.isHidden(context, schema, metadataField.getElement(), metadataField.getQualifier()))
{
//Check if our metadata field is highlighted
StringBuilder metadataKey = new StringBuilder();
metadataKey.append(schema).append(".").append(metadataField.getElement());
if (metadataField.getQualifier() != null)
{
metadataKey.append(".").append(metadataField.getQualifier());
}
StringBuilder itemName = new StringBuilder();
itemName.append(item.getHandle()).append(":").append(metadataKey.toString());
DCValue[] itemMetadata = item.getMetadata(schema, metadataField.getElement(), metadataField.getQualifier(), Item.ANY);
if(!ArrayUtils.isEmpty(itemMetadata))
{
org.dspace.app.xmlui.wing.element.List metadataFieldList = itemList.addList(itemName.toString());
for (DCValue metadataValue : itemMetadata)
{
String value = metadataValue.value;
addMetadataField(highlightedResults, metadataKey.toString(), metadataFieldList, value);
}
}
}
}
//Check our highlighted results, we may need to add non metadata (like our full text)
if(highlightedResults != null)
{
//Also add the full text snippet (if available !)
List<String> fullSnippets = highlightedResults.getHighlightResults("fulltext");
if(CollectionUtils.isNotEmpty(fullSnippets))
{
StringBuilder itemName = new StringBuilder();
itemName.append(item.getHandle()).append(":").append("fulltext");
org.dspace.app.xmlui.wing.element.List fullTextFieldList = itemList.addList(itemName.toString());
for (String snippet : fullSnippets)
{
addMetadataField(fullTextFieldList, snippet);
}
}
}
}
/**
* Render the given collection, all collection metadata is added to the list
* @param collection the collection to be rendered
* @param highlightedResults the highlighted results
* @throws WingException
*/
protected void renderCollection(Collection collection, DiscoverResult.DSpaceObjectHighlightResult highlightedResults, org.dspace.app.xmlui.wing.element.List collectionMetadata) throws WingException {
String description = collection.getMetadata("introductory_text");
String description_abstract = collection.getMetadata("short_description");
String description_table = collection.getMetadata("side_bar_text");
String identifier_uri = "http://hdl.handle.net/" + collection.getHandle();
String provenance = collection.getMetadata("provenance_description");
String rights = collection.getMetadata("copyright_text");
String rights_license = collection.getMetadata("license");
String title = collection.getMetadata("name");
if(StringUtils.isNotBlank(description))
{
addMetadataField(highlightedResults, "dc.description", collectionMetadata.addList(collection.getHandle() + ":dc.description"), description);
}
if(StringUtils.isNotBlank(description_abstract))
{
addMetadataField(highlightedResults, "dc.description.abstract", collectionMetadata.addList(collection.getHandle() + ":dc.description.abstract"), description_abstract);
}
if(StringUtils.isNotBlank(description_table))
{
addMetadataField(highlightedResults, "dc.description.tableofcontents", collectionMetadata.addList(collection.getHandle() + ":dc.description.tableofcontents"), description_table);
}
if(StringUtils.isNotBlank(identifier_uri))
{
addMetadataField(highlightedResults, "dc.identifier.uri", collectionMetadata.addList(collection.getHandle() + ":dc.identifier.uri"), identifier_uri);
}
if(StringUtils.isNotBlank(provenance))
{
addMetadataField(highlightedResults, "dc.provenance", collectionMetadata.addList(collection.getHandle() + ":dc.provenance"), provenance);
}
if(StringUtils.isNotBlank(rights))
{
addMetadataField(highlightedResults, "dc.rights", collectionMetadata.addList(collection.getHandle() + ":dc.rights"), rights);
}
if(StringUtils.isNotBlank(rights_license))
{
addMetadataField(highlightedResults, "dc.rights.license", collectionMetadata.addList(collection.getHandle() + ":dc.rights.license"), rights_license);
}
if(StringUtils.isNotBlank(title))
{
addMetadataField(highlightedResults, "dc.title", collectionMetadata.addList(collection.getHandle() + ":dc.title"), title);
}
}
/**
* Render the given collection, all collection metadata is added to the list
* @param community the community to be rendered
* @param highlightedResults the highlighted results
* @throws WingException
*/
protected void renderCommunity(Community community, DiscoverResult.DSpaceObjectHighlightResult highlightedResults, org.dspace.app.xmlui.wing.element.List communityMetadata) throws WingException {
String description = community.getMetadata("introductory_text");
String description_abstract = community.getMetadata("short_description");
String description_table = community.getMetadata("side_bar_text");
String identifier_uri = "http://hdl.handle.net/" + community.getHandle();
String rights = community.getMetadata("copyright_text");
String title = community.getMetadata("name");
if(StringUtils.isNotBlank(description))
{
addMetadataField(highlightedResults, "dc.description", communityMetadata.addList(community.getHandle() + ":dc.description"), description);
}
if(StringUtils.isNotBlank(description_abstract))
{
addMetadataField(highlightedResults, "dc.description.abstract", communityMetadata.addList(community.getHandle() + ":dc.description.abstract"), description_abstract);
}
if(StringUtils.isNotBlank(description_table))
{
addMetadataField(highlightedResults, "dc.description.tableofcontents", communityMetadata.addList(community.getHandle() + ":dc.description.tableofcontents"), description_table);
}
if(StringUtils.isNotBlank(identifier_uri))
{
addMetadataField(highlightedResults, "dc.identifier.uri", communityMetadata.addList(community.getHandle() + ":dc.identifier.uri"), identifier_uri);
}
if(StringUtils.isNotBlank(rights))
{
addMetadataField(highlightedResults, "dc.rights", communityMetadata.addList(community.getHandle() + ":dc.rights"), rights);
}
if(StringUtils.isNotBlank(title))
{
addMetadataField(highlightedResults, "dc.title", communityMetadata.addList(community.getHandle() + ":dc.title"), title);
}
}
/**
* Add the current value to the wing list,
* @param highlightedResults the highlighted results
* @param metadataKey the metadata key {schema}.{element}.{qualifier}
* @param metadataFieldList the wing list we need to add the metadata value to
* @param value the metadata value
* @throws WingException
*/
protected void addMetadataField(DiscoverResult.DSpaceObjectHighlightResult highlightedResults, String metadataKey, org.dspace.app.xmlui.wing.element.List metadataFieldList, String value) throws WingException {
if(value == null){
//In the unlikely event that the value is null, do not attempt to render this
return;
}
if(highlightedResults != null && highlightedResults.getHighlightResults(metadataKey) != null)
{
//Loop over all our highlighted results
for (String highlight : highlightedResults.getHighlightResults(metadataKey))
{
//If our non highlighted value matches our original one, ensure that the highlighted one is used
DiscoverHitHighlightingField highlightConfig = queryArgs.getHitHighlightingField(metadataKey);
//We might also have it configured for ALL !
if(highlightConfig == null)
{
highlightConfig = queryArgs.getHitHighlightingField("*");
}
switch (highlightConfig.getMaxChars())
{
case DiscoverHitHighlightingField.UNLIMITED_FRAGMENT_LENGTH:
//Exact match required
//\r is not indexed in solr & will cause issues
if(highlight.replaceAll("</?em>", "").equals(value.replace("\r", "")))
{
value = highlight;
}
break;
default:
//Partial match allowed, only render the highlighted part
if(value.contains(highlight.replaceAll("</?em>", "")))
{
value = highlight;
}
break;
}
}
}
addMetadataField(metadataFieldList, value);
}
/**
* Add our metadata value, this value will might contain the highlight ("<em></em>") tags, these will be removed & rendered as highlight wing fields.
* @param metadataFieldList the metadata list we need to add the value to
* @param value the metadata value to be rendered
* @throws WingException
*/
protected void addMetadataField(org.dspace.app.xmlui.wing.element.List metadataFieldList, String value) throws WingException {
//We need to put everything in <em> tags in a highlight !
org.dspace.app.xmlui.wing.element.Item metadataItem = metadataFieldList.addItem();
while(value.contains("<em>") && value.contains("</em>"))
{
if(0 < value.indexOf("<em>"))
{
//Add everything before the <em> !
metadataItem.addContent(value.substring(0, value.indexOf("<em>")));
}
metadataItem.addHighlight("highlight").addContent(StringUtils.substringBetween(value, "<em>", "</em>"));
value = StringUtils.substringAfter(value, "</em>");
}
if(0 < value.length())
{
metadataItem.addContent(value);
}
}
/** /**
* Add options to the search scope field. This field determines in what * Add options to the search scope field. This field determines in what
* communities or collections to search for the query. * communities or collections to search for the query.
@@ -472,61 +808,15 @@ public abstract class AbstractSearch extends AbstractDSpaceTransformer implement
queryArgs.setStart(0); queryArgs.setStart(0);
} }
if(discoveryConfiguration.getHitHighlightingConfiguration() != null)
// Use mlt
// queryArgs.add("mlt", "true");
// The fields to use for similarity. NOTE: if possible, these should have a stored TermVector
// queryArgs.add("mlt.fl", "author");
// Minimum Term Frequency - the frequency below which terms will be ignored in the source doc.
// queryArgs.add("mlt.mintf", "1");
// Minimum Document Frequency - the frequency at which words will be ignored which do not occur in at least this many docs.
// queryArgs.add("mlt.mindf", "1");
//queryArgs.add("mlt.q", "");
// mlt.minwl
// minimum word length below which words will be ignored.
// mlt.maxwl
// maximum word length above which words will be ignored.
// mlt.maxqt
// maximum number of query terms that will be included in any generated query.
// mlt.maxntp
// maximum number of tokens to parse in each example doc field that is not stored with TermVector support.
// mlt.boost
// [true/false] set if the query will be boosted by the interesting term relevance.
// mlt.qf
// Query fields and their boosts using the same format as that used in DisMaxRequestHandler. These fields must also be specified in mlt.fl.
//filePost.addParameter("fl", "handle, "search.resourcetype")");
//filePost.addParameter("field", "search.resourcetype");
//Set the default limit to 11
/*
ClientUtils.escapeQueryChars(location)
//f.category.facet.limit=5
for(Enumeration en = request.getParameterNames(); en.hasMoreElements();)
{ {
String key = (String)en.nextElement(); List<DiscoveryHitHighlightFieldConfiguration> metadataFields = discoveryConfiguration.getHitHighlightingConfiguration().getMetadataFields();
if(key.endsWith(".facet.limit")) for (DiscoveryHitHighlightFieldConfiguration fieldConfiguration : metadataFields)
{ {
filePost.addParameter(key, request.getParameter(key)); queryArgs.addHitHighlightingField(new DiscoverHitHighlightingField(fieldConfiguration.getField(), fieldConfiguration.getMaxSize(), fieldConfiguration.getSnippets()));
} }
} }
*/
this.queryResults = SearchUtils.getSearchService().search(context, scope, queryArgs); this.queryResults = SearchUtils.getSearchService().search(context, scope, queryArgs);
} }
@@ -536,9 +826,12 @@ public abstract class AbstractSearch extends AbstractDSpaceTransformer implement
* Returns a list of the filter queries for use in rendering pages, creating page more urls, .... * Returns a list of the filter queries for use in rendering pages, creating page more urls, ....
* @return an array containing the filter queries * @return an array containing the filter queries
*/ */
protected String[] getParameterFilterQueries(){ protected Map<String, String[]> getParameterFilterQueries()
{
try { try {
return ObjectModelHelper.getRequest(objectModel).getParameterValues("fq"); Map<String, String[]> result = new HashMap<String, String[]>();
result.put("fq", ObjectModelHelper.getRequest(objectModel).getParameterValues("fq"));
return result;
} }
catch (Exception e) { catch (Exception e) {
return null; return null;
@@ -659,89 +952,46 @@ public abstract class AbstractSearch extends AbstractDSpaceTransformer implement
protected void buildSearchControls(Division div) protected void buildSearchControls(Division div)
throws WingException, SQLException { throws WingException, SQLException {
org.dspace.app.xmlui.wing.element.List controlsList = div.addList("search-controls", org.dspace.app.xmlui.wing.element.List.TYPE_FORM);
controlsList.setHead(T_sort_head);
//Table controlsTable = div.addTable("search-controls", 1, 4);
org.dspace.app.xmlui.wing.element.Item controlsItem = controlsList.addItem();
// Create a control for the number of records to display
controlsItem.addContent(T_rpp);
Select rppSelect = controlsItem.addSelect("rpp");
for (int i : RESULTS_PER_PAGE_PROGRESSION) {
rppSelect.addOption((i == getParameterRpp()), i, Integer.toString(i));
}
/*
Cell groupCell = controlsRow.addCell();
try {
// Create a drop down of the different sort columns available
groupCell.addContent(T_group_by);
Select groupSelect = groupCell.addSelect("group_by");
groupSelect.addOption(false, "none", T_group_by_none);
String[] groups = {"publication_grp"};
for (String group : groups) {
groupSelect.addOption(group.equals(getParameterGroup()), group,
message("xmlui.ArtifactBrowser.AbstractSearch.group_by." + group));
}
}
catch (Exception se) {
throw new WingException("Unable to get group options", se);
}
*/
// Create a drop down of the different sort columns available
controlsItem.addContent(T_sort_by);
Select sortSelect = controlsItem.addSelect("sort_by");
sortSelect.addOption(false, "score", T_sort_by_relevance);
DSpaceObject dso = HandleUtil.obtainHandle(objectModel); DSpaceObject dso = HandleUtil.obtainHandle(objectModel);
DiscoveryConfiguration discoveryConfiguration = SearchUtils.getDiscoveryConfiguration(dso); DiscoveryConfiguration discoveryConfiguration = SearchUtils.getDiscoveryConfiguration(dso);
Division searchControlsGear = div.addDivision("masked-page-control").addDivision("search-controls-gear", "controls-gear-wrapper");
/**
* Add sort by options, the gear will be rendered by a combination fo javascript & css
*/
String currentSort = getParameterSortBy();
org.dspace.app.xmlui.wing.element.List sortList = searchControlsGear.addList("sort-options", org.dspace.app.xmlui.wing.element.List.TYPE_SIMPLE, "gear-selection");
sortList.addItem("sort-head", "gear-head first").addContent(T_sort_by);
DiscoverySortConfiguration searchSortConfiguration = discoveryConfiguration.getSearchSortConfiguration(); DiscoverySortConfiguration searchSortConfiguration = discoveryConfiguration.getSearchSortConfiguration();
if(searchSortConfiguration != null){
for (DiscoverySortFieldConfiguration sortFieldConfiguration : searchSortConfiguration.getSortFields()) { org.dspace.app.xmlui.wing.element.List sortOptions = sortList.addList("sort-selections");
boolean selected = ("score".equals(currentSort) || (currentSort == null && searchSortConfiguration.getDefaultSort() == null));
sortOptions.addItem("relevance", "gear-option" + (selected ? " gear-option-selected" : "")).addXref("sort_by=score&order=" + searchSortConfiguration.getDefaultSortOrder(), T_sort_by_relevance);
if(searchSortConfiguration.getSortFields() != null)
{
for (DiscoverySortFieldConfiguration sortFieldConfiguration : searchSortConfiguration.getSortFields())
{
String sortField = SearchUtils.getSearchService().toSortFieldIndex(sortFieldConfiguration.getMetadataField(), sortFieldConfiguration.getType()); String sortField = SearchUtils.getSearchService().toSortFieldIndex(sortFieldConfiguration.getMetadataField(), sortFieldConfiguration.getType());
String currentSort = getParameterSortBy(); boolean selectedAsc = ((sortField.equals(currentSort) && "asc".equals(getParameterOrder())) || (sortFieldConfiguration.equals(searchSortConfiguration.getDefaultSort())) && DiscoverySortConfiguration.SORT_ORDER.asc.equals(searchSortConfiguration.getDefaultSortOrder()));
sortSelect.addOption((sortField.equals(currentSort) || sortFieldConfiguration.equals(searchSortConfiguration.getDefaultSort())), sortField, boolean selectedDesc= ((sortField.equals(currentSort) && "desc".equals(getParameterOrder())) || (sortFieldConfiguration.equals(searchSortConfiguration.getDefaultSort())) && DiscoverySortConfiguration.SORT_ORDER.desc.equals(searchSortConfiguration.getDefaultSortOrder()));
message("xmlui.ArtifactBrowser.AbstractSearch.sort_by." + sortField)); String sortFieldParam = "sort_by=" + sortField + "&order=";
sortOptions.addItem(sortField, "gear-option" + (selectedAsc ? " gear-option-selected" : "")).addXref(sortFieldParam + "asc", message("xmlui.Discovery.AbstractSearch.sort_by." + sortField + "_asc"));
sortOptions.addItem(sortField, "gear-option" + (selectedDesc ? " gear-option-selected" : "")).addXref(sortFieldParam + "desc", message("xmlui.Discovery.AbstractSearch.sort_by." + sortField + "_desc"));
} }
} }
// Create a control to changing ascending / descending order //Add the rows per page
controlsItem.addContent(T_order); sortList.addItem("rpp-head", "gear-head").addContent(T_rpp);
Select orderSelect = controlsItem.addSelect("order"); org.dspace.app.xmlui.wing.element.List rppOptions = sortList.addList("rpp-selections");
for (int i : RESULTS_PER_PAGE_PROGRESSION)
String parameterOrder = getParameterOrder(); {
if(parameterOrder == null && searchSortConfiguration != null) { rppOptions.addItem("rpp-" + i, "gear-option" + (i == getParameterRpp() ? " gear-option-selected" : "")).addXref("rpp=" + i, Integer.toString(i));
parameterOrder = searchSortConfiguration.getDefaultSortOrder().toString();
} }
orderSelect.addOption(SortOption.ASCENDING.equalsIgnoreCase(parameterOrder), SortOption.ASCENDING, T_order_asc);
orderSelect.addOption(SortOption.DESCENDING.equalsIgnoreCase(parameterOrder), SortOption.DESCENDING, T_order_desc);
controlsItem.addButton("submit_sort").setValue(T_sort_button);
// Create a control for the number of authors per item to display
// FIXME This is currently disabled, as the supporting functionality
// is not currently present in xmlui
//if (isItemBrowse(info))
//{
// controlsForm.addContent(T_etal);
// Select etalSelect = controlsForm.addSelect(BrowseParams.ETAL);
//
// etalSelect.addOption((info.getEtAl() < 0), 0, T_etal_all);
// etalSelect.addOption(1 == info.getEtAl(), 1, Integer.toString(1));
//
// for (int i = 5; i <= 50; i += 5)
// {
// etalSelect.addOption(i == info.getEtAl(), i, Integer.toString(i));
// }
//}
} }
/** /**

View File

@@ -0,0 +1,99 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.xmlui.aspect.discovery;
import org.apache.cocoon.environment.Request;
import org.apache.commons.lang.StringUtils;
import org.dspace.core.Context;
import org.dspace.discovery.SearchService;
import org.dspace.utils.DSpace;
import java.util.*;
/**
* @author Kevin Van de Velde (kevin at atmire dot com)
* @author Ben Bosman (ben at atmire dot com)
* @author Mark Diggory (markd at atmire dot com)
*/
public class DiscoveryUIUtils {
private static SearchService searchService = null;
static {
DSpace dspace = new DSpace();
searchService = dspace.getServiceManager().getServiceByName(SearchService.class.getName(),SearchService.class);
}
/**
* Returns a list of the filter queries for use in rendering pages, creating page more urls, ....
* @return an array containing the filter queries
*/
public static Map<String, String[]> getParameterFilterQueries(Request request) {
Map<String, String[]> fqs = new HashMap<String, String[]>();
List<String> filterTypes = getRepeatableParameters(request, "filtertype");
List<String> filterOperators = getRepeatableParameters(request, "filter_relational_operator");
List<String> filterValues = getRepeatableParameters(request, "filter");
for (int i = 0; i < filterTypes.size(); i++) {
String filterType = filterTypes.get(i);
String filterValue = filterValues.get(i);
String filterOperator = filterOperators.get(i);
fqs.put("filtertype_" + i, new String[]{filterType});
fqs.put("filter_relational_operator_" + i, new String[]{filterOperator});
fqs.put("filter_" + i, new String[]{filterValue});
}
return fqs;
}
/**
* Returns all the filter queries for use by discovery
* @return an array containing the filter queries
*/
public static String[] getFilterQueries(Request request, Context context) {
try {
List<String> allFilterQueries = new ArrayList<String>();
List<String> filterTypes = getRepeatableParameters(request, "filtertype");
List<String> filterOperators = getRepeatableParameters(request, "filter_relational_operator");
List<String> filterValues = getRepeatableParameters(request, "filter");
for (int i = 0; i < filterTypes.size(); i++) {
String filterType = filterTypes.get(i);
String filterOperator = filterOperators.get(i);
String filterValue = filterValues.get(i);
if(StringUtils.isNotBlank(filterValue)){
allFilterQueries.add(searchService.toFilterQuery(context, (filterType.equals("*") ? "" : filterType), filterOperator, filterValue).getFilterQuery());
}
}
return allFilterQueries.toArray(new String[allFilterQueries.size()]);
}
catch (RuntimeException re) {
throw re;
} catch (Exception e) {
return new String[0];
}
}
public static List<String> getRepeatableParameters(Request request, String prefix){
TreeMap<String, String> result = new TreeMap<String, String>();
Enumeration parameterNames = request.getParameterNames();
while (parameterNames.hasMoreElements()) {
String parameter = (String) parameterNames.nextElement();
if(parameter.startsWith(prefix)){
result.put(parameter, request.getParameter(parameter));
}
}
return new ArrayList<String>(result.values());
}
}

View File

@@ -10,20 +10,18 @@ package org.dspace.app.xmlui.aspect.discovery;
import java.io.IOException; import java.io.IOException;
import java.sql.SQLException; import java.sql.SQLException;
import org.apache.log4j.Logger; import org.apache.commons.collections.CollectionUtils;
import org.dspace.app.xmlui.cocoon.AbstractDSpaceTransformer; import org.dspace.app.xmlui.cocoon.AbstractDSpaceTransformer;
import org.dspace.app.xmlui.utils.HandleUtil; import org.dspace.app.xmlui.utils.HandleUtil;
import org.dspace.app.xmlui.utils.UIException; import org.dspace.app.xmlui.wing.Message;
import org.dspace.app.xmlui.wing.WingException; import org.dspace.app.xmlui.wing.WingException;
import org.dspace.app.xmlui.wing.element.*; import org.dspace.app.xmlui.wing.element.*;
import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.AuthorizeException;
import org.dspace.content.DSpaceObject; import org.dspace.content.DSpaceObject;
import org.dspace.content.Item; import org.dspace.content.Item;
import org.dspace.discovery.DiscoverQuery;
import org.dspace.discovery.DiscoverResult;
import org.dspace.discovery.SearchUtils; import org.dspace.discovery.SearchUtils;
import org.dspace.discovery.configuration.DiscoveryConfiguration;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import org.dspace.discovery.SearchServiceException;
/** /**
* Displays related items to the currently viewable item * Displays related items to the currently viewable item
@@ -34,23 +32,15 @@ import org.dspace.discovery.SearchServiceException;
*/ */
public class RelatedItems extends AbstractDSpaceTransformer public class RelatedItems extends AbstractDSpaceTransformer
{ {
/**
* Cached query results private static final Message T_head = message("xmlui.Discovery.RelatedItems.head");
*/ private static final Message T_related_help = message("xmlui.Discovery.RelatedItems.help");
protected DiscoverResult queryResults;
/** /**
* Cached query arguments * Display items related to the given item
*/
protected DiscoverQuery queryArgs;
private static final Logger log = Logger.getLogger(RelatedItems.class);
/**
* Display a single item
*/ */
public void addBody(Body body) throws SAXException, WingException, public void addBody(Body body) throws SAXException, WingException,
UIException, SQLException, IOException, AuthorizeException SQLException, IOException, AuthorizeException
{ {
DSpaceObject dspaceObject = HandleUtil.obtainHandle(objectModel); DSpaceObject dspaceObject = HandleUtil.obtainHandle(objectModel);
@@ -59,109 +49,34 @@ public class RelatedItems extends AbstractDSpaceTransformer
return; return;
} }
Item item = (Item) dspaceObject; Item item = (Item) dspaceObject;
DiscoveryConfiguration discoveryConfiguration = SearchUtils.getDiscoveryConfiguration(item);
try { if(discoveryConfiguration != null && discoveryConfiguration.getMoreLikeThisConfiguration() != null)
performSearch(item);
} catch (SearchServiceException e) {
log.error(e.getMessage(),e);
}
// Build the collection viewer division.
if (this.queryResults != null) {
// TODO: develop this !
/*
NamedList nList = this.queryResults.getResponse();
SimpleOrderedMap<SolrDocumentList> mlt = (SimpleOrderedMap<SolrDocumentList>)nList.get("moreLikeThis");
//home.addPara(nList.toString());
if(mlt != null && 0 < mlt.size())
{
//TODO: also make sure if an item is unresolved we do not end up with an empty referenceset !
List<DSpaceObject> dsos = new ArrayList<DSpaceObject>();
for(Map.Entry<String,SolrDocumentList> entry : mlt)
{
//org.dspace.app.xmlui.wing.element.List mltList = mltDiv.addList(key);
//mltList.setHead(key);
for(SolrDocument doc : entry.getValue())
{
try{
dsos.add(SearchUtils.findDSpaceObject(context, doc));
}catch(Exception e){
log.error(LogManager.getHeader(context, "Error while resolving related item doc to dso", "Main item: " + item.getID()));
}
//mltList.addItem().addContent(doc.toString());
}
}
if(0 < dsos.size()){
Division home = body.addDivision("test", "secondary related");
String name = "Related Items";
//if (name == null || name.length() == 0)
// home.setHead(T_untitled);
//else
home.setHead(name);
Division mltDiv = home.addDivision("item-related", "secondary related");
mltDiv.setHead("Items By Author:");
ReferenceSet set = mltDiv.addReferenceSet(
"item-related-items", ReferenceSet.TYPE_SUMMARY_LIST,
null, "related-items");
for (DSpaceObject dso : dsos) {
set.addReference(dso);
}
}
}
*/
}
}
public void performSearch(DSpaceObject dso) throws SearchServiceException {
if(queryResults != null)
{ {
return; java.util.List<Item> relatedItems = SearchUtils.getSearchService().getRelatedItems(context, item, discoveryConfiguration.getMoreLikeThisConfiguration());
if(CollectionUtils.isNotEmpty(relatedItems))
{
Division mltDiv = body.addDivision("item-related-container").addDivision("item-related", "secondary related");
mltDiv.setHead(T_head);
mltDiv.addPara(T_related_help);
ReferenceSet set = mltDiv.addReferenceSet(
"item-related-items", ReferenceSet.TYPE_SUMMARY_LIST,
null, "related-items");
for (DSpaceObject dso : relatedItems)
{
set.addReference(dso);
}
}
} }
/*
this.queryArgs = getQueryArgs(getView());
this.queryArgs.setMaxResults(1);
this.queryArgs.add("fl","author,handle");
this.queryArgs.add("mlt","true");
this.queryArgs.add("mlt.fl","author,handle");
this.queryArgs.add("mlt.mindf","1");
this.queryArgs.add("mlt.mintf","1");
this.queryArgs.setQuery("handle:" + dso.getHandle());
this.queryArgs.setRows(1);
*/
//queryResults = SearchUtils.getSearchService().search(context, queryArgs);
}
public String getView()
{
return "item";
} }
/** /**
* Recycle * Recycle
*/ */
public void recycle() { public void recycle() {
this.queryArgs = null;
this.queryResults = null;
super.recycle(); super.recycle();
} }
} }

View File

@@ -27,13 +27,10 @@ import org.dspace.content.Collection;
import org.dspace.content.Community; import org.dspace.content.Community;
import org.dspace.content.DSpaceObject; import org.dspace.content.DSpaceObject;
import org.dspace.core.Constants; import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.discovery.*; import org.dspace.discovery.*;
import org.dspace.discovery.configuration.DiscoveryConfiguration; import org.dspace.discovery.configuration.DiscoveryConfiguration;
import org.dspace.discovery.configuration.DiscoveryConfigurationParameters; import org.dspace.discovery.configuration.DiscoveryConfigurationParameters;
import org.dspace.discovery.configuration.SidebarFacetConfiguration;
import org.dspace.handle.HandleManager; import org.dspace.handle.HandleManager;
import org.dspace.services.ConfigurationService;
import org.dspace.utils.DSpace; import org.dspace.utils.DSpace;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
@@ -77,15 +74,12 @@ public class SearchFacetFilter extends AbstractDSpaceTransformer implements Cach
private int DEFAULT_PAGE_SIZE = 10; private int DEFAULT_PAGE_SIZE = 10;
private ConfigurationService config = null;
private SearchService searchService = null; private SearchService searchService = null;
private static final Message T_go = message("xmlui.general.go"); private static final Message T_go = message("xmlui.general.go");
public SearchFacetFilter() { public SearchFacetFilter() {
DSpace dspace = new DSpace(); DSpace dspace = new DSpace();
config = dspace.getConfigurationService();
searchService = dspace.getServiceManager().getServiceByName(SearchService.class.getName(),SearchService.class); searchService = dspace.getServiceManager().getServiceByName(SearchService.class.getName(),SearchService.class);
} }
@@ -146,7 +140,7 @@ public class SearchFacetFilter extends AbstractDSpaceTransformer implements Cach
java.util.List<DiscoverResult.FacetResult> facetValues = queryResults.getFacetResults().get(facetField); java.util.List<DiscoverResult.FacetResult> facetValues = queryResults.getFacetResults().get(facetField);
for (DiscoverResult.FacetResult facetValue : facetValues) { for (DiscoverResult.FacetResult facetValue : facetValues) {
validity.add(facetValue.getAsFilterQuery() + facetValue.getCount()); validity.add(facetField + facetValue.getAsFilterQuery() + facetValue.getCount());
} }
} }
@@ -191,7 +185,7 @@ public class SearchFacetFilter extends AbstractDSpaceTransformer implements Cach
queryArgs.setMaxResults(0); queryArgs.setMaxResults(0);
queryArgs.addFilterQueries(getDiscoveryFilterQueries()); queryArgs.addFilterQueries(DiscoveryUIUtils.getFilterQueries(request, context));
//Set the default limit to 11 //Set the default limit to 11
@@ -317,11 +311,7 @@ public class SearchFacetFilter extends AbstractDSpaceTransformer implements Cach
Table singleTable = results.addTable("browse-by-" + facetField + "-results", (int) (queryResults.getDspaceObjects().size() + 1), 1); Table singleTable = results.addTable("browse-by-" + facetField + "-results", (int) (queryResults.getDspaceObjects().size() + 1), 1);
List<String> filterQueries = new ArrayList<String>(); List<String> filterQueries = Arrays.asList(DiscoveryUIUtils.getFilterQueries(request, context));
if(request.getParameterValues("fq") != null)
{
filterQueries = Arrays.asList(request.getParameterValues("fq"));
}
int end = values.size(); int end = values.size();
@@ -341,7 +331,7 @@ public class SearchFacetFilter extends AbstractDSpaceTransformer implements Cach
} }
private void addBrowseJumpNavigation(Division div, SearchFilterParam browseParams, Request request) private void addBrowseJumpNavigation(Division div, SearchFilterParam browseParams, Request request)
throws WingException, SQLException { throws WingException, SQLException, UnsupportedEncodingException {
String action; String action;
DSpaceObject dso = HandleUtil.obtainHandle(objectModel); DSpaceObject dso = HandleUtil.obtainHandle(objectModel);
if(dso != null){ if(dso != null){
@@ -359,9 +349,14 @@ public class SearchFacetFilter extends AbstractDSpaceTransformer implements Cach
for(Map.Entry<String, String> param : params.entrySet()){ for(Map.Entry<String, String> param : params.entrySet()){
jump.addHidden(param.getKey()).setValue(param.getValue()); jump.addHidden(param.getKey()).setValue(param.getValue());
} }
String[] filterQueries = getParameterFilterQueries(); Map<String, String[]> filterQueries = DiscoveryUIUtils.getParameterFilterQueries(request);
for (String filterQuery : filterQueries) { for (String parameter : filterQueries.keySet())
jump.addHidden("fq").setValue(filterQuery); {
for (int i = 0; i < filterQueries.get(parameter).length; i++)
{
String value = filterQueries.get(parameter)[i];
jump.addHidden(parameter).setValue(value);
}
} }
//We cannot create a filter for dates //We cannot create a filter for dates
@@ -394,7 +389,6 @@ public class SearchFacetFilter extends AbstractDSpaceTransformer implements Cach
private void renderFacetField(SearchFilterParam browseParams, DSpaceObject dso, String facetField, Table singleTable, List<String> filterQueries, DiscoverResult.FacetResult value) throws SQLException, WingException, UnsupportedEncodingException { private void renderFacetField(SearchFilterParam browseParams, DSpaceObject dso, String facetField, Table singleTable, List<String> filterQueries, DiscoverResult.FacetResult value) throws SQLException, WingException, UnsupportedEncodingException {
String displayedValue = value.getDisplayedValue(); String displayedValue = value.getDisplayedValue();
String filterQuery = value.getAsFilterQuery();
// if(field.getGap() != null){ // if(field.getGap() != null){
// //We have a date get the year so we can display it // //We have a date get the year so we can display it
// DateFormat simpleDateformat = new SimpleDateFormat("yyyy"); // DateFormat simpleDateformat = new SimpleDateFormat("yyyy");
@@ -405,7 +399,7 @@ public class SearchFacetFilter extends AbstractDSpaceTransformer implements Cach
Cell cell = singleTable.addRow().addCell(); Cell cell = singleTable.addRow().addCell();
//No use in selecting the same filter twice //No use in selecting the same filter twice
if(filterQueries.contains(filterQuery)){ if(filterQueries.contains(searchService.toFilterQuery(context, facetField, "equals", displayedValue).getFilterQuery())){
cell.addContent(displayedValue + " (" + value.getCount() + ")"); cell.addContent(displayedValue + " (" + value.getCount() + ")");
} else { } else {
//Add the basics //Add the basics
@@ -415,13 +409,15 @@ public class SearchFacetFilter extends AbstractDSpaceTransformer implements Cach
//Add already existing filter queries //Add already existing filter queries
url = addFilterQueriesToUrl(url); url = addFilterQueriesToUrl(url);
//Last add the current filter query //Last add the current filter query
url += "&fq=" + URLEncoder.encode(filterQuery, "UTF-8"); url += "&filtertype=" + facetField;
url += "&filter_relational_operator=equals";
url += "&filter=" + URLEncoder.encode(displayedValue, "UTF-8");
cell.addXref(url, displayedValue + " (" + value.getCount() + ")" cell.addXref(url, displayedValue + " (" + value.getCount() + ")"
); );
} }
} }
private String getNextPageURL(SearchFilterParam browseParams, Request request) { private String getNextPageURL(SearchFilterParam browseParams, Request request) throws UnsupportedEncodingException, UIException {
int offSet = Util.getIntParameter(request, SearchFilterParam.OFFSET); int offSet = Util.getIntParameter(request, SearchFilterParam.OFFSET);
if (offSet == -1) if (offSet == -1)
{ {
@@ -433,7 +429,6 @@ public class SearchFacetFilter extends AbstractDSpaceTransformer implements Cach
parameters.putAll(browseParams.getControlParameters()); parameters.putAll(browseParams.getControlParameters());
parameters.put(SearchFilterParam.OFFSET, String.valueOf(offSet + DEFAULT_PAGE_SIZE)); parameters.put(SearchFilterParam.OFFSET, String.valueOf(offSet + DEFAULT_PAGE_SIZE));
//TODO: correct comm/collection url
// Add the filter queries // Add the filter queries
String url = generateURL("search-filter", parameters); String url = generateURL("search-filter", parameters);
url = addFilterQueriesToUrl(url); url = addFilterQueriesToUrl(url);
@@ -441,7 +436,7 @@ public class SearchFacetFilter extends AbstractDSpaceTransformer implements Cach
return url; return url;
} }
private String getPreviousPageURL(SearchFilterParam browseParams, Request request) { private String getPreviousPageURL(SearchFilterParam browseParams, Request request) throws UnsupportedEncodingException, UIException {
//If our offset should be 0 then we shouldn't be able to view a previous page url //If our offset should be 0 then we shouldn't be able to view a previous page url
if (0 == queryArgs.getFacetOffset() && Util.getIntParameter(request, "offset") == -1) if (0 == queryArgs.getFacetOffset() && Util.getIntParameter(request, "offset") == -1)
{ {
@@ -459,7 +454,6 @@ public class SearchFacetFilter extends AbstractDSpaceTransformer implements Cach
parameters.putAll(browseParams.getControlParameters()); parameters.putAll(browseParams.getControlParameters());
parameters.put(SearchFilterParam.OFFSET, String.valueOf(offset - DEFAULT_PAGE_SIZE)); parameters.put(SearchFilterParam.OFFSET, String.valueOf(offset - DEFAULT_PAGE_SIZE));
//TODO: correct comm/collection url
// Add the filter queries // Add the filter queries
String url = generateURL("search-filter", parameters); String url = generateURL("search-filter", parameters);
url = addFilterQueriesToUrl(url); url = addFilterQueriesToUrl(url);
@@ -477,74 +471,25 @@ public class SearchFacetFilter extends AbstractDSpaceTransformer implements Cach
super.recycle(); super.recycle();
} }
public String addFilterQueriesToUrl(String url){ public String addFilterQueriesToUrl(String url) throws UIException {
String[] fqs = getParameterFilterQueries(); Map<String, String[]> fqs = DiscoveryUIUtils.getParameterFilterQueries(ObjectModelHelper.getRequest(objectModel));
if (fqs != null) { if (fqs != null)
{
StringBuilder urlBuilder = new StringBuilder(url); StringBuilder urlBuilder = new StringBuilder(url);
for (String fq : fqs) { for (String parameter : fqs.keySet())
urlBuilder.append("&fq=").append(fq); {
for (int i = 0; i < fqs.get(parameter).length; i++)
{
String value = fqs.get(parameter)[i];
urlBuilder.append("&").append(parameter).append("=").append(encodeForURL(value));
}
} }
return urlBuilder.toString(); return urlBuilder.toString();
} }
return url; return url;
} }
protected String[] getParameterFilterQueries() {
Request request = ObjectModelHelper.getRequest(objectModel);
java.util.List<String> fqs = new ArrayList<String>();
if(request.getParameterValues("fq") != null)
{
fqs.addAll(Arrays.asList(request.getParameterValues("fq")));
}
//Have we added a filter using the UI
if(request.getParameter("filter") != null && !"".equals(request.getParameter("filter")))
{
fqs.add((request.getParameter("filtertype").equals("*") ? "" : request.getParameter("filtertype") + ":") + request.getParameter("filter"));
}
return fqs.toArray(new String[fqs.size()]);
}
/**
* Returns all the filter queries for use by discovery
* This method returns more expanded filter queries then the getParameterFilterQueries
* @return an array containing the filter queries
*/
protected String[] getDiscoveryFilterQueries() {
try {
java.util.List<String> allFilterQueries = new ArrayList<String>();
Request request = ObjectModelHelper.getRequest(objectModel);
java.util.List<String> fqs = new ArrayList<String>();
if(request.getParameterValues("fq") != null)
{
fqs.addAll(Arrays.asList(request.getParameterValues("fq")));
}
String type = request.getParameter("filtertype");
String value = request.getParameter("filter");
if(value != null && !value.equals("")){
allFilterQueries.add(searchService.toFilterQuery(context, (type.equals("*") ? "" : type), value).getFilterQuery());
}
//Add all the previous filters also
for (String fq : fqs) {
allFilterQueries.add(searchService.toFilterQuery(context, fq).getFilterQuery());
}
return allFilterQueries.toArray(new String[allFilterQueries.size()]);
}
catch (RuntimeException re) {
throw re;
} catch (Exception e) {
return null;
}
}
private static class SearchFilterParam { private static class SearchFilterParam {
private Request request; private Request request;

View File

@@ -11,6 +11,7 @@ import org.apache.cocoon.caching.CacheableProcessingComponent;
import org.apache.cocoon.environment.ObjectModelHelper; import org.apache.cocoon.environment.ObjectModelHelper;
import org.apache.cocoon.environment.Request; import org.apache.cocoon.environment.Request;
import org.apache.cocoon.util.HashUtil; import org.apache.cocoon.util.HashUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.excalibur.source.SourceValidity; import org.apache.excalibur.source.SourceValidity;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.dspace.app.xmlui.cocoon.AbstractDSpaceTransformer; import org.dspace.app.xmlui.cocoon.AbstractDSpaceTransformer;
@@ -28,14 +29,14 @@ import org.dspace.core.LogManager;
import org.dspace.discovery.*; import org.dspace.discovery.*;
import org.dspace.discovery.configuration.DiscoveryConfiguration; import org.dspace.discovery.configuration.DiscoveryConfiguration;
import org.dspace.discovery.configuration.DiscoveryConfigurationParameters; import org.dspace.discovery.configuration.DiscoveryConfigurationParameters;
import org.dspace.discovery.configuration.SidebarFacetConfiguration; import org.dspace.discovery.configuration.DiscoverySearchFilterFacet;
import org.dspace.handle.HandleManager; import org.dspace.handle.HandleManager;
import org.dspace.utils.DSpace; import org.dspace.utils.DSpace;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import java.io.IOException; import java.io.IOException;
import java.io.Serializable; import java.io.Serializable;
import java.net.URLEncoder; import java.io.UnsupportedEncodingException;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.*; import java.util.*;
import java.util.regex.Matcher; import java.util.regex.Matcher;
@@ -134,7 +135,7 @@ public class SidebarFacetsTransformer extends AbstractDSpaceTransformer implemen
java.util.List<DiscoverResult.FacetResult> facetValues = queryResults.getFacetResults().get(facetField); java.util.List<DiscoverResult.FacetResult> facetValues = queryResults.getFacetResults().get(facetField);
for (DiscoverResult.FacetResult facetValue : facetValues) { for (DiscoverResult.FacetResult facetValue : facetValues) {
val.add(facetValue.getAsFilterQuery() + facetValue.getCount()); val.add(facetField + facetValue.getAsFilterQuery() + facetValue.getCount());
} }
} }
@@ -151,9 +152,9 @@ public class SidebarFacetsTransformer extends AbstractDSpaceTransformer implemen
public void performSearch() throws SearchServiceException, UIException, SQLException { public void performSearch() throws SearchServiceException, UIException, SQLException {
DSpaceObject dso = getScope(); DSpaceObject dso = getScope();
queryArgs = getQueryArgs(context, dso, getAllFilterQueries());
//If we are on a search page performing a search a query may be used
Request request = ObjectModelHelper.getRequest(objectModel); Request request = ObjectModelHelper.getRequest(objectModel);
queryArgs = getQueryArgs(context, dso, DiscoveryUIUtils.getFilterQueries(request, context));
//If we are on a search page performing a search a query may be used
String query = request.getParameter("query"); String query = request.getParameter("query");
if(query != null && !"".equals(query)){ if(query != null && !"".equals(query)){
queryArgs.setQuery(query); queryArgs.setQuery(query);
@@ -179,22 +180,16 @@ public class SidebarFacetsTransformer extends AbstractDSpaceTransformer implemen
if (this.queryResults != null) { if (this.queryResults != null) {
DSpaceObject dso = HandleUtil.obtainHandle(objectModel); DSpaceObject dso = HandleUtil.obtainHandle(objectModel);
java.util.List<String> fqs = new ArrayList<String>(); java.util.List<String> fqs = Arrays.asList(DiscoveryUIUtils.getFilterQueries(request, context));
if(request.getParameterValues("fq") != null){
for (int i = 0; i < request.getParameterValues("fq").length; i++) {
String fq = request.getParameterValues("fq")[i];
fqs.add(getSearchService().toFilterQuery(context, fq).getFilterQuery());
}
}
DiscoveryConfiguration discoveryConfiguration = SearchUtils.getDiscoveryConfiguration(dso); DiscoveryConfiguration discoveryConfiguration = SearchUtils.getDiscoveryConfiguration(dso);
java.util.List<SidebarFacetConfiguration> facets = discoveryConfiguration.getSidebarFacets(); java.util.List<DiscoverySearchFilterFacet> facets = discoveryConfiguration.getSidebarFacets();
if (facets != null && 0 < facets.size()) { if (facets != null && 0 < facets.size()) {
List browse = null; List browse = null;
for (SidebarFacetConfiguration field : facets) { for (DiscoverySearchFilterFacet field : facets) {
//Retrieve our values //Retrieve our values
java.util.List<DiscoverResult.FacetResult> facetValues = queryResults.getFacetResult(field.getIndexFieldName()); java.util.List<DiscoverResult.FacetResult> facetValues = queryResults.getFacetResult(field.getIndexFieldName());
//Check if we are dealing with a date, sometimes the facet values arrive as dates ! //Check if we are dealing with a date, sometimes the facet values arrive as dates !
@@ -224,6 +219,10 @@ public class SidebarFacetsTransformer extends AbstractDSpaceTransformer implemen
if (!iter.hasNext()) if (!iter.hasNext())
{ {
//When we have an hierarchical facet always show the view more they may want to filter the children of the top nodes
if(field.getType().equals(DiscoveryConfigurationParameters.TYPE_HIERARCHICAL)){
addViewMoreUrl(filterValsList, dso, request, field.getIndexFieldName());
}
break; break;
} }
@@ -233,7 +232,7 @@ public class SidebarFacetsTransformer extends AbstractDSpaceTransformer implemen
String displayedValue = value.getDisplayedValue(); String displayedValue = value.getDisplayedValue();
String filterQuery = value.getAsFilterQuery(); String filterQuery = value.getAsFilterQuery();
if (fqs.contains(filterQuery)) { if (fqs.contains(getSearchService().toFilterQuery(context, field.getIndexFieldName(), "equals", value.getDisplayedValue()).getFilterQuery())) {
filterValsList.addItem(Math.random() + "", "selected").addContent(displayedValue + " (" + value.getCount() + ")"); filterValsList.addItem(Math.random() + "", "selected").addContent(displayedValue + " (" + value.getCount() + ")");
} else { } else {
String paramsQuery = retrieveParameters(request); String paramsQuery = retrieveParameters(request);
@@ -243,15 +242,15 @@ public class SidebarFacetsTransformer extends AbstractDSpaceTransformer implemen
(dso == null ? "" : "/handle/" + dso.getHandle()) + (dso == null ? "" : "/handle/" + dso.getHandle()) +
"/discover?" + "/discover?" +
paramsQuery + paramsQuery +
"fq=" + "filtertype=" + field.getIndexFieldName() +
URLEncoder.encode(filterQuery, "UTF-8"), "&filter_relational_operator=equals" +
"&filter=" + encodeForURL(filterQuery),
displayedValue + " (" + value.getCount() + ")" displayedValue + " (" + value.getCount() + ")"
); );
} }
} }
//Show a view more url should there be more values, unless we have a date //Show a view more url should there be more values, unless we have a date
if (i == shownFacets - 1 && !field.getType().equals(DiscoveryConfigurationParameters.TYPE_DATE)/*&& facetField.getGap() == null*/) { if (i == shownFacets - 1 && !field.getType().equals(DiscoveryConfigurationParameters.TYPE_DATE)/*&& facetField.getGap() == null*/) {
addViewMoreUrl(filterValsList, dso, request, field.getIndexFieldName()); addViewMoreUrl(filterValsList, dso, request, field.getIndexFieldName());
} }
} }
@@ -266,26 +265,42 @@ public class SidebarFacetsTransformer extends AbstractDSpaceTransformer implemen
* @param request the cocoon request * @param request the cocoon request
* @return the parameters used on this page * @return the parameters used on this page
*/ */
private String retrieveParameters(Request request) { private String retrieveParameters(Request request) throws UnsupportedEncodingException, UIException {
StringBuffer result = new StringBuffer(); java.util.List<String> parameters = new ArrayList<String>();
Enumeration keys = request.getParameterNames(); if(StringUtils.isNotBlank(request.getParameter("query"))){
if(keys != null){ parameters.add("query=" + encodeForURL(request.getParameter("query")));
while (keys.hasMoreElements()){
String key = (String) keys.nextElement();
//Ignore the page and submit button keys
if(key != null && !"page".equals(key) && !key.startsWith("submit")){
String[] vals = request.getParameterValues(key);
for(String paramValue : vals){
result.append(key).append("=").append(paramValue);
result.append("&");
}
}
}
} }
return result.toString();
if(StringUtils.isNotBlank(request.getParameter("scope"))){
parameters.add("scope=" + request.getParameter("scope"));
}
if(StringUtils.isNotBlank(request.getParameter("sort_by"))){
parameters.add("sort_by=" + request.getParameter("sort_by"));
}
if(StringUtils.isNotBlank(request.getParameter("order"))){
parameters.add("order=" + request.getParameter("order"));
}
if(StringUtils.isNotBlank(request.getParameter("rpp"))){
parameters.add("rpp=" + request.getParameter("rpp"));
}
Map<String, String[]> parameterFilterQueries = DiscoveryUIUtils.getParameterFilterQueries(request);
for(String parameter : parameterFilterQueries.keySet()){
for (int i = 0; i < parameterFilterQueries.get(parameter).length; i++) {
String value = parameterFilterQueries.get(parameter)[i];
parameters.add(parameter + "=" + encodeForURL(value));
}
}
//Join all our parameters by using an "&" sign
String parametersString = StringUtils.join(parameters.toArray(new String[parameters.size()]), "&");
if(StringUtils.isNotEmpty(parametersString)){
parametersString += "&";
}
return parametersString;
} }
private void addViewMoreUrl(List facet, DSpaceObject dso, Request request, String fieldName) throws WingException { private void addViewMoreUrl(List facet, DSpaceObject dso, Request request, String fieldName) throws WingException, UnsupportedEncodingException {
String parameters = retrieveParameters(request); String parameters = retrieveParameters(request);
facet.addItem().addXref( facet.addItem().addXref(
contextPath + contextPath +
@@ -300,7 +315,7 @@ public class SidebarFacetsTransformer extends AbstractDSpaceTransformer implemen
DiscoverQuery queryArgs = new DiscoverQuery(); DiscoverQuery queryArgs = new DiscoverQuery();
DiscoveryConfiguration discoveryConfiguration = SearchUtils.getDiscoveryConfiguration(scope); DiscoveryConfiguration discoveryConfiguration = SearchUtils.getDiscoveryConfiguration(scope);
java.util.List<SidebarFacetConfiguration> facets = discoveryConfiguration.getSidebarFacets(); java.util.List<DiscoverySearchFilterFacet> facets = discoveryConfiguration.getSidebarFacets();
log.info("facets for scope, " + scope + ": " + (facets != null ? facets.size() : null)); log.info("facets for scope, " + scope + ": " + (facets != null ? facets.size() : null));
@@ -317,7 +332,7 @@ public class SidebarFacetsTransformer extends AbstractDSpaceTransformer implemen
/** enable faceting of search results */ /** enable faceting of search results */
if (facets != null){ if (facets != null){
for (SidebarFacetConfiguration facet : facets) { for (DiscoverySearchFilterFacet facet : facets) {
if(facet.getType().equals(DiscoveryConfigurationParameters.TYPE_DATE)){ if(facet.getType().equals(DiscoveryConfigurationParameters.TYPE_DATE)){
String dateFacet = facet.getIndexFieldName() + ".year"; String dateFacet = facet.getIndexFieldName() + ".year";
try{ try{
@@ -447,50 +462,13 @@ public class SidebarFacetsTransformer extends AbstractDSpaceTransformer implemen
int facetLimit = facet.getFacetLimit(); int facetLimit = facet.getFacetLimit();
//Add one to our facet limit to make sure that if we have more then the shown facets that we show our show more url //Add one to our facet limit to make sure that if we have more then the shown facets that we show our show more url
facetLimit++; facetLimit++;
queryArgs.addFacetField(new DiscoverFacetField(facet.getIndexFieldName(), DiscoveryConfigurationParameters.TYPE_TEXT, facetLimit, facet.getSortOrder())); queryArgs.addFacetField(new DiscoverFacetField(facet.getIndexFieldName(), facet.getType(), facetLimit, facet.getSortOrder()));
} }
} }
} }
return queryArgs; return queryArgs;
} }
/**
* Returns all the filter queries for use by discovery
* This method returns more expanded filter queries then the getParameterFilterQueries
* @return an array containing the filter queries
*/
protected String[] getAllFilterQueries() {
try {
java.util.List<String> allFilterQueries = new ArrayList<String>();
Request request = ObjectModelHelper.getRequest(objectModel);
java.util.List<String> fqs = new ArrayList<String>();
if(request.getParameterValues("fq") != null)
{
fqs.addAll(Arrays.asList(request.getParameterValues("fq")));
}
String type = request.getParameter("filtertype");
String value = request.getParameter("filter");
if(value != null && !value.equals("")){
allFilterQueries.add(getSearchService().toFilterQuery(context, (type.equals("*") ? "" : type), value).getFilterQuery());
}
//Add all the previous filters also
for (String fq : fqs) {
allFilterQueries.add(getSearchService().toFilterQuery(context, fq).getFilterQuery());
}
return allFilterQueries.toArray(new String[allFilterQueries.size()]);
}
catch (RuntimeException re) {
throw re;
} catch (Exception e) {
return null;
}
}
/** /**
* Determine the current scope. This may be derived from the current url * Determine the current scope. This may be derived from the current url
* handle if present or the scope parameter is given. If no scope is * handle if present or the scope parameter is given. If no scope is

View File

@@ -10,12 +10,11 @@ package org.dspace.app.xmlui.aspect.discovery;
import java.io.IOException; import java.io.IOException;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.*; import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.cocoon.caching.CacheableProcessingComponent; import org.apache.cocoon.caching.CacheableProcessingComponent;
import org.apache.cocoon.environment.ObjectModelHelper; import org.apache.cocoon.environment.ObjectModelHelper;
import org.apache.cocoon.environment.Request; import org.apache.cocoon.environment.Request;
import org.apache.commons.lang.StringUtils;
import org.dspace.app.xmlui.cocoon.AbstractDSpaceTransformer; import org.dspace.app.xmlui.cocoon.AbstractDSpaceTransformer;
import org.dspace.app.xmlui.utils.HandleUtil; import org.dspace.app.xmlui.utils.HandleUtil;
import org.dspace.app.xmlui.utils.UIException; import org.dspace.app.xmlui.utils.UIException;
@@ -55,21 +54,24 @@ public class SimpleSearch extends AbstractSearch implements CacheableProcessingC
message("xmlui.ArtifactBrowser.SimpleSearch.trail"); message("xmlui.ArtifactBrowser.SimpleSearch.trail");
private static final Message T_search_scope = private static final Message T_search_scope =
message("xmlui.ArtifactBrowser.SimpleSearch.search_scope"); message("xmlui.Discovery.SimpleSearch.search_scope");
private static final Message T_head = private static final Message T_head =
message("xmlui.ArtifactBrowser.SimpleSearch.head"); message("xmlui.ArtifactBrowser.SimpleSearch.head");
private static final Message T_search_label = // private static final Message T_search_label =
message("xmlui.discovery.SimpleSearch.search_label"); // message("xmlui.discovery.SimpleSearch.search_label");
private static final Message T_go = private static final Message T_go = message("xmlui.general.go");
message("xmlui.general.go");
private static final Message T_filter_label = message("xmlui.Discovery.SimpleSearch.filter_head"); private static final Message T_filter_label = message("xmlui.Discovery.SimpleSearch.filter_head");
private static final Message T_filter_help = message("xmlui.Discovery.SimpleSearch.filter_help"); private static final Message T_filter_help = message("xmlui.Discovery.SimpleSearch.filter_help");
private static final Message T_add_filter = message("xmlui.Discovery.SimpleSearch.filter_add"); private static final String T_filter_new_filters = "xmlui.Discovery.AbstractSearch.filters.controls.new-filters.head";
private static final Message T_filter_apply = message("xmlui.Discovery.SimpleSearch.filter_apply"); private static final Message T_filter_controls_apply = message("xmlui.Discovery.AbstractSearch.filters.controls.apply-filters");
private static final Message T_FILTERS_SELECTED = message("xmlui.ArtifactBrowser.SimpleSearch.filter.selected"); private static final Message T_filter_controls_add = message("xmlui.Discovery.AbstractSearch.filters.controls.add-filter");
private static final Message T_filter_controls_remove = message("xmlui.Discovery.AbstractSearch.filters.controls.remove-filter");
private static final Message T_filters_show = message("xmlui.Discovery.AbstractSearch.filters.display");
private static final Message T_filter_contain = message("xmlui.Discovery.SimpleSearch.filter.contains");
private static final Message T_filter_equals = message("xmlui.Discovery.SimpleSearch.filter.equals");
private SearchService searchService = null; private SearchService searchService = null;
@@ -117,15 +119,18 @@ public class SimpleSearch extends AbstractSearch implements CacheableProcessingC
} }
search.addHidden("contextpath").setValue(contextPath); search.addHidden("contextpath").setValue(contextPath);
String[] fqs = getFilterQueries(); Map<String, String[]> fqs = getParameterFilterQueries();
Division mainSearchDiv = search.addInteractiveDivision("general-query", Division searchBoxDivision = search.addDivision("discovery-search-box", "discoverySearchBox");
"discover", Division.METHOD_GET, "discover-search-box search");
Division mainSearchDiv = searchBoxDivision.addInteractiveDivision("general-query",
"discover", Division.METHOD_GET, "discover-search-box");
List searchList = mainSearchDiv.addList("primary-search", List.TYPE_FORM); List searchList = mainSearchDiv.addList("primary-search", List.TYPE_FORM);
searchList.setHead(T_search_label); // searchList.setHead(T_search_label);
if (variableScope()) { if (variableScope())
{
Select scope = searchList.addItem().addSelect("scope"); Select scope = searchList.addItem().addSelect("scope");
scope.setLabel(T_search_scope); scope.setLabel(T_search_scope);
buildScopeList(scope); buildScopeList(scope);
@@ -134,106 +139,74 @@ public class SimpleSearch extends AbstractSearch implements CacheableProcessingC
Item searchBoxItem = searchList.addItem(); Item searchBoxItem = searchList.addItem();
Text text = searchBoxItem.addText("query"); Text text = searchBoxItem.addText("query");
text.setValue(queryString); text.setValue(queryString);
text.setSize(75); searchBoxItem.addButton("submit", "search-icon").setValue(T_go);
searchBoxItem.addButton("submit").setValue(T_go);
addHiddenFormFields("search", request, fqs, mainSearchDiv);
DSpaceObject dso = HandleUtil.obtainHandle(objectModel); DSpaceObject dso = HandleUtil.obtainHandle(objectModel);
DiscoveryConfiguration discoveryConfiguration = SearchUtils.getDiscoveryConfiguration(dso); DiscoveryConfiguration discoveryConfiguration = SearchUtils.getDiscoveryConfiguration(dso);
java.util.List<DiscoverySearchFilter> filterFields = discoveryConfiguration.getSearchFilters(); java.util.List<DiscoverySearchFilter> filterFields = discoveryConfiguration.getSearchFilters();
if(0 < fqs.length || 0 < filterFields.size()){ java.util.List<String> filterTypes = DiscoveryUIUtils.getRepeatableParameters(request, "filtertype");
Division searchFiltersDiv = search.addInteractiveDivision("search-filters", java.util.List<String> filterOperators = DiscoveryUIUtils.getRepeatableParameters(request, "filter_relational_operator");
"discover", Division.METHOD_GET, "discover-search-box search"); java.util.List<String> filterValues = DiscoveryUIUtils.getRepeatableParameters(request, "filter");
List secondarySearchList = searchFiltersDiv.addList("secondary-search", List.TYPE_FORM); if(0 < filterFields.size() && filterTypes.size() == 0)
secondarySearchList.setHead(T_filter_label); {
//Display the add filters url ONLY if we have no filters selected & fitlers can be added
searchList.addItem().addXref("display-filters", T_filters_show);
}
addHiddenFormFields("search", request, fqs, mainSearchDiv);
if(0 < filterFields.size())
{
Division searchFiltersDiv = searchBoxDivision.addInteractiveDivision("search-filters",
"discover", Division.METHOD_GET, "discover-filters-box " + (0 < filterTypes.size() ? "" : "hidden"));
Division filtersWrapper = searchFiltersDiv.addDivision("discovery-filters-wrapper");
filtersWrapper.setHead(T_filter_label);
filtersWrapper.addPara(T_filter_help);
Table filtersTable = filtersWrapper.addTable("discovery-filters", 1, 4, "discovery-filters");
// queryList.addItem().addContent("Filters");
//If we have any filters, show them //If we have any filters, show them
if(fqs.length > 0){ if(filterTypes.size() > 0)
//if(filters != null && filters.size() > 0){ {
Item item = secondarySearchList.addItem("used-filters", "used-filters-list");
for (int i = 0; i < filterTypes.size(); i++)
{
String filterType = filterTypes.get(i);
String filterValue = filterValues.get(i);
String filterOperator = filterOperators.get(i);
// Composite composite = item.addComposite("facet-controls"); if(StringUtils.isNotBlank(filterValue))
{
// composite.setLabel(T_FILTERS_SELECTED); Row row = filtersTable.addRow("used-filters-" + i, Row.ROLE_DATA, "search-filter used-filter");
addFilterRow(filterFields, i, row, filterType, filterOperator, filterValue);
for (int i = 0; i < fqs.length; i++) {
String filterQuery = fqs[i];
DiscoverFilterQuery fq = searchService.toFilterQuery(context, filterQuery);
// CheckBox box = item.addCheckBox("fq");
CheckBox box = item.addCheckBox("fq");
if(i == 0){
box.setLabel(T_FILTERS_SELECTED);
} }
Option option = box.addOption(true, fq.getFilterQuery());
String field = fq.getField();
option.addContent(message("xmlui.ArtifactBrowser.SimpleSearch.filter." + field));
//We have a filter query get the display value
//Check for a range query
Pattern pattern = Pattern.compile("\\[(.*? TO .*?)\\]");
Matcher matcher = pattern.matcher(fq.getDisplayedValue());
boolean hasPattern = matcher.find();
if (hasPattern) {
String[] years = matcher.group(0).replace("[", "").replace("]", "").split(" TO ");
option.addContent(": " + years[0] + " - " + years[1]);
continue;
}
option.addContent(": " + fq.getDisplayedValue());
} }
secondarySearchList.addItem().addButton("submit_update_filters", "update-filters").setValue(T_filter_apply); filtersTable.addRow(Row.ROLE_HEADER).addCell("", Cell.ROLE_HEADER, 1, 4, "new-filter-header").addContent(message(T_filter_new_filters));
} }
int index = filterTypes.size() + 1;
Row row = filtersTable.addRow("filter-new-" + index, Row.ROLE_DATA, "search-filter");
if(0 < filterFields.size()){ addFilterRow(filterFields, index, row, null, null, null);
//We have at least one filter so add our filter box
Item item = secondarySearchList.addItem("search-filter-list", "search-filter-list");
Composite filterComp = item.addComposite("search-filter-controls");
filterComp.setLabel(T_add_filter);
filterComp.setHelp(T_filter_help);
// filterComp.setLabel(""); Row filterControlsItem = filtersTable.addRow("filter-controls", Row.ROLE_DATA, "apply-filter");
filterControlsItem.addCell(1, 3).addContent("");
Select select = filterComp.addSelect("filtertype"); filterControlsItem.addCell().addButton("submit_apply_filter", "discovery-apply-filter-button").setValue(T_filter_controls_apply);
//For each field found (at least one) add options
for (DiscoverySearchFilter searchFilter : filterFields) {
select.addOption(searchFilter.getIndexFieldName(), message("xmlui.ArtifactBrowser.SimpleSearch.filter." + searchFilter.getIndexFieldName()));
}
//Add a box so we can search for our value
filterComp.addText("filter").setSize(30);
//And last add an add button
filterComp.enableAddOperation();
}
addHiddenFormFields("filter", request, fqs, searchFiltersDiv); addHiddenFormFields("filter", request, fqs, searchFiltersDiv);
} }
Division searchControlsDiv = search.addInteractiveDivision("search-controls",
"discover", Division.METHOD_GET, "discover-sort-box search");
buildSearchControls(searchControlsDiv);
addHiddenFormFields("sort", request, fqs, searchControlsDiv);
// query.addPara(null, "button-list").addButton("submit").setValue(T_go); // query.addPara(null, "button-list").addButton("submit").setValue(T_go);
// Build the DRI Body // Build the DRI Body
//Division results = body.addDivision("results", "primary"); //Division results = body.addDivision("results", "primary");
//results.setHead(T_head); //results.setHead(T_head);
buildMainForm(search);
// Add the result division // Add the result division
try { try {
@@ -244,61 +217,49 @@ public class SimpleSearch extends AbstractSearch implements CacheableProcessingC
} }
/** protected void addFilterRow(java.util.List<DiscoverySearchFilter> filterFields, int index, Row row, String selectedFilterType, String relationalOperator, String value) throws WingException {
* Returns a list of the filter queries for use in rendering pages, creating page more urls, .... Select select = row.addCell("", Cell.ROLE_DATA, "selection").addSelect("filtertype_" + index);
* @return an array containing the filter queries
*/
protected String[] getParameterFilterQueries() {
Request request = ObjectModelHelper.getRequest(objectModel);
java.util.List<String> fqs = new ArrayList<String>();
if(request.getParameterValues("fq") != null)
{
fqs.addAll(Arrays.asList(request.getParameterValues("fq")));
}
//Have we added a filter using the UI //For each field found (at least one) add options
if(request.getParameter("filter") != null && !"".equals(request.getParameter("filter"))) for (DiscoverySearchFilter searchFilter : filterFields)
{ {
fqs.add((request.getParameter("filtertype")) + ":" + request.getParameter("filter")); select.addOption(StringUtils.equals(searchFilter.getIndexFieldName(), selectedFilterType), searchFilter.getIndexFieldName(), message("xmlui.ArtifactBrowser.SimpleSearch.filter." + searchFilter.getIndexFieldName()));
} }
return fqs.toArray(new String[fqs.size()]); Select typeSelect = row.addCell("", Cell.ROLE_DATA, "selection").addSelect("filter_relational_operator_" + index);
typeSelect.addOption(StringUtils.equals(relationalOperator, "contains"), "contains", T_filter_contain);
typeSelect.addOption(StringUtils.equals(relationalOperator, "equals"), "equals", T_filter_equals);
//Add a box so we can search for our value
row.addCell("", Cell.ROLE_DATA, "discovery-filter-input-cell").addText("filter_" + index, "discovery-filter-input").setValue(value == null ? "" : value);
//And last add an add button
Cell buttonsCell = row.addCell("filter-controls_" + index, Cell.ROLE_DATA, "filter-controls");
buttonsCell.addButton("add-filter_" + index, "filter-control filter-add").setValue(T_filter_controls_add);
buttonsCell.addButton("remove-filter_" + index, "filter-control filter-remove").setValue(T_filter_controls_remove);
} }
@Override
protected String getBasicUrl() throws SQLException {
Request request = ObjectModelHelper.getRequest(objectModel);
DSpaceObject dso = HandleUtil.obtainHandle(objectModel);
return request.getContextPath() + (dso == null ? "" : "/handle/" + dso.getHandle()) + "/discover";
}
protected Map<String, String[]> getParameterFilterQueries(){
return DiscoveryUIUtils.getParameterFilterQueries(ObjectModelHelper.getRequest(objectModel));
}
/** /**
* Returns all the filter queries for use by discovery * Returns all the filter queries for use by discovery
* This method returns more expanded filter queries then the getParameterFilterQueries * This method returns more expanded filter queries then the getParameterFilterQueries
* @return an array containing the filter queries * @return an array containing the filter queries
*/ */
protected String[] getFilterQueries() { protected String[] getFilterQueries() {
try { return DiscoveryUIUtils.getFilterQueries(ObjectModelHelper.getRequest(objectModel), context);
java.util.List<String> allFilterQueries = new ArrayList<String>();
Request request = ObjectModelHelper.getRequest(objectModel);
java.util.List<String> fqs = new ArrayList<String>();
if(request.getParameterValues("fq") != null)
{
fqs.addAll(Arrays.asList(request.getParameterValues("fq")));
}
String type = request.getParameter("filtertype");
String value = request.getParameter("filter");
if(value != null && !value.equals("")){
allFilterQueries.add(searchService.toFilterQuery(context, (type.equals("*") ? "" : type), value).getFilterQuery());
}
//Add all the previous filters also
for (String fq : fqs) {
allFilterQueries.add(searchService.toFilterQuery(context, fq).getFilterQuery());
}
return allFilterQueries.toArray(new String[allFilterQueries.size()]);
}
catch (RuntimeException re) {
throw re;
} catch (Exception e) {
return null;
}
} }
@@ -375,7 +336,7 @@ public class SimpleSearch extends AbstractSearch implements CacheableProcessingC
* @param division the division that requires the hidden fields * @param division the division that requires the hidden fields
* @throws WingException will never occur * @throws WingException will never occur
*/ */
private void addHiddenFormFields(String type, Request request, String[] fqs, Division division) throws WingException { private void addHiddenFormFields(String type, Request request, Map<String, String[]> fqs, Division division) throws WingException {
if(type.equals("filter") || type.equals("sort")){ if(type.equals("filter") || type.equals("sort")){
if(request.getParameter("query") != null){ if(request.getParameter("query") != null){
division.addHidden("query").setValue(request.getParameter("query")); division.addHidden("query").setValue(request.getParameter("query"));
@@ -386,9 +347,14 @@ public class SimpleSearch extends AbstractSearch implements CacheableProcessingC
} }
//Add the filter queries, current search settings so these remain saved when performing a new search ! //Add the filter queries, current search settings so these remain saved when performing a new search !
if(type.equals("search") || type.equals("sort")){ if(type.equals("search") || type.equals("sort"))
for (String fq : fqs) { {
division.addHidden("fq").setValue(fq); for (String parameter : fqs.keySet())
{
String[] values = fqs.get(parameter);
for (String value : values) {
division.addHidden(parameter).setValue(value);
}
} }
} }

View File

@@ -26,7 +26,6 @@ import org.dspace.handle.HandleManager;
import org.dspace.utils.DSpace; import org.dspace.utils.DSpace;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.sql.SQLException; import java.sql.SQLException;
@@ -118,7 +117,7 @@ public class JSONDiscoverySearcher extends AbstractReader implements Recyclable
try { try {
Context context = ContextUtil.obtainContext(objectModel); Context context = ContextUtil.obtainContext(objectModel);
JSONStream = getSearchService().searchJSON(queryArgs, getScope(context, objectModel), jsonWrf); JSONStream = getSearchService().searchJSON(context, queryArgs, getScope(context, objectModel), jsonWrf);
} catch (Exception e) { } catch (Exception e) {
log.error("Error while retrieving JSON string for Discovery auto complete", e); log.error("Error while retrieving JSON string for Discovery auto complete", e);
} }

View File

@@ -85,7 +85,6 @@
<message key="xmlui.ArtifactBrowser.SimpleSearch.filter.title">Title</message> <message key="xmlui.ArtifactBrowser.SimpleSearch.filter.title">Title</message>
<message key="xmlui.ArtifactBrowser.SimpleSearch.filter.subject">Subject</message> <message key="xmlui.ArtifactBrowser.SimpleSearch.filter.subject">Subject</message>
<message key="xmlui.ArtifactBrowser.SimpleSearch.filter.dateIssued">Date issued</message> <message key="xmlui.ArtifactBrowser.SimpleSearch.filter.dateIssued">Date issued</message>
<message key="xmlui.ArtifactBrowser.SimpleSearch.filter.selected">Selected filters</message>
@@ -102,9 +101,23 @@
<message key="xmlui.Discovery.AbstractSearch.startswith">Starts with</message> <message key="xmlui.Discovery.AbstractSearch.startswith">Starts with</message>
<message key="xmlui.Discovery.AbstractSearch.startswith.help">Or enter first few letters:</message> <message key="xmlui.Discovery.AbstractSearch.startswith.help">Or enter first few letters:</message>
<message key="xmlui.ArtifactBrowser.AbstractSearch.sort_by.dc.title_sort">Title</message> <message key="xmlui.Discovery.AbstractSearch.sort_by.head">Sort Options:</message>
<message key="xmlui.ArtifactBrowser.AbstractSearch.sort_by.dc.date.issued_dt">Issue Date</message> <message key="xmlui.Discovery.AbstractSearch.sort_by.relevance">Relevance</message>
<message key="xmlui.Discovery.AbstractSearch.sort_by.dc.title_sort_desc">Title Desc</message>
<message key="xmlui.Discovery.AbstractSearch.sort_by.dc.date.issued_dt_desc">Issue Date Desc</message>
<message key="xmlui.Discovery.AbstractSearch.sort_by.dc.title_sort_asc">Title Asc</message>
<message key="xmlui.Discovery.AbstractSearch.sort_by.dc.date.issued_dt_asc">Issue Date Asc</message>
<message key="xmlui.Discovery.AbstractSearch.rpp">Results Per Page:</message>
<message key="xmlui.Discovery.AbstractSearch.filters.controls.add-filter">Add Filter</message>
<message key="xmlui.Discovery.AbstractSearch.filters.controls.apply-filters">Apply</message>
<message key="xmlui.Discovery.AbstractSearch.filters.controls.remove-filter">Remove</message>
<message key="xmlui.Discovery.AbstractSearch.filters.controls.new-filters.head">New Filters:</message>
<message key="xmlui.Discovery.AbstractSearch.filters.display">Add filters</message>
<message key="xmlui.discovery.SearchFacetFilter.no-results">No filter values found</message> <message key="xmlui.discovery.SearchFacetFilter.no-results">No filter values found</message>
@@ -112,13 +125,22 @@
<message key="xmlui.discovery.AbstractFiltersTransformer.filters.view-more">... View More</message> <message key="xmlui.discovery.AbstractFiltersTransformer.filters.view-more">... View More</message>
<message key="xmlui.Discovery.SimpleSearch.search_scope">Search</message>
<message key="xmlui.discovery.SimpleSearch.search_label">Search</message> <message key="xmlui.discovery.SimpleSearch.search_label">Search</message>
<message key="xmlui.Discovery.SimpleSearch.filter_head">Filters</message> <message key="xmlui.Discovery.SimpleSearch.filter_head">Filters</message>
<message key="xmlui.Discovery.SimpleSearch.filter_add">Add Filters</message>
<message key="xmlui.Discovery.SimpleSearch.filter_help">Use filters to refine the search results.</message> <message key="xmlui.Discovery.SimpleSearch.filter_help">Use filters to refine the search results.</message>
<message key="xmlui.Discovery.SimpleSearch.filter_apply">Update filters</message>
<message key="xmlui.Discovery.SimpleSearch.sort_head">Sort options</message> <message key="xmlui.Discovery.SimpleSearch.filter.contains">Contains</message>
<message key="xmlui.Discovery.SimpleSearch.sort_apply">Apply</message> <message key="xmlui.Discovery.SimpleSearch.filter.equals">Equals</message>
<message key="xmlui.Discovery.RelatedItems.head">Related items</message>
<message key="xmlui.Discovery.RelatedItems.help">Showing items related by title, author, creator and subject.</message>
<message key="xmlui.Discovery.AbstractSearch.head1_community">Showing {0} out of a total of {1} results for community: {2}. <span class="searchTime">({3} seconds)</span></message>
<message key="xmlui.Discovery.AbstractSearch.head1_collection">Showing {0} out of a total of {1} results for collection: {2}. <span class="searchTime">({3} seconds)</span></message>
<message key="xmlui.Discovery.AbstractSearch.head1_none">Showing {0} out of a total of {1} results. <span class="searchTime">({2} seconds)</span></message>
<message key="xmlui.Discovery.AbstractSearch.head2">Communities or Collections matching your query</message>
<message key="xmlui.Discovery.AbstractSearch.head3">Items matching your query</message>
</catalogue> </catalogue>

View File

@@ -1,214 +1,196 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- <!--
The contents of this file are subject to the license and copyright The contents of this file are subject to the license and copyright
detailed in the LICENSE and NOTICE files at the root of the source detailed in the LICENSE and NOTICE files at the root of the source
tree and available online at tree and available online at
http://www.dspace.org/license/ http://www.dspace.org/license/
--> -->
<!-- <!--
The ArtifactBrowser Aspect is responsible for browsing communities / The ArtifactBrowser Aspect is responsible for browsing communities /
collections / items / and bitstreams, viewing an individual item, collections / items / and bitstreams, viewing an individual item,
and searching the repository. and searching the repository.
--> -->
<map:sitemap xmlns:map="http://apache.org/cocoon/sitemap/1.0"> <map:sitemap xmlns:map="http://apache.org/cocoon/sitemap/1.0">
<map:components> <map:components>
<map:transformers> <map:transformers>
<map:transformer name="Navigation" src="org.dspace.app.xmlui.aspect.discovery.Navigation"/> <map:transformer name="Navigation" src="org.dspace.app.xmlui.aspect.discovery.Navigation"/>
<map:transformer name="SimpleSearch" src="org.dspace.app.xmlui.aspect.discovery.SimpleSearch"/> <map:transformer name="SimpleSearch" src="org.dspace.app.xmlui.aspect.discovery.SimpleSearch"/>
<map:transformer name="BrowseFacet" src="org.dspace.app.xmlui.aspect.discovery.BrowseFacet"/> <map:transformer name="BrowseFacet" src="org.dspace.app.xmlui.aspect.discovery.BrowseFacet"/>
<map:transformer name="SearchFacetFilter" src="org.dspace.app.xmlui.aspect.discovery.SearchFacetFilter"/> <map:transformer name="SearchFacetFilter" src="org.dspace.app.xmlui.aspect.discovery.SearchFacetFilter"/>
<map:transformer name="FrontPageSearch" src="org.dspace.app.xmlui.aspect.discovery.SiteViewer"/> <map:transformer name="FrontPageSearch" src="org.dspace.app.xmlui.aspect.discovery.SiteViewer"/>
<map:transformer name="SiteRecentSubmissions" src="org.dspace.app.xmlui.aspect.discovery.SiteRecentSubmissions"/> <map:transformer name="SiteRecentSubmissions" src="org.dspace.app.xmlui.aspect.discovery.SiteRecentSubmissions"/>
<map:transformer name="SidebarFacetsTransformer" src="org.dspace.app.xmlui.aspect.discovery.SidebarFacetsTransformer"/> <map:transformer name="SidebarFacetsTransformer" src="org.dspace.app.xmlui.aspect.discovery.SidebarFacetsTransformer"/>
<map:transformer name="CommunitySearch" src="org.dspace.app.xmlui.aspect.discovery.CommunitySearch"/> <map:transformer name="CommunitySearch" src="org.dspace.app.xmlui.aspect.discovery.CommunitySearch"/>
<map:transformer name="CommunityRecentSubmissions" src="org.dspace.app.xmlui.aspect.discovery.CommunityRecentSubmissions"/> <map:transformer name="CommunityRecentSubmissions" src="org.dspace.app.xmlui.aspect.discovery.CommunityRecentSubmissions"/>
<map:transformer name="CollectionSearch" src="org.dspace.app.xmlui.aspect.discovery.CollectionSearch"/> <map:transformer name="CollectionSearch" src="org.dspace.app.xmlui.aspect.discovery.CollectionSearch"/>
<map:transformer name="CollectionRecentSubmissions" src="org.dspace.app.xmlui.aspect.discovery.CollectionRecentSubmissions"/> <map:transformer name="CollectionRecentSubmissions" src="org.dspace.app.xmlui.aspect.discovery.CollectionRecentSubmissions"/>
<map:transformer name="RelatedItems" src="org.dspace.app.xmlui.aspect.discovery.RelatedItems"/> <map:transformer name="RelatedItems" src="org.dspace.app.xmlui.aspect.discovery.RelatedItems"/>
<map:transformer name="RestrictedItem" src="org.dspace.app.xmlui.aspect.artifactbrowser.RestrictedItem"/> <map:transformer name="RestrictedItem" src="org.dspace.app.xmlui.aspect.artifactbrowser.RestrictedItem"/>
</map:transformers> </map:transformers>
<map:matchers default="wildcard"> <map:matchers default="wildcard">
<map:matcher name="HandleTypeMatcher" src="org.dspace.app.xmlui.aspect.general.HandleTypeMatcher"/> <map:matcher name="HandleTypeMatcher" src="org.dspace.app.xmlui.aspect.general.HandleTypeMatcher"/>
<map:matcher name="HandleAuthorizedMatcher" src="org.dspace.app.xmlui.aspect.general.HandleAuthorizedMatcher"/> <map:matcher name="HandleAuthorizedMatcher" src="org.dspace.app.xmlui.aspect.general.HandleAuthorizedMatcher"/>
</map:matchers> </map:matchers>
<map:selectors> <map:selectors>
<map:selector name="AuthenticatedSelector" src="org.dspace.app.xmlui.aspect.general.AuthenticatedSelector"/> <map:selector name="AuthenticatedSelector" src="org.dspace.app.xmlui.aspect.general.AuthenticatedSelector"/>
</map:selectors> </map:selectors>
</map:components> </map:components>
<map:pipelines> <map:pipelines>
<map:pipeline> <map:pipeline>
<map:generate/> <map:generate/>
<!-- <!--
Add the basic navigation content to everypage. This includes: Add the basic navigation content to everypage. This includes:
1) Metadata about the current page (really just what the current 1) Metadata about the current page (really just what the current
context path is) context path is)
2) Navigation links to browse the repository. 2) Navigation links to browse the repository.
- This includes links that are relative to the currently - This includes links that are relative to the currently
selected community or collection. selected community or collection.
3) Metadata about the search urls. 3) Metadata about the search urls.
--> -->
<map:transform type="Navigation"/> <map:transform type="Navigation"/>
<!-- <!--
Display the DSpace homepage. This includes the news.xml file Display the DSpace homepage. This includes the news.xml file
along with a list of top level communities in DSpace. along with a list of top level communities in DSpace.
--> -->
<map:match pattern=""> <map:match pattern="">
<map:transform type="SidebarFacetsTransformer"/> <map:transform type="SidebarFacetsTransformer"/>
<map:transform type="FrontPageSearch"/> <map:transform type="FrontPageSearch"/>
<map:transform type="SiteRecentSubmissions"/> <map:transform type="SiteRecentSubmissions"/>
<map:serialize type="xml"/> <map:serialize type="xml"/>
</map:match> </map:match>
<!-- List all communities & collections in DSpace <!-- List all communities & collections in DSpace
<map:match pattern="community-list"> <map:match pattern="community-list">
<map:transform type="CommunityBrowser"> <map:transform type="CommunityBrowser">
<map:parameter name="depth" value="999"/> <map:parameter name="depth" value="999"/>
</map:transform> </map:transform>
<map:serialize type="xml"/> <map:serialize type="xml"/>
</map:match> --> </map:match> -->
<!-- Search --> <!-- Search -->
<map:match pattern="discover"> <map:match pattern="discover">
<map:transform type="SidebarFacetsTransformer"/> <map:transform type="SidebarFacetsTransformer"/>
<map:transform type="SimpleSearch"/> <map:transform type="SimpleSearch"/>
<map:transform type="IncludePageMeta"> <map:transform type="IncludePageMeta">
<map:parameter name="stylesheet.screen.discovery#1" value="../../static/css/discovery/style.css"/> <map:parameter name="stylesheet.screen.discovery#1" value="../../static/css/discovery/discovery-style.css"/>
<map:parameter name="javascript.static#1" value="loadJQuery.js"/> <map:parameter name="javascript.static#1" value="loadJQuery.js"/>
<map:parameter name="javascript.static#2" value="static/js/discovery/core/Core.js"/> <map:parameter name="javascript.static#2" value="static/js/discovery/search-controls.js"/>
<map:parameter name="javascript.static#3" value="static/js/discovery/core/AbstractManager.js"/> </map:transform>
<map:parameter name="javascript.static#4" value="static/js/discovery/core/Parameter.js"/> <map:serialize type="xml"/>
<map:parameter name="javascript.static#5" value="static/js/discovery/core/ParameterStore.js"/> </map:match>
<map:parameter name="javascript.static#6" value="static/js/discovery/core/AbstractWidget.js"/>
<map:parameter name="javascript.static#7" value="static/js/discovery/core/AbstractFacetWidget.js"/> <!--<map:match pattern="browse-discovery">-->
<map:parameter name="javascript.static#8" value="static/js/discovery/managers/Manager.jquery.js"/> <!--<map:transform type="BrowseFacet"/>-->
<map:parameter name="javascript.static#9" value="static/js/jquery/jquery.autocomplete.js"/> <!--<map:serialize type="xml"/>-->
<map:parameter name="javascript.static#10" value="static/js/discovery/widgets/AutocompleteWidget.js"/> <!--</map:match>-->
<map:parameter name="javascript.static#11" value="static/js/discovery/search/search.js"/>
</map:transform> <map:match pattern="search-filter">
<map:serialize type="xml"/> <map:transform type="SearchFacetFilter"/>
</map:match> <map:serialize type="xml"/>
</map:match>
<!--<map:match pattern="browse-discovery">-->
<!--<map:transform type="BrowseFacet"/>--> <!-- Handle specific features -->
<!--<map:serialize type="xml"/>--> <map:match pattern="handle/*/**">
<!--</map:match>-->
<!-- Scoped browse by features -->
<map:match pattern="search-filter"> <map:match type="HandleAuthorizedMatcher" pattern="READ">
<map:transform type="SearchFacetFilter"/> <map:match type="HandleTypeMatcher" pattern="community,collection">
<map:serialize type="xml"/>
</map:match> <!-- Browse (by anything) -->
<!--<map:match pattern="handle/*/*/browse-discovery">-->
<!-- Handle specific features --> <!--<map:transform type="BrowseFacet"/>-->
<map:match pattern="handle/*/**"> <!--<map:serialize type="xml"/>-->
<!--</map:match>-->
<!-- Scoped browse by features -->
<map:match type="HandleAuthorizedMatcher" pattern="READ"> <!-- Simple search -->
<map:match type="HandleTypeMatcher" pattern="community,collection"> <map:match pattern="handle/*/*/discover">
<map:transform type="SidebarFacetsTransformer"/>
<!-- Browse (by anything) --> <map:transform type="SimpleSearch"/>
<!--<map:match pattern="handle/*/*/browse-discovery">--> <map:transform type="IncludePageMeta">
<!--<map:transform type="BrowseFacet"/>--> <map:parameter name="stylesheet.screen.discovery#1" value="../../static/css/discovery/discovery-style.css"/>
<!--<map:serialize type="xml"/>-->
<!--</map:match>--> <map:parameter name="javascript.static#1" value="loadJQuery.js"/>
<map:parameter name="javascript.static#2" value="static/js/discovery/search-controls.js"/>
<!-- Simple search --> </map:transform>
<map:match pattern="handle/*/*/discover"> <map:serialize type="xml"/>
<map:transform type="SidebarFacetsTransformer"/> </map:match>
<map:transform type="SimpleSearch"/>
<map:transform type="IncludePageMeta">
<map:parameter name="stylesheet.screen.discovery#1" value="../../static/css/discovery/style.css"/> <map:match pattern="handle/*/*/search-filter">
<map:transform type="SearchFacetFilter"/>
<map:parameter name="javascript.static#1" value="loadJQuery.js"/> <map:serialize type="xml"/>
<map:parameter name="javascript.static#2" value="static/js/discovery/core/Core.js"/> </map:match>
<map:parameter name="javascript.static#3" value="static/js/discovery/core/AbstractManager.js"/> </map:match>
<map:parameter name="javascript.static#4" value="static/js/discovery/core/Parameter.js"/> </map:match>
<map:parameter name="javascript.static#5" value="static/js/discovery/core/ParameterStore.js"/>
<map:parameter name="javascript.static#6" value="static/js/discovery/core/AbstractWidget.js"/> <map:match pattern="handle/*/*">
<map:parameter name="javascript.static#7" value="static/js/discovery/core/AbstractFacetWidget.js"/> <map:match type="HandleAuthorizedMatcher" pattern="READ">
<map:parameter name="javascript.static#8" value="static/js/discovery/managers/Manager.jquery.js"/> <map:match type="HandleTypeMatcher" pattern="community">
<map:parameter name="javascript.static#9" value="static/js/jquery/jquery.autocomplete.js"/> <map:transform type="SidebarFacetsTransformer"/>
<map:parameter name="javascript.static#10" value="static/js/discovery/widgets/AutocompleteWidget.js"/> <map:transform type="CommunitySearch"/>
<map:parameter name="javascript.static#11" value="static/js/discovery/search/search.js"/> <map:transform type="CommunityRecentSubmissions"/>
</map:transform> <map:serialize type="xml"/>
<map:serialize type="xml"/> </map:match>
</map:match> <map:match type="HandleTypeMatcher" pattern="collection">
<map:transform type="SidebarFacetsTransformer"/>
<map:transform type="CollectionSearch"/>
<map:match pattern="handle/*/*/search-filter"> <map:transform type="CollectionRecentSubmissions"/>
<map:transform type="SearchFacetFilter"/> <map:serialize type="xml"/>
<map:serialize type="xml"/> </map:match>
</map:match> <map:match type="HandleTypeMatcher" pattern="item">
</map:match> <!--<map:transform type="SidebarFacetsTransformer"/>-->
</map:match> <!--<map:transform type="ItemFacets"/>-->
<map:transform type="RelatedItems"/>
<map:match pattern="handle/*/*"> <map:serialize type="xml"/>
<map:match type="HandleAuthorizedMatcher" pattern="READ"> </map:match>
<map:match type="HandleTypeMatcher" pattern="community"> </map:match>
<map:transform type="SidebarFacetsTransformer"/>
<map:transform type="CommunitySearch"/> <map:match type="HandleAuthorizedMatcher" pattern="!READ">
<map:transform type="CommunityRecentSubmissions"/> <map:transform type="RestrictedItem">
<map:serialize type="xml"/> <map:parameter name="header" value="xmlui.ArtifactBrowser.RestrictedItem.auth_header"/>
</map:match> <map:parameter name="message" value="xmlui.ArtifactBrowser.RestrictedItem.auth_message"/>
<map:match type="HandleTypeMatcher" pattern="collection"> </map:transform>
<map:transform type="SidebarFacetsTransformer"/> <map:serialize type="xml"/>
<map:transform type="CollectionSearch"/> </map:match>
<map:transform type="CollectionRecentSubmissions"/> </map:match>
<map:serialize type="xml"/>
</map:match>
<map:match type="HandleTypeMatcher" pattern="item"> </map:match> <!-- End match handle/*/** -->
<!--<map:transform type="SidebarFacetsTransformer"/>-->
<!--<map:transform type="ItemFacets"/>--> <!-- Not a URL we care about, so just pass it on. -->
<map:transform type="RelatedItems"/> <map:serialize type="xml"/>
<map:serialize type="xml"/>
</map:match> </map:pipeline>
</map:match>
<map:match type="HandleAuthorizedMatcher" pattern="!READ"> </map:pipelines>
<map:transform type="RestrictedItem"> </map:sitemap>
<map:parameter name="header" value="xmlui.ArtifactBrowser.RestrictedItem.auth_header"/>
<map:parameter name="message" value="xmlui.ArtifactBrowser.RestrictedItem.auth_message"/>
</map:transform>
<map:serialize type="xml"/>
</map:match>
</map:match>
</map:match> <!-- End match handle/*/** -->
<!-- Not a URL we care about, so just pass it on. -->
<map:serialize type="xml"/>
</map:pipeline>
</map:pipelines>
</map:sitemap>

View File

@@ -0,0 +1,136 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
/**
Discovery control gears start
**/
div.controls-gear-wrapper{
position: relative;
float: right;
cursor: pointer;
}
div.controls-gear-wrapper .discovery-controls-gear{
padding: 3px 24px;
margin-right: 3px;
margin-bottom: 0;
margin-top: 0;
}
ul.gear-selection{
margin: 0 2px 0 0;
list-style: none;
background-color: #FFFFFF;
position: absolute;
right: 0;
z-index: 999;
border: 1px solid #EBEBEB;
padding: 0;
/*Hidden by default*/
display: none;
}
.bottom ul.gear-selection {
/*Css to ensure that the bottom gear selection list is shown on TOP of the button */
bottom: 33px;
}
div.gear-icon{
height: 25px;
width: 25px;
}
.rgba.boxshadow ul.gear-selection{
-webkit-box-shadow: 2px 2px 10px rgba(0, 0, 0, 0.2);
-moz-box-shadow: 2px 2px 10px rgba(0,0,0,0.2);
box-shadow: 2px 2px 10px rgba(0, 0, 0, 0.2);
}
ul.gear-selection ul {
margin-top: 0;
margin-bottom: 0;
margin-left: 0;
padding-left: 0;
}
ul.gear-selection li {
list-style: none;
}
ul.gear-selection li.gear-head{
padding: 5px;
border-top: 1px solid #EBEBEB;
}
ul.gear-selection li.gear-head.first{
border-top: none;
}
ul.gear-selection li.gear-option{
padding: 5px 5px 5px 25px;
white-space: nowrap;
cursor: pointer;
}
ul.gear-selection li.gear-option:hover{
background-color: #EBEBEB;
}
ul.gear-selection li.gear-option a{
color: #444444;
text-decoration: none;
}
/**
Discovery control gears end
**/
table.discovery-filters td.discovery-filter-input-cell input{
width: 98%;
}
table.discovery-filters tr.search-filter.used-filter input.filter-add
{
visibility: hidden;
}
.searchTime{
font-size: 80%;
font-weight: normal;
}
input#aspect_discovery_SimpleSearch_field_query{
height: 25px;
font-size: 18px;
float: left;
display: block;
}
input.search-icon{
height: 33px;
float: left;
margin-left: 5px;
display: block;
width: 75px;
}
div#aspect_discovery_SimpleSearch_div_search-results ul{
padding-left: 0;
}
div#aspect_discovery_SimpleSearch_div_search-results ul li{
list-style: none;
}

View File

@@ -1,56 +0,0 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
.ac_results {
padding: 0px;
border: 1px solid black;
background-color: white;
overflow: hidden;
z-index: 99999;
}
.ac_results ul {
width: 100%;
list-style-position: outside;
list-style: none;
padding: 0;
margin: 0;
}
.ac_results li {
margin: 0px;
padding: 2px 5px;
cursor: default;
display: block;
text-align:left;
/*
if width will be 100% horizontal scrollbar will apear
when scroll mode will be used
*/
/*width: 100%;*/
font: menu;
font-size: 12px;
/*
it is very important, if line-height not setted or setted
in relative units scroll will be broken in firefox
*/
line-height: 16px;
overflow: hidden;
}
.ac_loading {
/*background: white url('indicator.gif') right center no-repeat;*/
}
.ac_odd {
background-color: #eee;
}
.ac_over {
background-color: #0A246A;
color: white;
}

View File

@@ -1,17 +0,0 @@
Portions of this AJAX Solr are licensed under the Apache License (ASL) v2.0.
===
Copyright 2009 Evolving Web Inc.
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.

View File

@@ -1,133 +0,0 @@
/*
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
// $Id$
/**
* Baseclass for all facet widgets.
*
* @class AbstractFacetWidget
* @augments AjaxSolr.AbstractWidget
*/
AjaxSolr.AbstractFacetWidget = AjaxSolr.AbstractWidget.extend(
/** @lends AjaxSolr.AbstractFacetWidget.prototype */
{
/**
* The field to facet on.
*
* @field
* @public
* @type String
*/
field: null,
/**
* @returns {Boolean} Whether any filter queries have been set using this
* widget's facet field.
*/
isEmpty: function () {
return !this.manager.store.find('fq', new RegExp('^-?' + this.field + ':'));
},
/**
* Adds a filter query.
*
* @returns {Boolean} Whether a filter query was added.
*/
add: function (value) {
return this.changeSelection(function () {
return this.manager.store.addByValue('fq', this.fq(value));
});
},
/**
* Removes a filter query.
*
* @returns {Boolean} Whether a filter query was removed.
*/
remove: function (value) {
return this.changeSelection(function () {
return this.manager.store.removeByValue('fq', this.fq(value));
});
},
/**
* Removes all filter queries using the widget's facet field.
*
* @returns {Boolean} Whether a filter query was removed.
*/
clear: function () {
return this.changeSelection(function () {
return this.manager.store.removeByValue('fq', new RegExp('^-?' + this.field + ':'));
});
},
/**
* Helper for selection functions.
*
* @param {Function} Selection function to call.
* @returns {Boolean} Whether the selection changed.
*/
changeSelection: function (func) {
changed = func.apply(this);
if (changed) {
this.afterChangeSelection();
}
return changed;
},
/**
* An abstract hook for child implementations.
*
* <p>This method is executed after the filter queries change.</p>
*/
afterChangeSelection: function () {},
/**
* @param {String} value The value.
* @returns {Function} Sends a request to Solr if it successfully adds a
* filter query with the given value.
*/
clickHandler: function (value) {
var self = this;
return function () {
if (self.add(value)) {
self.manager.doRequest(0);
}
return false;
}
},
/**
* @param {String} value The value.
* @returns {Function} Sends a request to Solr if it successfully removes a
* filter query with the given value.
*/
unclickHandler: function (value) {
var self = this;
return function () {
if (self.remove(value)) {
self.manager.doRequest(0);
}
return false;
}
},
/**
* @param {String} value The facet value.
* @param {Boolean} exclude Whether to exclude this fq parameter value.
* @returns {String} An fq parameter value.
*/
fq: function (value, exclude) {
// If the field value has a space or a colon in it, wrap it in quotes,
// unless it is a range query.
if (value.match(/[ :]/) && !value.match(/[\[\{]\S+ TO \S+[\]\}]/)) {
value = '"' + value + '"';
}
return (exclude ? '-' : '') + this.field + ':' + value;
}
});

View File

@@ -1,189 +0,0 @@
/*
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
// $Id$
/**
* The Manager acts as the controller in a Model-View-Controller framework. All
* public calls should be performed on the manager object.
*
* @param properties A map of fields to set. Refer to the list of public fields.
* @class AbstractManager
*/
AjaxSolr.AbstractManager = AjaxSolr.Class.extend(
/** @lends AjaxSolr.AbstractManager.prototype */
{
/**
* The fully-qualified URL of the Solr application. You must include the
* trailing slash. Do not include the path to any Solr servlet.
*
* @field
* @public
* @type String
* @default "http://localhost:8983/solr/"
*/
solrUrl: 'http://localhost:8983/solr/',
/**
* If we want to proxy queries through a script, rather than send queries
* to Solr directly, set this field to the fully-qualified URL of the script.
*
* @field
* @public
* @type String
*/
proxyUrl: null,
/**
* The default Solr servlet.
*
* @field
* @public
* @type String
* @default "select"
*/
servlet: 'select',
/**
* The most recent response from Solr.
*
* @field
* @private
* @type Object
* @default {}
*/
response: {},
/**
* A collection of all registered widgets. For internal use only.
*
* @field
* @private
* @type Object
* @default {}
*/
widgets: {},
/**
* The parameter store for the manager and its widgets. For internal use only.
*
* @field
* @private
* @type Object
*/
store: null,
/**
* Whether <tt>init()</tt> has been called yet. For internal use only.
*
* @field
* @private
* @type Boolean
* @default false
*/
initialized: false,
/**
* An abstract hook for child implementations.
*
* <p>This method should be called after the store and the widgets have been
* added. It should initialize the widgets and the store, and do any other
* one-time initializations, e.g., perform the first request to Solr.</p>
*
* <p>If no store has been set, it sets the store to the basic <tt>
* AjaxSolr.ParameterStore</tt>.</p>
*/
init: function () {
this.initialized = true;
if (this.store === null) {
this.setStore(new AjaxSolr.ParameterStore());
}
this.store.load(false);
for (var widgetId in this.widgets) {
this.widgets[widgetId].init();
}
this.store.init();
},
/**
* Set the manager's parameter store.
*
* @param {AjaxSolr.ParameterStore} store
*/
setStore: function (store) {
store.manager = this;
this.store = store;
},
/**
* Adds a widget to the manager.
*
* @param {AjaxSolr.AbstractWidget} widget
*/
addWidget: function (widget) {
widget.manager = this;
this.widgets[widget.id] = widget;
},
/**
* Stores the Solr parameters to be sent to Solr and sends a request to Solr.
*
* @param {Boolean} [start] The Solr start offset parameter.
* @param {String} [servlet] The Solr servlet to send the request to.
*/
doRequest: function (start, servlet) {
if (this.initialized === false) {
this.init();
}
// Allow non-pagination widgets to reset the offset parameter.
if (start !== undefined) {
this.store.get('start').val(start);
}
if (servlet === undefined) {
servlet = this.servlet;
}
this.store.save();
for (var widgetId in this.widgets) {
this.widgets[widgetId].beforeRequest();
}
this.executeRequest(servlet);
},
/**
* An abstract hook for child implementations.
*
* <p>Sends the request to Solr, i.e. to <code>this.solrUrl</code> or <code>
* this.proxyUrl</code>, and receives Solr's response. It should send <code>
* this.store.string()</code> as the Solr query, and it should pass Solr's
* response to <code>handleResponse()</code> for handling.</p>
*
* <p>See <tt>managers/Manager.jquery.js</tt> for a jQuery implementation.</p>
*
* @param {String} servlet The Solr servlet to send the request to.
* @throws If not defined in child implementation.
*/
executeRequest: function (servlet) {
throw 'Abstract method executeRequest must be overridden in a subclass.';
},
/**
* This method is executed after the Solr response data arrives. Allows each
* widget to handle Solr's response separately.
*
* @param {Object} data The Solr response.
*/
handleResponse: function (data) {
this.response = data;
for (var widgetId in this.widgets) {
this.widgets[widgetId].afterRequest();
}
}
});

View File

@@ -1,70 +0,0 @@
/*
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
// $Id$
/**
* Baseclass for all widgets.
*
* Provides abstract hooks for child classes.
*
* @param properties A map of fields to set. May be new or public fields.
* @class AbstractWidget
*/
AjaxSolr.AbstractWidget = AjaxSolr.Class.extend(
/** @lends AjaxSolr.AbstractWidget.prototype */
{
/**
* A unique identifier of this widget.
*
* @field
* @public
* @type String
*/
id: null,
/**
* The CSS selector for this widget's target HTML element, e.g. a specific
* <tt>div</tt> or <tt>ul</tt>. A Widget is usually implemented to perform
* all its UI changes relative to its target HTML element.
*
* @field
* @public
* @type String
*/
target: null,
/**
* A reference to the widget's manager. For internal use only.
*
* @field
* @private
* @type AjaxSolr.AbstractManager
*/
manager: null,
/**
* An abstract hook for child implementations.
*
* <p>This method should do any necessary one-time initializations.</p>
*/
init: function () {},
/**
* An abstract hook for child implementations.
*
* <p>This method is executed before the Solr request is sent.</p>
*/
beforeRequest: function () {},
/**
* An abstract hook for child implementations.
*
* <p>This method is executed after the Solr response is received.</p>
*/
afterRequest: function () {}
});

View File

@@ -1,233 +0,0 @@
/*
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
// $Id$
/**
* @namespace A unique namespace for the AJAX Solr library.
*/
AjaxSolr = function () {};
/**
* @namespace Baseclass for all classes
*/
AjaxSolr.Class = function () {};
/**
* A class 'extends' itself into a subclass.
*
* @static
* @param properties The properties of the subclass.
* @returns A function that represents the subclass.
*/
AjaxSolr.Class.extend = function (properties) {
var klass = this; // Safari dislikes 'class'
// The subclass is just a function that when called, instantiates itself.
// Nothing is _actually_ shared between _instances_ of the same class.
var subClass = function (options) {
// 'this' refers to the subclass, which starts life as an empty object.
// Add its parent's properties, its own properties, and any passed options.
AjaxSolr.extend(this, new klass(options), properties, options);
}
// Allow the subclass to extend itself into further subclasses.
subClass.extend = this.extend;
return subClass;
};
/**
* @static
* @param {Object} obj Any object.
* @returns {Number} the number of properties on an object.
* @see http://stackoverflow.com/questions/5223/length-of-javascript-associative-array
*/
AjaxSolr.size = function (obj) {
var size = 0;
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
size++;
}
}
return size;
};
/**
* @static
* @param foo A value.
* @param bar A value.
* @returns {Boolean} Whether the two given values are equal.
*/
AjaxSolr.equals = function (foo, bar) {
if (AjaxSolr.isArray(foo) && AjaxSolr.isArray(bar)) {
if (foo.length !== bar.length) {
return false;
}
for (var i = 0, l = foo.length; i < l; i++) {
if (foo[i] !== bar[i]) {
return false;
}
}
return true;
}
else if (AjaxSolr.isRegExp(foo) && AjaxSolr.isString(bar)) {
return bar.match(foo);
}
else if (AjaxSolr.isRegExp(bar) && AjaxSolr.isString(foo)) {
return foo.match(bar);
}
else {
return foo === bar;
}
};
/**
* @static
* @param value A value.
* @param array An array.
* @returns {Boolean} Whether value exists in the array.
*/
AjaxSolr.inArray = function (value, array) {
if (array) {
for (var i = 0, l = array.length; i < l; i++) {
if (AjaxSolr.equals(array[i], value)) {
return i;
}
}
}
return -1;
};
/**
* A copy of MooTools' Array.flatten function.
*
* @static
* @see http://ajax.googleapis.com/ajax/libs/mootools/1.2.4/mootools.js
*/
AjaxSolr.flatten = function(array) {
var ret = [];
for (var i = 0, l = array.length; i < l; i++) {
ret = ret.concat(AjaxSolr.isArray(array[i]) ? AjaxSolr.flatten(array[i]) : array[i]);
}
return ret;
};
/**
* A copy of jQuery's jQuery.grep function.
*
* @static
* @see http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.js
*/
AjaxSolr.grep = function(array, callback) {
var ret = [];
for (var i = 0, l = array.length; i < l; i++) {
if (!callback(array[i], i) === false) {
ret.push(array[i]);
}
}
return ret;
}
/**
* Equivalent to Ruby's Array#compact.
*/
AjaxSolr.compact = function(array) {
return AjaxSolr.grep(array, function (item) {
return item.toString();
});
}
/**
* Can't use toString.call(obj) === "[object Array]", as it may return
* "[xpconnect wrapped native prototype]", which is undesirable.
*
* @static
* @see http://thinkweb2.com/projects/prototype/instanceof-considered-harmful-or-how-to-write-a-robust-isarray/
* @see http://ajax.googleapis.com/ajax/libs/prototype/1.6.0.3/prototype.js
*/
AjaxSolr.isArray = function (obj) {
return obj != null && typeof obj == 'object' && 'splice' in obj && 'join' in obj;
};
/**
* @param obj Any object.
* @returns {Boolean} Whether the object is a RegExp object.
*/
AjaxSolr.isRegExp = function (obj) {
return obj != null && (typeof obj == 'object' || typeof obj == 'function') && 'ignoreCase' in obj;
};
/**
* @param obj Any object.
* @returns {Boolean} Whether the object is a String object.
*/
AjaxSolr.isString = function (obj) {
return obj != null && typeof obj == 'string';
};
/**
* Define theme functions to separate, as much as possible, your HTML from your
* JavaScript. Theme functions provided by AJAX Solr are defined in the
* AjaxSolr.theme.prototype namespace, e.g. AjaxSolr.theme.prototype.select_tag.
*
* To override a theme function provided by AJAX Solr, define a function of the
* same name in the AjaxSolr.theme namespace, e.g. AjaxSolr.theme.select_tag.
*
* To retrieve the HTML output by AjaxSolr.theme.prototype.select_tag(...), call
* AjaxSolr.theme('select_tag', ...).
*
* @param {String} func
* The name of the theme function to call.
* @param ...
* Additional arguments to pass along to the theme function.
* @returns
* Any data the theme function returns. This could be a plain HTML string,
* but also a complex object.
*
* @static
* @throws Exception if the theme function is not defined.
* @see http://cvs.drupal.org/viewvc.py/drupal/drupal/misc/drupal.js?revision=1.58
*/
AjaxSolr.theme = function (func) {
for (var i = 1, args = []; i < arguments.length; i++) {
args.push(arguments[i]);
}
try {
return (AjaxSolr.theme[func] || AjaxSolr.theme.prototype[func]).apply(this, args);
}
catch (e) {
if (console && console.log) {
console.log('Theme function "' + func + '" is not defined.');
}
throw e;
}
};
/**
* A simplified version of jQuery's extend function.
*
* @static
* @see http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.js
*/
AjaxSolr.extend = function () {
var target = arguments[0] || {}, i = 1, length = arguments.length, options;
for (; i < length; i++) {
if ((options = arguments[i]) != null) {
for (var name in options) {
var src = target[name], copy = options[name];
if (target === copy) {
continue;
}
if (copy && typeof copy == 'object' && !copy.nodeType) {
target[name] = AjaxSolr.extend(src || (copy.length != null ? [] : {}), copy);
}
else if (copy !== undefined) {
target[name] = copy;
}
}
}
}
return target;
};

View File

@@ -1,168 +0,0 @@
/*
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
// $Id$
/**
* Represents a Solr parameter.
*
* @param properties A map of fields to set. Refer to the list of public fields.
* @class Parameter
*/
AjaxSolr.Parameter = AjaxSolr.Class.extend(
/** @lends AjaxSolr.Parameter.prototype */
{
/**
* The parameter's name.
*
* @field
* @private
* @type String
*/
name: null,
/**
* The parameter's value.
*
* @field
* @private
* @type String
*/
value: null,
/**
* The parameter's local parameters.
*
* @field
* @private
* @type Object
* @default {}
*/
locals: {},
/**
* Returns the value. If called with an argument, sets the value.
*
* @param {String|Number|String[]|Number[]} [value] The value to set.
* @returns The value.
*/
val: function (value) {
if (value === undefined) {
return this.value;
}
else {
this.value = value;
}
},
/**
* Returns the value of a local parameter. If called with a second argument,
* sets the value of a local parameter.
*
* @param {String} name The name of the local parameter.
* @param {String|Number|String[]|Number[]} [value] The value to set.
* @returns The value.
*/
local: function (name, value) {
if (value === undefined) {
return this.locals[name];
}
else {
this.locals[name] = value;
}
},
/**
* Deletes a local parameter.
*
* @param {String} name The name of the local parameter.
*/
remove: function (name) {
delete this.locals[name];
},
/**
* Returns the Solr parameter as a query string key-value pair.
*
* <p>IE6 calls the default toString() if you write <tt>store.toString()
* </tt>. So, we need to choose another name for toString().</p>
*/
string: function () {
var pairs = [];
for (var name in this.locals) {
if (this.locals[name]) {
pairs.push(name + '=' + encodeURIComponent(this.locals[name]));
}
}
var prefix = pairs.length ? '{!' + pairs.join('%20') + '}' : '';
if (this.value) {
return this.name + '=' + prefix + this.valueString(this.value);
}
// For dismax request handlers, if the q parameter has local params, the
// q parameter must be set to a non-empty value. In case the q parameter
// is empty, use the q.alt parameter, which accepts wildcards.
else if (this.name == 'q') {
return 'q.alt=' + prefix + encodeURIComponent('*.*');
}
else {
return '';
}
},
/**
* Parses a string formed by calling string().
*
* @param {String} str The string to parse.
*/
parseString: function (str) {
var param = str.match(/^([^=]+)=(?:\{!([^\}]*)\})?(.*)$/);
if (param) {
var matches;
while (matches = /([^\s=]+)=(\S*)/g.exec(decodeURIComponent(param[2]))) {
this.locals[matches[1]] = decodeURIComponent(matches[2]);
param[2] = param[2].replace(matches[0], ''); // Safari's exec seems not to do this on its own
}
if (param[1] == 'q.alt') {
this.name = 'q';
// if q.alt is present, assume it is because q was empty, as above
}
else {
this.name = param[1];
this.value = this.parseValueString(param[3]);
}
}
},
/**
* Returns the value as a URL-encoded string.
*
* @private
* @param {String|Number|String[]|Number[]} value The value.
* @returns {String} The URL-encoded string.
*/
valueString: function (value) {
value = AjaxSolr.isArray(value) ? value.join(',') : value;
return encodeURIComponent(value);
},
/**
* Parses a URL-encoded string to return the value.
*
* @private
* @param {String} str The URL-encoded string.
* @returns {Array} The value.
*/
parseValueString: function (str) {
str = decodeURIComponent(str);
return str.indexOf(',') == -1 ? str : str.split(',');
}
});

View File

@@ -1,361 +0,0 @@
/*
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
// $Id$
/**
* The ParameterStore, as its name suggests, stores Solr parameters. Widgets
* expose some of these parameters to the user. Whenever the user changes the
* values of these parameters, the state of the application changes. In order to
* allow the user to move back and forth between these states with the browser's
* Back and Forward buttons, and to bookmark these states, each state needs to
* be stored. The easiest method is to store the exposed parameters in the URL
* hash (see the <tt>ParameterHashStore</tt> class). However, you may implement
* your own storage method by extending this class.
*
* <p>For a list of possible parameters, please consult the links below.</p>
*
* @see http://wiki.apache.org/solr/CoreQueryParameters
* @see http://wiki.apache.org/solr/CommonQueryParameters
* @see http://wiki.apache.org/solr/SimpleFacetParameters
* @see http://wiki.apache.org/solr/HighlightingParameters
* @see http://wiki.apache.org/solr/MoreLikeThis
* @see http://wiki.apache.org/solr/SpellCheckComponent
* @see http://wiki.apache.org/solr/StatsComponent
* @see http://wiki.apache.org/solr/TermsComponent
* @see http://wiki.apache.org/solr/TermVectorComponent
* @see http://wiki.apache.org/solr/LocalParams
*
* @param properties A map of fields to set. Refer to the list of public fields.
* @class ParameterStore
*/
AjaxSolr.ParameterStore = AjaxSolr.Class.extend(
/** @lends AjaxSolr.ParameterStore.prototype */
{
/**
* The names of the exposed parameters. Any parameters that your widgets
* expose to the user, directly or indirectly, should be listed here.
*
* @field
* @public
* @type String[]
* @default []
*/
exposed: [],
/**
* The Solr parameters.
*
* @field
* @private
* @type Object
* @default {}
*/
params: {},
/**
* A reference to the parameter store's manager. For internal use only.
*
* @field
* @private
* @type AjaxSolr.AbstractManager
*/
manager: null,
/**
* An abstract hook for child implementations.
*
* <p>This method should do any necessary one-time initializations.</p>
*/
init: function () {},
/**
* Some Solr parameters may be specified multiple times. It is easiest to
* hard-code a list of such parameters. You may change the list by passing
* <code>{ multiple: /pattern/ }</code> as an argument to the constructor of
* this class or one of its children, e.g.:
*
* <p><code>new ParameterStore({ multiple: /pattern/ })</code>
*
* @param {String} name The name of the parameter.
* @returns {Boolean} Whether the parameter may be specified multiple times.
*/
isMultiple: function (name) {
return name.match(/^(?:bf|bq|facet\.date|facet\.date\.other|facet\.field|facet\.query|fq|pf|qf)$/);
},
/**
* Returns a parameter. If the parameter doesn't exist, creates it.
*
* @param {String} name The name of the parameter.
* @returns {AjaxSolr.Parameter|AjaxSolr.Parameter[]} The parameter.
*/
get: function (name) {
if (this.params[name] === undefined) {
var param = new AjaxSolr.Parameter({ name: name });
if (this.isMultiple(name)) {
this.params[name] = [ param ];
}
else {
this.params[name] = param;
}
}
return this.params[name];
},
/**
* If the parameter may be specified multiple times, returns the values of
* all identically-named parameters. If the parameter may be specified only
* once, returns the value of that parameter.
*
* @param {String} name The name of the parameter.
* @returns {String[]|Number[]} The value(s) of the parameter.
*/
values: function (name) {
if (this.params[name] !== undefined) {
if (this.isMultiple(name)) {
var values = [];
for (var i = 0, l = this.params[name].length; i < l; i++) {
values.push(this.params[name][i].val());
}
return values;
}
else {
return [ this.params[name].val() ];
}
}
return [];
},
/**
* If the parameter may be specified multiple times, adds the given parameter
* to the list of identically-named parameters, unless one already exists with
* the same value. If it may be specified only once, replaces the parameter.
*
* @param {String} name The name of the parameter.
* @param {AjaxSolr.Parameter} [param] The parameter.
* @returns {AjaxSolr.Parameter|Boolean} The parameter, or false.
*/
add: function (name, param) {
if (param === undefined) {
param = new AjaxSolr.Parameter({ name: name });
}
if (this.isMultiple(name)) {
if (this.params[name] === undefined) {
this.params[name] = [ param ];
}
else {
if (AjaxSolr.inArray(param.val(), this.values(name)) == -1) {
this.params[name].push(param);
}
else {
return false;
}
}
}
else {
this.params[name] = param;
}
return param;
},
/**
* Deletes a parameter.
*
* @param {String} name The name of the parameter.
* @param {Number} [index] The index of the parameter.
*/
remove: function (name, index) {
if (index === undefined) {
delete this.params[name];
}
else {
this.params[name].splice(index, 1);
if (this.params[name].length == 0) {
delete this.params[name];
}
}
},
/**
* Finds all parameters with matching values.
*
* @param {String} name The name of the parameter.
* @param {String|Number|String[]|Number[]|RegExp} value The value.
* @returns {String|Number[]} The indices of the parameters found.
*/
find: function (name, value) {
if (this.params[name] !== undefined) {
if (this.isMultiple(name)) {
var indices = [];
for (var i = 0, l = this.params[name].length; i < l; i++) {
if (AjaxSolr.equals(this.params[name][i].val(), value)) {
indices.push(i);
}
}
return indices.length ? indices : false;
}
else {
if (AjaxSolr.equals(this.params[name].val(), value)) {
return name;
}
}
}
return false;
},
/**
* If the parameter may be specified multiple times, creates a parameter using
* the given name and value, and adds it to the list of identically-named
* parameters, unless one already exists with the same value. If it may be
* specified only once, replaces the parameter.
*
* @param {String} name The name of the parameter.
* @param {String|Number|String[]|Number[]} value The value.
* @returns {AjaxSolr.Parameter|Boolean} The parameter, or false.
*/
addByValue: function (name, value) {
if (this.isMultiple(name) && AjaxSolr.isArray(value)) {
var ret = [];
for (var i = 0, l = value.length; i < l; i++) {
ret.push(this.add(name, new AjaxSolr.Parameter({ name: name, value: value[i] })));
}
return ret;
}
else {
return this.add(name, new AjaxSolr.Parameter({ name: name, value: value }))
}
},
/**
* Deletes any parameter with a matching value.
*
* @param {String} name The name of the parameter.
* @param {String|Number|String[]|Number[]|RegExp} value The value.
* @returns {String|Number[]} The indices deleted.
*/
removeByValue: function (name, value) {
var indices = this.find(name, value);
if (indices) {
if (AjaxSolr.isArray(indices)) {
for (var i = indices.length - 1; i >= 0; i--) {
this.remove(name, indices[i]);
}
}
else {
this.remove(indices);
}
}
return indices;
},
/**
* Returns the Solr parameters as a query string.
*
* <p>IE6 calls the default toString() if you write <tt>store.toString()
* </tt>. So, we need to choose another name for toString().</p>
*/
string: function () {
var params = [];
for (var name in this.params) {
if (this.isMultiple(name)) {
for (var i = 0, l = this.params[name].length; i < l; i++) {
params.push(this.params[name][i].string());
}
}
else {
params.push(this.params[name].string());
}
}
return AjaxSolr.compact(params).join('&');
},
/**
* Parses a query string into Solr parameters.
*
* @param {String} str The string to parse.
*/
parseString: function (str) {
var pairs = str.split('&');
for (var i = 0, l = pairs.length; i < l; i++) {
if (pairs[i]) { // ignore leading, trailing, and consecutive &'s
var param = new AjaxSolr.Parameter();
param.parseString(pairs[i]);
this.add(param.name, param);
}
}
},
/**
* Returns the exposed parameters as a query string.
*
* @returns {String} A string representation of the exposed parameters.
*/
exposedString: function () {
var params = [];
for (var i = 0, l = this.exposed.length; i < l; i++) {
if (this.params[this.exposed[i]] !== undefined) {
if (this.isMultiple(this.exposed[i])) {
for (var j = 0, m = this.params[this.exposed[i]].length; j < m; j++) {
params.push(this.params[this.exposed[i]][j].string());
}
}
else {
params.push(this.params[this.exposed[i]].string());
}
}
}
return AjaxSolr.compact(params).join('&');
},
/**
* Resets the values of the exposed parameters.
*/
exposedReset: function () {
for (var i = 0, l = this.exposed.length; i < l; i++) {
this.remove(this.exposed[i]);
}
},
/**
* Loads the values of exposed parameters from persistent storage. It is
* necessary, in most cases, to reset the values of exposed parameters before
* setting the parameters to the values in storage. This is to ensure that a
* parameter whose name is not present in storage is properly reset.
*
* @param {Boolean} [reset=true] Whether to reset the exposed parameters.
* before loading new values from persistent storage. Default: true.
*/
load: function (reset) {
if (reset === undefined) {
reset = true;
}
if (reset) {
this.exposedReset();
}
this.parseString(this.storedString());
},
/**
* An abstract hook for child implementations.
*
* <p>Stores the values of the exposed parameters in persistent storage. This
* method should usually be called before each Solr request.</p>
*/
save: function () {},
/**
* An abstract hook for child implementations.
*
* <p>Returns the string to parse from persistent storage.</p>
*
* @returns {String} The string from persistent storage.
*/
storedString: function () {
return '';
}
});

View File

@@ -1,28 +0,0 @@
/*
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
// $Id$
/**
* @see http://wiki.apache.org/solr/SolJSON#JSON_specific_parameters
* @class Manager
* @augments AjaxSolr.AbstractManager
*/
AjaxSolr.Manager = AjaxSolr.AbstractManager.extend(
/** @lends AjaxSolr.Manager.prototype */
{
executeRequest: function (servlet) {
var self = this;
if (this.proxyUrl) {
jQuery.post(this.proxyUrl, { query: this.store.string() }, function (data) { self.handleResponse(data); }, 'json');
}
else {
// jQuery.getJSON(this.solrUrl + servlet + '?' + this.store.string() + '&wt=json&json.wrf=?', {}, function (data) { self.handleResponse(data); });
jQuery.getJSON(this.solrUrl + '?' + this.store.string() + '&wt=json&json.wrf=?', {}, function (data) { self.handleResponse(data); });
}
}
});

View File

@@ -0,0 +1,158 @@
/*
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
(function ($) {
$(document).ready(function() {
initializeGear();
initializeFilters();
});
function initializeGear(){
var gearControlsDivs = $('div#aspect_discovery_SimpleSearch_div_search-controls-gear');
jQuery.each(gearControlsDivs, function(index, value) {
var gearControlsDiv = $(value);
var gearControls = gearControlsDiv.find('ul#aspect_discovery_SimpleSearch_list_sort-options');
var gearButton = $('<button class="discovery-controls-gear ds-button-field"><div class="gear-icon">&nbsp;</div></button>');
gearButton.click(function(){
if(gearControls.is(':visible')){
gearControls.hide();
}else{
gearControls.show();
}
return false;
});
//Disable the default click
gearControls.find('li.gear-option,li.gear-option a').click(function(event){
//Ensure that our html click isn't called !
event.stopPropagation();
var $link = $(this);
var listItem;
if($link.is('li')){
listItem = $link;
}else{
listItem = $link.parents('li:first');
}
//Check if this option is currently selected, if so skip the next stuff
if(listItem.hasClass('gear-option-selected')){
return false;
}
if(!$link.attr('href')){
$link = $link.find('a');
}
//Retrieve the params we are to fill in in our main form
var params = $link.attr('href').split('&');
var mainForm = $('form#aspect_discovery_SimpleSearch_div_main-form');
//Split them & fill in in the main form, when done submit the main form !
for(var i = 0; i < params.length; i++){
var param = params[i].split('=')[0];
var value = params[i].split('=')[1];
mainForm.find('input[name="' + param + '"]').val(value);
}
//Clear the page param
mainForm.find('input[name="page"]').val('1');
mainForm.submit();
return false;
});
gearButton.prependTo(gearControlsDiv);
gearControls.hide();
$('html').click(function() {
//Hide the menus if visible
if(gearControls.is(':visible')){
gearControls.hide();
}
});
});
}
function initializeFilters(){
//Initialize the show filters link
$('a[href="display-filters"]').click(function(){
var filtersForm = $('form#aspect_discovery_SimpleSearch_div_search-filters');
filtersForm.show();
filtersForm.css('visibility', 'visible');
$(this).hide();
return false;
});
$('input[name^="add-filter_"]').click(function(){
addFilterRow();
//Disable "normal" button actions
return false;
});
$('input[name^=remove-filter_]').click(function(){
removeFilterRow($(this));
return false;
});
//Disable the enter key !
$('input[name^=filter_][type=text]').keypress(function(event){
if(event.which == 13){
//Entered pressed, do NOT submit the form, add a new filter instead !
addFilterRow();
event.preventDefault();
}
});
}
function removeFilterRow(button){
var parentRow = button.parents('tr:first');
//Check if we are removing a new filter AND our last new filter at that, if so removes values instead of the row
if(parentRow.is('[id^="aspect_discovery_SimpleSearch_row_filter-new-"]')
&& parentRow.parents('table:first').find('tr[id^="aspect_discovery_SimpleSearch_row_filter-new-"]').length == 1){
//Hide ourselves & clear our values!
parentRow.find('input[type=text]", select').val('');
}else{
parentRow.remove();
}
}
function addFilterRow(){
var previousFilterRow = $('tr#aspect_discovery_SimpleSearch_row_filter-controls').prev();
//Duplicate our element & give it a new index !
var newFilterRow = previousFilterRow.clone();
//Alter the html to update the index
var rowIdentifier = newFilterRow.attr('id');
var oldIndex = parseInt(rowIdentifier.substr(rowIdentifier.lastIndexOf('-')+1, rowIdentifier.length));
//Add one to the index !
var newIndex = oldIndex + 1;
//Update the index of all inputs & our list
newFilterRow.attr('id', newFilterRow.attr('id').replace('-' + oldIndex, '-' + newIndex));
newFilterRow.find('input, select').each(function(){
var $this = $(this);
//Update the index of the name (if present)
$this.attr('name', $this.attr('name').replace('_' + oldIndex, '_' + newIndex));
$this.attr('id', $this.attr('id').replace('_' + oldIndex, '_' + newIndex));
});
//Clear the values
newFilterRow.find('input[type=text], select').val('');
previousFilterRow = newFilterRow.insertAfter(previousFilterRow);
//Initialize the add button
previousFilterRow.find('input[name^="add-filter_"]').click(function(){
addFilterRow();
return false;
});
//Initialize the remove button
previousFilterRow.find('input[name^=remove-filter_]').click(function(){
removeFilterRow($(this));
return false;
});
}
})(jQuery);

View File

@@ -1,133 +0,0 @@
/*
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
var Manager;
var query;
var defaultFacets = new Array();
(function ($) {
$(function () {
var searchUrl = $("input[name='discovery-json-search-url']").val();
Manager = new AjaxSolr.Manager({
solrUrl: searchUrl
});
//Retrieve our filterSelect, which contains all the types to be sorted on
var filterSelect = $("select[id='aspect_discovery_SimpleSearch_field_filtertype']");
//Get our filters
/*
var filterOptions = filterSelect.find('option');
//Get all the
for (var index = 1; index < filterOptions.length; index++){
//We skip the first one (for the moment)
defaultFacets[index - 1] = filterOptions[index].value;
}
*/
//As a default facet we use the selected value
defaultFacets[0] = filterSelect.find('option:selected').val();
var widget = Manager.addWidget(new AjaxSolr.AutocompleteWidget({
id: 'text',
target: 'li#aspect_discovery_SimpleSearch_item_search-filter-list',
field: 'allText',
fields: defaultFacets
}));
Manager.init();
query = $('input#aspect_discovery_SimpleSearch_field_query').val();
if(query == '')
query = '*:*';
Manager.store.addByValue('q', query);
//Retrieve our filter queries
var fqs = $("input[name='fq']");
for(var j = 0; j < fqs.length; j ++){
Manager.store.addByValue('fq', $(fqs[j]).val());
}
Manager.store.addByValue('facet.sort', 'count');
var params = {
facet: true,
'facet.field': defaultFacets,
'facet.limit': 20,
'facet.mincount': 1,
'f.topics.facet.limit': 50,
'json.nl': 'map'
};
for (var name in params) {
Manager.store.addByValue(name, params[name]);
}
//Attempt to add our scope !
var scope = $("input[name='discovery-json-scope']").val();
if(scope != undefined){
Manager.store.addByValue("scope", scope);
}
Manager.doRequest();
filterSelect.change(function() {
// TODO: this is dirty, but with lack of time the best I could do
var oldInput = $('input#aspect_discovery_SimpleSearch_field_filter');
var newInput = oldInput.clone(false);
// newInput.val(oldInput.val());
newInput.appendTo(oldInput.parent());
oldInput.remove();
//Remove any results lists we may still have standing
$("div#discovery_autocomplete_div").remove();
//Put the field in which our facet is going to facet into the widget
var facetFields;
if($(this).val() != '*'){
var facetVal = $(this).val();
//Only facet on autocomplete fields
// if(!facetVal.match(/.year$/)){
// facetVal += '_ac';
// }
facetFields = [facetVal];
} else {
facetFields = defaultFacets;
}
Manager.widgets.text.fields = facetFields;
Manager.initialized = false;
Manager.init();
//TODO: does this need to happen twice ?
Manager.store.addByValue('q', query);
//Retrieve our filter queries
var fqs = $("input[name='fq']");
for(var j = 0; j < fqs.length; j ++){
Manager.store.addByValue('fq', $(fqs[j]).val());
}
Manager.store.addByValue('facet.sort', 'count');
var params = {
facet: true,
'facet.field': facetFields,
'facet.limit': 20,
'facet.mincount': 1,
'f.topics.facet.limit': 50,
'json.nl': 'map'
};
for (var name in params) {
Manager.store.addByValue(name, params[name]);
}
//Attempt to add our scope !
var scope = $("input[name='discovery-json-scope']").val();
if(scope != undefined){
Manager.store.addByValue("scope", scope);
}
Manager.doRequest();
});
});
})(jQuery);

View File

@@ -1,75 +0,0 @@
/*
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
(function ($) {
AjaxSolr.AutocompleteWidget = AjaxSolr.AbstractFacetWidget.extend({
afterRequest: function () {
$(this.target).find("input[type='text']").val('');
var self = this;
var callback = function (response) {
var list = [];
for (var field in response.facet_counts.facet_fields) {
for (var facet in response.facet_counts.facet_fields[field]) {
list.push({
field: field,
value: facet,
text: facet + ' (' + response.facet_counts.facet_fields[field][facet] + ')'
});
}
}
self.requestSent = false;
$(self.target).find("input[type='text']").autocomplete(list, {
formatItem: function(facet) {
return facet.text;
}
}).result(function(e, facet) {
$(this).val(facet.value);
// self.requestSent = true;
// if (self.manager.store.addByValue('fq', facet.field + ':' + facet.value)) {
// self.manager.doRequest(0);
// }
}).bind('keydown', function(e) {
if (self.requestSent === false && e.which == 13) {
var value = $(this).val();
if (value && self.add(value)) {
self.manager.doRequest(0);
}
}
});
}; // end callback
var params = [ 'q=' + query + '&facet=true&facet.limit=-1&facet.sort=count&facet.mincount=1&json.nl=map' ];
for (var i = 0; i < this.fields.length; i++) {
params.push('facet.field=' + this.fields[i]);
}
var fqs = $("input[name='fq']");
for(var j = 0; j < fqs.length; j ++){
params.push('fq=' + encodeURIComponent($(fqs[j]).val()));
}
//Attempt to add our scope !
var scope = $("input[name='discovery-json-scope']").val();
if(scope != undefined){
params.push("scope=" + scope);
}
// jQuery.getJSON(this.manager.solrUrl + 'select?' + params.join('&') + '&wt=json&json.wrf=?', {}, callback);
jQuery.getJSON(this.manager.solrUrl + '?' + params.join('&') + '&wt=json&json.wrf=?', {}, callback);
}
});
})(jQuery);

View File

@@ -1,20 +0,0 @@
Copyright (c) 2010 John Resig, http://jquery.com/
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -1,799 +0,0 @@
;(function($) {
$.fn.extend({
autocomplete: function(urlOrData, options) {
var isUrl = typeof urlOrData == "string";
options = $.extend({}, $.Autocompleter.defaults, {
url: isUrl ? urlOrData : null,
data: isUrl ? null : urlOrData,
delay: isUrl ? $.Autocompleter.defaults.delay : 10,
max: options && !options.scroll ? 10 : 150
}, options);
// if highlight is set to false, replace it with a do-nothing function
options.highlight = options.highlight || function(value) { return value; };
// if the formatMatch option is not specified, then use formatItem for backwards compatibility
options.formatMatch = options.formatMatch || options.formatItem;
return this.each(function() {
new $.Autocompleter(this, options);
});
},
result: function(handler) {
return this.bind("result", handler);
},
search: function(handler) {
return this.trigger("search", [handler]);
},
flushCache: function() {
return this.trigger("flushCache");
},
setOptions: function(options){
return this.trigger("setOptions", [options]);
},
unautocomplete: function() {
return this.trigger("unautocomplete");
}
});
$.Autocompleter = function(input, options) {
var KEY = {
UP: 38,
DOWN: 40,
DEL: 46,
TAB: 9,
RETURN: 13,
ESC: 27,
COMMA: 188,
PAGEUP: 33,
PAGEDOWN: 34,
BACKSPACE: 8
};
// Create $ object for input element
var $input = $(input).attr("autocomplete", "off").addClass(options.inputClass);
var timeout;
var previousValue = "";
var cache = $.Autocompleter.Cache(options);
var hasFocus = 0;
var lastKeyPressCode;
var config = {
mouseDownOnSelect: false
};
var select = $.Autocompleter.Select(options, input, selectCurrent, config);
var blockSubmit;
// prevent form submit in opera when selecting with return key
$.browser.opera && $(input.form).bind("submit.autocomplete", function() {
if (blockSubmit) {
blockSubmit = false;
return false;
}
});
// only opera doesn't trigger keydown multiple times while pressed, others don't work with keypress at all
$input.bind(($.browser.opera ? "keypress" : "keydown") + ".autocomplete", function(event) {
// a keypress means the input has focus
// avoids issue where input had focus before the autocomplete was applied
hasFocus = 1;
// track last key pressed
lastKeyPressCode = event.keyCode;
switch(event.keyCode) {
case KEY.UP:
event.preventDefault();
if ( select.visible() ) {
select.prev();
} else {
onChange(0, true);
}
break;
case KEY.DOWN:
event.preventDefault();
if ( select.visible() ) {
select.next();
} else {
onChange(0, true);
}
break;
case KEY.PAGEUP:
event.preventDefault();
if ( select.visible() ) {
select.pageUp();
} else {
onChange(0, true);
}
break;
case KEY.PAGEDOWN:
event.preventDefault();
if ( select.visible() ) {
select.pageDown();
} else {
onChange(0, true);
}
break;
// matches also semicolon
case options.multiple && $.trim(options.multipleSeparator) == "," && KEY.COMMA:
case KEY.TAB:
case KEY.RETURN:
if( selectCurrent() ) {
// stop default to prevent a form submit, Opera needs special handling
event.preventDefault();
blockSubmit = true;
return false;
}
break;
case KEY.ESC:
select.hide();
break;
default:
clearTimeout(timeout);
timeout = setTimeout(onChange, options.delay);
break;
}
}).focus(function(){
// track whether the field has focus, we shouldn't process any
// results if the field no longer has focus
hasFocus++;
}).blur(function() {
hasFocus = 0;
if (!config.mouseDownOnSelect) {
hideResults();
}
}).click(function() {
// show select when clicking in a focused field
if ( hasFocus++ > 1 && !select.visible() ) {
onChange(0, true);
}
}).bind("search", function() {
// TODO why not just specifying both arguments?
var fn = (arguments.length > 1) ? arguments[1] : null;
function findValueCallback(q, data) {
var result;
if( data && data.length ) {
for (var i=0; i < data.length; i++) {
if( data[i].result.toLowerCase() == q.toLowerCase() ) {
result = data[i];
break;
}
}
}
if( typeof fn == "function" ) fn(result);
else $input.trigger("result", result && [result.data, result.value]);
}
$.each(trimWords($input.val()), function(i, value) {
request(value, findValueCallback, findValueCallback);
});
}).bind("flushCache", function() {
cache.flush();
}).bind("setOptions", function() {
$.extend(options, arguments[1]);
// if we've updated the data, repopulate
if ( "data" in arguments[1] )
cache.populate();
}).bind("unautocomplete", function() {
select.unbind();
$input.unbind();
$(input.form).unbind(".autocomplete");
});
function selectCurrent() {
var selected = select.selected();
if( !selected )
return false;
var v = selected.result;
previousValue = v;
if ( options.multiple ) {
var words = trimWords($input.val());
if ( words.length > 1 ) {
var separator = options.multipleSeparator.length;
var cursorAt = $(input).selection().start;
var wordAt, progress = 0;
$.each(words, function(i, word) {
progress += word.length;
if (cursorAt <= progress) {
wordAt = i;
return false;
}
progress += separator;
});
words[wordAt] = v;
// TODO this should set the cursor to the right position, but it gets overriden somewhere
//$.Autocompleter.Selection(input, progress + separator, progress + separator);
v = words.join( options.multipleSeparator );
}
v += options.multipleSeparator;
}
$input.val(v);
hideResultsNow();
$input.trigger("result", [selected.data, selected.value]);
return true;
}
function onChange(crap, skipPrevCheck) {
if( lastKeyPressCode == KEY.DEL ) {
select.hide();
return;
}
var currentValue = $input.val();
if ( !skipPrevCheck && currentValue == previousValue )
return;
previousValue = currentValue;
currentValue = lastWord(currentValue);
if ( currentValue.length >= options.minChars) {
$input.addClass(options.loadingClass);
if (!options.matchCase)
currentValue = currentValue.toLowerCase();
request(currentValue, receiveData, hideResultsNow);
} else {
stopLoading();
select.hide();
}
};
function trimWords(value) {
if (!value)
return [""];
if (!options.multiple)
return [$.trim(value)];
return $.map(value.split(options.multipleSeparator), function(word) {
return $.trim(value).length ? $.trim(word) : null;
});
}
function lastWord(value) {
if ( !options.multiple )
return value;
var words = trimWords(value);
if (words.length == 1)
return words[0];
var cursorAt = $(input).selection().start;
if (cursorAt == value.length) {
words = trimWords(value)
} else {
words = trimWords(value.replace(value.substring(cursorAt), ""));
}
return words[words.length - 1];
}
// fills in the input box w/the first match (assumed to be the best match)
// q: the term entered
// sValue: the first matching result
function autoFill(q, sValue){
// autofill in the complete box w/the first match as long as the user hasn't entered in more data
// if the last user key pressed was backspace, don't autofill
if( options.autoFill && (lastWord($input.val()).toLowerCase() == q.toLowerCase()) && lastKeyPressCode != KEY.BACKSPACE ) {
// fill in the value (keep the case the user has typed)
$input.val($input.val() + sValue.substring(lastWord(previousValue).length));
// select the portion of the value not typed by the user (so the next character will erase)
$(input).selection(previousValue.length, previousValue.length + sValue.length);
}
};
function hideResults() {
clearTimeout(timeout);
timeout = setTimeout(hideResultsNow, 200);
};
function hideResultsNow() {
var wasVisible = select.visible();
select.hide();
clearTimeout(timeout);
stopLoading();
if (options.mustMatch) {
// call search and run callback
$input.search(
function (result){
// if no value found, clear the input box
if( !result ) {
if (options.multiple) {
var words = trimWords($input.val()).slice(0, -1);
$input.val( words.join(options.multipleSeparator) + (words.length ? options.multipleSeparator : "") );
}
else {
$input.val( "" );
$input.trigger("result", null);
}
}
}
);
}
};
function receiveData(q, data) {
if ( data && data.length && hasFocus ) {
stopLoading();
select.display(data, q);
autoFill(q, data[0].value);
select.show();
} else {
hideResultsNow();
}
};
function request(term, success, failure) {
if (!options.matchCase)
term = term.toLowerCase();
var data = cache.load(term);
// receive the cached data
if (data && data.length) {
success(term, data);
// if an AJAX url has been supplied, try loading the data now
} else if( (typeof options.url == "string") && (options.url.length > 0) ){
var extraParams = {
timestamp: +new Date()
};
$.each(options.extraParams, function(key, param) {
extraParams[key] = typeof param == "function" ? param() : param;
});
$.ajax({
// try to leverage ajaxQueue plugin to abort previous requests
mode: "abort",
// limit abortion to this input
port: "autocomplete" + input.name,
dataType: options.dataType,
url: options.url,
data: $.extend({
q: lastWord(term),
limit: options.max
}, extraParams),
success: function(data) {
var parsed = options.parse && options.parse(data) || parse(data);
cache.add(term, parsed);
success(term, parsed);
}
});
} else {
// if we have a failure, we need to empty the list -- this prevents the the [TAB] key from selecting the last successful match
select.emptyList();
failure(term);
}
};
function parse(data) {
var parsed = [];
var rows = data.split("\n");
for (var i=0; i < rows.length; i++) {
var row = $.trim(rows[i]);
if (row) {
row = row.split("|");
parsed[parsed.length] = {
data: row,
value: row[0],
result: options.formatResult && options.formatResult(row, row[0]) || row[0]
};
}
}
return parsed;
};
function stopLoading() {
$input.removeClass(options.loadingClass);
};
};
$.Autocompleter.defaults = {
inputClass: "ac_input",
resultId: "discovery_autocomplete_div",
resultsClass: "ac_results",
loadingClass: "ac_loading",
minChars: 1,
delay: 400,
matchCase: false,
matchSubset: true,
matchContains: false,
cacheLength: 10,
max: 100,
mustMatch: false,
extraParams: {},
selectFirst: true,
formatItem: function(row) { return row[0]; },
formatMatch: null,
autoFill: false,
width: 0,
multiple: false,
multipleSeparator: ", ",
highlight: function(value, term) {
return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
},
scroll: true,
scrollHeight: 180
};
$.Autocompleter.Cache = function(options) {
var data = {};
var length = 0;
function matchSubset(s, sub) {
if (!options.matchCase)
s = s.toLowerCase();
var i = s.indexOf(sub);
if (options.matchContains == "word"){
i = s.toLowerCase().search("\\b" + sub.toLowerCase());
}
if (i == -1) return false;
return i == 0 || options.matchContains;
};
function add(q, value) {
if (length > options.cacheLength){
flush();
}
if (!data[q]){
length++;
}
data[q] = value;
}
function populate(){
if( !options.data ) return false;
// track the matches
var stMatchSets = {},
nullData = 0;
// no url was specified, we need to adjust the cache length to make sure it fits the local data store
if( !options.url ) options.cacheLength = 1;
// track all options for minChars = 0
stMatchSets[""] = [];
// loop through the array and create a lookup structure
for ( var i = 0, ol = options.data.length; i < ol; i++ ) {
var rawValue = options.data[i];
// if rawValue is a string, make an array otherwise just reference the array
rawValue = (typeof rawValue == "string") ? [rawValue] : rawValue;
var value = options.formatMatch(rawValue, i+1, options.data.length);
if ( value === false )
continue;
var firstChar = value.charAt(0).toLowerCase();
// if no lookup array for this character exists, look it up now
if( !stMatchSets[firstChar] )
stMatchSets[firstChar] = [];
// if the match is a string
var row = {
value: value,
data: rawValue,
result: options.formatResult && options.formatResult(rawValue) || value
};
// push the current match into the set list
stMatchSets[firstChar].push(row);
// keep track of minChars zero items
if ( nullData++ < options.max ) {
stMatchSets[""].push(row);
}
};
// add the data items to the cache
$.each(stMatchSets, function(i, value) {
// increase the cache size
options.cacheLength++;
// add to the cache
add(i, value);
});
}
// populate any existing data
setTimeout(populate, 25);
function flush(){
data = {};
length = 0;
}
return {
flush: flush,
add: add,
populate: populate,
load: function(q) {
if (!options.cacheLength || !length)
return null;
/*
* if dealing w/local data and matchContains than we must make sure
* to loop through all the data collections looking for matches
*/
if( !options.url && options.matchContains ){
// track all matches
var csub = [];
// loop through all the data grids for matches
for( var k in data ){
// don't search through the stMatchSets[""] (minChars: 0) cache
// this prevents duplicates
if( k.length > 0 ){
var c = data[k];
$.each(c, function(i, x) {
// if we've got a match, add it to the array
if (matchSubset(x.value, q)) {
csub.push(x);
}
});
}
}
return csub;
} else
// if the exact item exists, use it
if (data[q]){
return data[q];
} else
if (options.matchSubset) {
for (var i = q.length - 1; i >= options.minChars; i--) {
var c = data[q.substr(0, i)];
if (c) {
var csub = [];
$.each(c, function(i, x) {
if (matchSubset(x.value, q)) {
csub[csub.length] = x;
}
});
return csub;
}
}
}
return null;
}
};
};
$.Autocompleter.Select = function (options, input, select, config) {
var CLASSES = {
ACTIVE: "ac_over"
};
var listItems,
active = -1,
data,
term = "",
needsInit = true,
element,
list;
// Create results
function init() {
if (!needsInit)
return;
element = $("<div/>")
.hide()
.addClass(options.resultsClass)
.attr("id", options.resultId)
.css("position", "absolute")
.appendTo(document.body);
list = $("<ul/>").appendTo(element).mouseover( function(event) {
if(target(event).nodeName && target(event).nodeName.toUpperCase() == 'LI') {
active = $("li", list).removeClass(CLASSES.ACTIVE).index(target(event));
$(target(event)).addClass(CLASSES.ACTIVE);
}
}).click(function(event) {
$(target(event)).addClass(CLASSES.ACTIVE);
select();
// TODO provide option to avoid setting focus again after selection? useful for cleanup-on-focus
input.focus();
return false;
}).mousedown(function() {
config.mouseDownOnSelect = true;
}).mouseup(function() {
config.mouseDownOnSelect = false;
});
if( options.width > 0 )
element.css("width", options.width);
needsInit = false;
}
function target(event) {
var element = event.target;
while(element && element.tagName != "LI")
element = element.parentNode;
// more fun with IE, sometimes event.target is empty, just ignore it then
if(!element)
return [];
return element;
}
function moveSelect(step) {
listItems.slice(active, active + 1).removeClass(CLASSES.ACTIVE);
movePosition(step);
var activeItem = listItems.slice(active, active + 1).addClass(CLASSES.ACTIVE);
if(options.scroll) {
var offset = 0;
listItems.slice(0, active).each(function() {
offset += this.offsetHeight;
});
if((offset + activeItem[0].offsetHeight - list.scrollTop()) > list[0].clientHeight) {
list.scrollTop(offset + activeItem[0].offsetHeight - list.innerHeight());
} else if(offset < list.scrollTop()) {
list.scrollTop(offset);
}
}
};
function movePosition(step) {
active += step;
if (active < 0) {
active = listItems.size() - 1;
} else if (active >= listItems.size()) {
active = 0;
}
}
function limitNumberOfItems(available) {
return options.max && options.max < available
? options.max
: available;
}
function fillList() {
list.empty();
var max = limitNumberOfItems(data.length);
for (var i=0; i < max; i++) {
if (!data[i])
continue;
var formatted = options.formatItem(data[i].data, i+1, max, data[i].value, term);
if ( formatted === false )
continue;
var li = $("<li/>").html( options.highlight(formatted, term) ).addClass(i%2 == 0 ? "ac_even" : "ac_odd").appendTo(list)[0];
$.data(li, "ac_data", data[i]);
}
listItems = list.find("li");
if ( options.selectFirst ) {
listItems.slice(0, 1).addClass(CLASSES.ACTIVE);
active = 0;
}
// apply bgiframe if available
if ( $.fn.bgiframe )
list.bgiframe();
}
return {
display: function(d, q) {
init();
data = d;
term = q;
fillList();
},
next: function() {
moveSelect(1);
},
prev: function() {
moveSelect(-1);
},
pageUp: function() {
if (active != 0 && active - 8 < 0) {
moveSelect( -active );
} else {
moveSelect(-8);
}
},
pageDown: function() {
if (active != listItems.size() - 1 && active + 8 > listItems.size()) {
moveSelect( listItems.size() - 1 - active );
} else {
moveSelect(8);
}
},
hide: function() {
element && element.hide();
listItems && listItems.removeClass(CLASSES.ACTIVE);
active = -1;
},
visible : function() {
return element && element.is(":visible");
},
current: function() {
return this.visible() && (listItems.filter("." + CLASSES.ACTIVE)[0] || options.selectFirst && listItems[0]);
},
show: function() {
var offset = $(input).offset();
element.css({
width: typeof options.width == "string" || options.width > 0 ? options.width : $(input).width(),
top: offset.top + input.offsetHeight,
left: offset.left
}).show();
if(options.scroll) {
list.scrollTop(0);
list.css({
maxHeight: options.scrollHeight,
overflow: 'auto'
});
if($.browser.msie && typeof document.body.style.maxHeight === "undefined") {
var listHeight = 0;
listItems.each(function() {
listHeight += this.offsetHeight;
});
var scrollbarsVisible = listHeight > options.scrollHeight;
list.css('height', scrollbarsVisible ? options.scrollHeight : listHeight );
if (!scrollbarsVisible) {
// IE doesn't recalculate width when scrollbar disappears
listItems.width( list.width() - parseInt(listItems.css("padding-left")) - parseInt(listItems.css("padding-right")) );
}
}
}
},
selected: function() {
var selected = listItems && listItems.filter("." + CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE);
return selected && selected.length && $.data(selected[0], "ac_data");
},
emptyList: function (){
list && list.empty();
},
unbind: function() {
element && element.remove();
}
};
};
$.fn.selection = function(start, end) {
if (start !== undefined) {
return this.each(function() {
if( this.createTextRange ){
var selRange = this.createTextRange();
if (end === undefined || start == end) {
selRange.move("character", start);
selRange.select();
} else {
selRange.collapse(true);
selRange.moveStart("character", start);
selRange.moveEnd("character", end);
selRange.select();
}
} else if( this.setSelectionRange ){
this.setSelectionRange(start, end);
} else if( this.selectionStart ){
this.selectionStart = start;
this.selectionEnd = end;
}
});
}
var field = this[0];
if ( field.createTextRange ) {
var range = document.selection.createRange(),
orig = field.value,
teststring = "<->",
textLength = range.text.length;
range.text = teststring;
var caretAt = field.value.indexOf(teststring);
field.value = orig;
this.selection(caretAt, caretAt + textLength);
return {
start: caretAt,
end: caretAt + textLength
}
} else if( field.selectionStart !== undefined ){
return {
start: field.selectionStart,
end: field.selectionEnd
}
}
};
})(jQuery);

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@@ -288,6 +288,8 @@ div.pagination {
div.pagination-masked { div.pagination-masked {
position: relative; position: relative;
margin: 10px 20px 10px 20px; margin: 10px 20px 10px 20px;
/*Property below is required for IE7 when using discovery*/
z-index: 9999;
} }
a.previous-page-link { a.previous-page-link {
@@ -886,3 +888,81 @@ margin: 2px 2px 0px 2px;
/* border: 1px solid rgb(240, 240, 210); */ /* border: 1px solid rgb(240, 240, 210); */
} }
/* Start discovery layout DSpace 3.x*/
div.discoverySearchBox label{
width: auto;
}
input#aspect_discovery_SimpleSearch_field_query{
width: 700px;
}
input.search-icon{
background-image: url('../images/search_icon_000000_20x20.png');
background-repeat: no-repeat;
background-position: center center;
text-indent: -1000px;
/*Css props below are required for IE*/
font-size: 0;
line-height: 0;
background-color: #F3F3F3;
border: 1px solid #000000;
}
div.controls-gear-wrapper{
float: none;
position: absolute;
top: 0;
}
div.gear-icon{
background-image: url('../images/gear_000000_25x25.png');
}
ul.gear-selection li.gear-option-selected{
background: url('../images/check_606060_15x15.png') no-repeat 3px center;
}
table.discovery-filters input.filter-control {
width: 30px;
margin-left: 5px;
text-indent: -1000px;
background-repeat: no-repeat;
background-position: center center;
height: 22px;
float: left;
/*Css props below are required for IE*/
font-size: 0;
display:block;
line-height: 0;
}
table.discovery-filters input.filter-control.filter-remove{
margin-left: 15px;
background-image: url('../images/remove_icon_000000_16x16.png');
background-color: #F3F3F3;
border: 1px solid #000000;
}
table.discovery-filters input.filter-control.filter-add{
background-image: url('../images/plus_icon_000000_16x16.png');
background-color: #F3F3F3;
border: 1px solid #000000;
}
ul.gear-selection{
left: 0;
right: auto;
}
ul.gear-selection li {
margin-left: 0;
}
div#aspect_discovery_SimpleSearch_div_search a.previous-page-link {
left: 80px;
}
/* End discovery layout DSpace 3.x*/

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@@ -816,52 +816,73 @@ td select.ds-select-field {
margin-left: 5px; margin-left: 5px;
} }
form.search { form.search,
div.discoverySearchBox
{
background-color: #fafafa; background-color: #fafafa;
border: 1px solid #ebebeb; border: 1px solid #ebebeb;
padding: 10px; padding: 10px;
margin-bottom: 15px; margin-bottom: 15px;
} }
form.search label { form.search label,
div.discoverySearchBox label
{
font-weight: bold; font-weight: bold;
} }
form.search p.ds-paragraph.button-list { form.search p.ds-paragraph.button-list,
div.discoverySearchBox p.ds-paragraph.button-list
{
text-align: center; text-align: center;
margin: 0; margin: 0;
} }
form.search fieldset { form.search fieldset,
div.discoverySearchBox fieldset {
margin: 0; margin: 0;
} }
form.search .ds-form-item { form.search .ds-form-item,
div.discoverySearchBox .ds-form-item
{
margin: 0; margin: 0;
padding-bottom: 5px; padding-bottom: 5px;
} }
form.search .ds-form-item select{ form.search .ds-form-item select,
div.discoverySearchBox .ds-form-item select
{
margin-top: 0; margin-top: 0;
} }
form.search label.ds-composite-component .ds-select-field{ form.search label.ds-composite-component .ds-select-field,
div.discoverySearchBox label.ds-composite-component .ds-select-field
{
margin-top: 6px; margin-top: 6px;
} }
form.search .ds-form-item label { form.search .ds-form-item label,
div.discoverySearchBox .ds-form-item label
{
font-size: 100%; font-size: 100%;
} }
form.search .ds-form-content { form.search .ds-form-content,
div.discoverySearchBox .ds-form-content
{
display: inline; display: inline;
} }
form.search table input.ds-text-field { form.search table input.ds-text-field,
div.discoverySearchBox table input.ds-text-field
{
margin: 0; margin: 0;
} }
form.search .field-help { form.search .field-help,
div.discoverySearchBox .field-help
{
margin: 3px 0; margin: 3px 0;
} }
@@ -1071,11 +1092,6 @@ form.discover-search-box{
margin-bottom: 10px; margin-bottom: 10px;
} }
li.search-filter-list,
li.used-filters-list
{
padding-top: 5px;
}
form.discover-sort-box select{ form.discover-sort-box select{
margin: 0 4px; margin: 0 4px;
@@ -1183,3 +1199,111 @@ margin: 2px 2px 0px 2px;
{ {
border: 1px solid lightgray; border: 1px solid lightgray;
} }
span.highlight{
font-weight: bold;
}
div.gear-icon{
background-image: url('../../images/gear_ffffff_25x25.png');
}
ul.gear-selection li.gear-option-selected{
background: url('../../images/check_606060_15x15.png') no-repeat 3px center;
}
input#aspect_discovery_SimpleSearch_field_query{
width: 565px;
}
input.search-icon{
background-image: url('../../images/search_icon_ffffff_20x20.png');
background-repeat: no-repeat;
background-position: center center;
text-indent: -1000px;
/*Css props below are required for IE*/
font-size: 0;
display:block;
line-height: 0;
}
div#aspect_discovery_SimpleSearch_div_search p.pagination-info{
display: none;
}
div#aspect_discovery_SimpleSearch_div_search .pagination-links{
float: left;
}
table.discovery-filters{
width: 100%;
background-color: #FFFFFF;
}
table.discovery-filters tr{
border-top: 1px solid #EBEBEB;
}
table.discovery-filters td{
padding: 0;
}
table.discovery-filters td.selection{
width: 1%;
}
table.discovery-filters th.new-filter-header{
text-align: left;
padding-top: 20px;
}
table.discovery-filters td.discovery-filter-input-cell {
padding-left: 3px;
}
table.discovery-filters tr.apply-filter{
background-color: #FAFAFA;
}
table.discovery-filters tr.apply-filter input{
width: 75px;
height: 33px;
margin-left: 5px;
font-size: 108%;
}
table.discovery-filters td.filter-controls{
width: 80px;
}
table.discovery-filters input.filter-control {
width: 30px;
margin-left: 5px;
text-indent: -1000px;
background-repeat: no-repeat;
background-position: center center;
height: 22px;
float: left;
/*Css props below are required for IE*/
font-size: 0;
display:block;
line-height: 0;
}
table.discovery-filters input.filter-control.filter-remove{
margin-left: 15px;
background-image: url('../../images/remove_icon_ffffff_16x16.png');
}
table.discovery-filters input.filter-control.filter-add{
background-image: url('../../images/plus_icon_ffffff_16x16.png');
}
.searchTime{
color: #999999;
}

View File

@@ -180,9 +180,29 @@
</xsl:if> </xsl:if>
</ul> </ul>
<xsl:if test="parent::node()/dri:div[@n = 'masked-page-control']">
<xsl:apply-templates select="parent::node()/dri:div[@n='masked-page-control']/dri:div">
<xsl:with-param name="position" select="$position"/>
</xsl:apply-templates>
</xsl:if>
</div> </div>
</xsl:when> </xsl:when>
</xsl:choose> </xsl:choose>
</xsl:template> </xsl:template>
<xsl:template match="dri:div[@n = 'masked-page-control']">
<!--Do not render this division, this is handled by the xsl-->
</xsl:template>
<xsl:template match="dri:div[@n ='search-controls-gear']">
<xsl:param name="position"/>
<div>
<xsl:call-template name="standardAttributes">
<xsl:with-param name="class"><xsl:value-of select="$position"/></xsl:with-param>
</xsl:call-template>
<xsl:apply-templates/>
</div>
</xsl:template>
</xsl:stylesheet> </xsl:stylesheet>

View File

@@ -44,87 +44,89 @@
<xsl:template match="dri:options"> <xsl:template match="dri:options">
<div id="ds-options-wrapper"> <div id="ds-options-wrapper">
<div id="ds-options"> <div id="ds-options">
<h1 id="ds-search-option-head" class="ds-option-set-head"> <xsl:if test="not(contains(/dri:document/dri:meta/dri:pageMeta/dri:metadata[@element='request'][@qualifier='URI'], 'discover'))">
<i18n:text>xmlui.dri2xhtml.structural.search</i18n:text> <h1 id="ds-search-option-head" class="ds-option-set-head">
</h1> <i18n:text>xmlui.dri2xhtml.structural.search</i18n:text>
<div id="ds-search-option" class="ds-option-set"> </h1>
<!-- The form, complete with a text box and a button, all built from attributes referenced <div id="ds-search-option" class="ds-option-set">
from under pageMeta. --> <!-- The form, complete with a text box and a button, all built from attributes referenced
<form id="ds-search-form" method="post"> from under pageMeta. -->
<xsl:attribute name="action"> <form id="ds-search-form" method="post">
<xsl:value-of select="/dri:document/dri:meta/dri:pageMeta/dri:metadata[@element='contextPath']"/> <xsl:attribute name="action">
<xsl:value-of <xsl:value-of select="/dri:document/dri:meta/dri:pageMeta/dri:metadata[@element='contextPath']"/>
select="/dri:document/dri:meta/dri:pageMeta/dri:metadata[@element='search'][@qualifier='simpleURL']"/>
</xsl:attribute>
<fieldset>
<input class="ds-text-field " type="text">
<xsl:attribute name="name">
<xsl:value-of
select="/dri:document/dri:meta/dri:pageMeta/dri:metadata[@element='search'][@qualifier='queryField']"/>
</xsl:attribute>
</input>
<input class="ds-button-field " name="submit" type="submit" i18n:attr="value"
value="xmlui.general.go">
<xsl:attribute name="onclick">
<xsl:text>
var radio = document.getElementById(&quot;ds-search-form-scope-container&quot;);
if (radio != undefined &amp;&amp; radio.checked)
{
var form = document.getElementById(&quot;ds-search-form&quot;);
form.action=
</xsl:text>
<xsl:text>&quot;</xsl:text>
<xsl:value-of
select="/dri:document/dri:meta/dri:pageMeta/dri:metadata[@element='contextPath']"/>
<xsl:text>/handle/&quot; + radio.value + &quot;</xsl:text>
<xsl:value-of select="/dri:document/dri:meta/dri:pageMeta/dri:metadata[@element='search'][@qualifier='simpleURL']"/>
<xsl:text>&quot; ; </xsl:text>
<xsl:text>
}
</xsl:text>
</xsl:attribute>
</input>
<xsl:if test="/dri:document/dri:meta/dri:pageMeta/dri:metadata[@element='focus'][@qualifier='container']">
<label>
<input id="ds-search-form-scope-all" type="radio" name="scope" value=""
checked="checked"/>
<i18n:text>xmlui.dri2xhtml.structural.search</i18n:text>
</label>
<br/>
<label>
<input id="ds-search-form-scope-container" type="radio" name="scope">
<xsl:attribute name="value">
<xsl:value-of
select="substring-after(/dri:document/dri:meta/dri:pageMeta/dri:metadata[@element='focus'][@qualifier='container'],':')"/>
</xsl:attribute>
</input>
<xsl:choose>
<xsl:when
test="/dri:document/dri:meta/dri:pageMeta/dri:metadata[@element='focus'][@qualifier='containerType']/text() = 'type:community'">
<i18n:text>xmlui.dri2xhtml.structural.search-in-community</i18n:text>
</xsl:when>
<xsl:otherwise>
<i18n:text>xmlui.dri2xhtml.structural.search-in-collection</i18n:text>
</xsl:otherwise>
</xsl:choose>
</label>
</xsl:if>
</fieldset>
</form>
<!--Only add if the advanced search url is different from the simple search-->
<xsl:if test="/dri:document/dri:meta/dri:pageMeta/dri:metadata[@element='search'][@qualifier='advancedURL'] != /dri:document/dri:meta/dri:pageMeta/dri:metadata[@element='search'][@qualifier='simpleURL']">
<!-- The "Advanced search" link, to be perched underneath the search box -->
<a>
<xsl:attribute name="href">
<xsl:value-of <xsl:value-of
select="/dri:document/dri:meta/dri:pageMeta/dri:metadata[@element='search'][@qualifier='advancedURL']"/> select="/dri:document/dri:meta/dri:pageMeta/dri:metadata[@element='search'][@qualifier='simpleURL']"/>
</xsl:attribute> </xsl:attribute>
<i18n:text>xmlui.dri2xhtml.structural.search-advanced</i18n:text> <fieldset>
</a> <input class="ds-text-field " type="text">
</xsl:if> <xsl:attribute name="name">
</div> <xsl:value-of
select="/dri:document/dri:meta/dri:pageMeta/dri:metadata[@element='search'][@qualifier='queryField']"/>
</xsl:attribute>
</input>
<input class="ds-button-field " name="submit" type="submit" i18n:attr="value"
value="xmlui.general.go">
<xsl:attribute name="onclick">
<xsl:text>
var radio = document.getElementById(&quot;ds-search-form-scope-container&quot;);
if (radio != undefined &amp;&amp; radio.checked)
{
var form = document.getElementById(&quot;ds-search-form&quot;);
form.action=
</xsl:text>
<xsl:text>&quot;</xsl:text>
<xsl:value-of
select="/dri:document/dri:meta/dri:pageMeta/dri:metadata[@element='contextPath']"/>
<xsl:text>/handle/&quot; + radio.value + &quot;</xsl:text>
<xsl:value-of select="/dri:document/dri:meta/dri:pageMeta/dri:metadata[@element='search'][@qualifier='simpleURL']"/>
<xsl:text>&quot; ; </xsl:text>
<xsl:text>
}
</xsl:text>
</xsl:attribute>
</input>
<xsl:if test="/dri:document/dri:meta/dri:pageMeta/dri:metadata[@element='focus'][@qualifier='container']">
<label>
<input id="ds-search-form-scope-all" type="radio" name="scope" value=""
checked="checked"/>
<i18n:text>xmlui.dri2xhtml.structural.search</i18n:text>
</label>
<br/>
<label>
<input id="ds-search-form-scope-container" type="radio" name="scope">
<xsl:attribute name="value">
<xsl:value-of
select="substring-after(/dri:document/dri:meta/dri:pageMeta/dri:metadata[@element='focus'][@qualifier='container'],':')"/>
</xsl:attribute>
</input>
<xsl:choose>
<xsl:when
test="/dri:document/dri:meta/dri:pageMeta/dri:metadata[@element='focus'][@qualifier='containerType']/text() = 'type:community'">
<i18n:text>xmlui.dri2xhtml.structural.search-in-community</i18n:text>
</xsl:when>
<xsl:otherwise>
<i18n:text>xmlui.dri2xhtml.structural.search-in-collection</i18n:text>
</xsl:otherwise>
</xsl:choose>
</label>
</xsl:if>
</fieldset>
</form>
<!--Only add if the advanced search url is different from the simple search-->
<xsl:if test="/dri:document/dri:meta/dri:pageMeta/dri:metadata[@element='search'][@qualifier='advancedURL'] != /dri:document/dri:meta/dri:pageMeta/dri:metadata[@element='search'][@qualifier='simpleURL']">
<!-- The "Advanced search" link, to be perched underneath the search box -->
<a>
<xsl:attribute name="href">
<xsl:value-of
select="/dri:document/dri:meta/dri:pageMeta/dri:metadata[@element='search'][@qualifier='advancedURL']"/>
</xsl:attribute>
<i18n:text>xmlui.dri2xhtml.structural.search-advanced</i18n:text>
</a>
</xsl:if>
</div>
</xsl:if>
<!-- Once the search box is built, the other parts of the options are added --> <!-- Once the search box is built, the other parts of the options are added -->
<xsl:apply-templates/> <xsl:apply-templates/>

View File

@@ -475,7 +475,7 @@
</xsl:variable> </xsl:variable>
<xsl:if test="$ccLicenseName and $ccLicenseUri and contains($ccLicenseUri, 'creativecommons')"> <xsl:if test="$ccLicenseName and $ccLicenseUri and contains($ccLicenseUri, 'creativecommons')">
<div about="{$handleUri}"> <div about="{$handleUri}" class="clearfix">
<xsl:attribute name="style"> <xsl:attribute name="style">
<xsl:text>margin:0em 2em 0em 2em; padding-bottom:0em;</xsl:text> <xsl:text>margin:0em 2em 0em 2em; padding-bottom:0em;</xsl:text>
</xsl:attribute> </xsl:attribute>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -1246,22 +1246,6 @@ span.Z3988 {
display: none; display: none;
} }
form.discover-search-box div.ds-form-content,
form.discover-sort-box div.ds-form-content
{
width: auto;
}
form.discover-search-box div.ds-form-content input.update-filters{
margin-left: 145px;
}
form.discover-sort-box select{
margin: 0 4px;
}
.hidden { .hidden {
display:none; display:none;
visibility:hidden; visibility:hidden;
@@ -1333,3 +1317,85 @@ select#aspect_submission_submit_SelectCollectionStep_field_handle
{ {
max-width: 350px; max-width: 350px;
} }
/* Start discovery layout DSpace 3.x*/
div.discoverySearchBox
{
background-color: #FFFFF5;
border: 2px solid #F0F0D2;
}
form.discover-search-box fieldset{
border: none;
}
div.discoverySearchBox label{
width: auto;
}
div.discoverySearchBox div.ds-form-content{
width: auto;
}
input#aspect_discovery_SimpleSearch_field_query{
width: 480px;
}
input.search-icon{
background-image: url('../images/search_icon_DF6E00_20x20.png');
background-repeat: no-repeat;
background-position: center center;
text-indent: -1000px;
/*Css props below are required for IE*/
font-size: 0;
line-height: 0;
border: 1px solid #000000;
}
div.controls-gear-wrapper{
float: none;
position: relative;
}
div.gear-icon{
background-image: url('../images/gear_DF6E00_25x25.png');
}
ul.gear-selection li.gear-option-selected{
background: url('../images/check_606060_15x15.png') no-repeat 3px center;
}
table.discovery-filters input.filter-control {
width: 30px;
margin-left: 5px;
text-indent: -1000px;
background-repeat: no-repeat;
background-position: center center;
height: 22px;
float: left;
/*Css props below are required for IE*/
font-size: 0;
display:block;
line-height: 0;
}
table.discovery-filters input.filter-control.filter-remove{
margin-left: 15px;
background-image: url('../images/remove_icon_DF6E00_16x16.png');
border: 1px solid #000000;
}
table.discovery-filters input.filter-control.filter-add{
background-image: url('../images/plus_icon_DF6E00_16x16.png');
border: 1px solid #000000;
}
ul.gear-selection{
left: 0;
right: auto;
background-color: ivory;
border: 2px solid #F0F0D2;
}
/* End discovery layout DSpace 3.x*/

View File

@@ -42,6 +42,7 @@
<xsl:import href="community-view.xsl"/> <xsl:import href="community-view.xsl"/>
<xsl:import href="ORE.xsl"/> <xsl:import href="ORE.xsl"/>
<xsl:import href="COinS.xsl"/> <xsl:import href="COinS.xsl"/>
<xsl:import href="discovery.xsl"/>
<xsl:output indent="yes"/> <xsl:output indent="yes"/>

View File

@@ -0,0 +1,298 @@
<!--
The contents of this file are subject to the license and copyright
detailed in the LICENSE and NOTICE files at the root of the source
tree and available online at
http://www.dspace.org/license/
-->
<xsl:stylesheet
xmlns:i18n="http://apache.org/cocoon/i18n/2.1"
xmlns:dri="http://di.tamu.edu/DRI/1.0/"
xmlns:mets="http://www.loc.gov/METS/"
xmlns:dim="http://www.dspace.org/xmlns/dspace/dim"
xmlns:xlink="http://www.w3.org/TR/xlink/"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xalan="http://xml.apache.org/xalan"
xmlns:encoder="xalan://java.net.URLEncoder"
exclude-result-prefixes="xalan encoder i18n dri mets dim xlink xsl">
<xsl:output indent="yes"/>
<!--
These templaes are devoted to rendering the search results for discovery.
Since discovery used hit highlighting seperate templates are required !
-->
<xsl:template match="dri:list[@type='dsolist']" priority="2">
<xsl:apply-templates select="dri:head"/>
<ul class="ds-artifact-list">
<xsl:apply-templates select="*[not(name()='head')]" mode="dsoList"/>
</ul>
</xsl:template>
<xsl:template match="dri:list/dri:list" mode="dsoList" priority="7">
<xsl:apply-templates select="dri:head"/>
<ul>
<xsl:apply-templates select="*[not(name()='head')]" mode="dsoList"/>
</ul>
</xsl:template>
<xsl:template match="dri:list/dri:list/dri:list" mode="dsoList" priority="8">
<li>
<xsl:attribute name="class">
<xsl:text>ds-artifact-item clearfix </xsl:text>
<xsl:choose>
<xsl:when test="position() mod 2 = 0">even</xsl:when>
<xsl:otherwise>odd</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<!--
Retrieve the type from our name, the name contains the following format:
{handle}:{metadata}
-->
<xsl:variable name="handle">
<xsl:value-of select="substring-before(@n, ':')"/>
</xsl:variable>
<xsl:variable name="type">
<xsl:value-of select="substring-after(@n, ':')"/>
</xsl:variable>
<xsl:variable name="externalMetadataURL">
<xsl:text>cocoon://metadata/handle/</xsl:text>
<xsl:value-of select="$handle"/>
<xsl:text>/mets.xml</xsl:text>
<!-- Since this is a summary only grab the descriptive metadata, and the thumbnails -->
<xsl:text>?sections=dmdSec,fileSec&amp;fileGrpTypes=THUMBNAIL</xsl:text>
<!-- An example of requesting a specific metadata standard (MODS and QDC crosswalks only work for items)->
<xsl:if test="@type='DSpace Item'">
<xsl:text>&amp;dmdTypes=DC</xsl:text>
</xsl:if>-->
</xsl:variable>
<xsl:choose>
<xsl:when test="$type='community'">
<xsl:call-template name="communitySummaryList">
<xsl:with-param name="handle">
<xsl:value-of select="$handle"/>
</xsl:with-param>
<xsl:with-param name="externalMetadataUrl">
<xsl:value-of select="$externalMetadataURL"/>
</xsl:with-param>
</xsl:call-template>
</xsl:when>
<xsl:when test="$type='collection'">
<xsl:call-template name="collectionSummaryList">
<xsl:with-param name="handle">
<xsl:value-of select="$handle"/>
</xsl:with-param>
<xsl:with-param name="externalMetadataUrl">
<xsl:value-of select="$externalMetadataURL"/>
</xsl:with-param>
</xsl:call-template>
</xsl:when>
<xsl:when test="$type='item'">
<xsl:call-template name="itemSummaryList">
<xsl:with-param name="handle">
<xsl:value-of select="$handle"/>
</xsl:with-param>
<xsl:with-param name="externalMetadataUrl">
<xsl:value-of select="$externalMetadataURL"/>
</xsl:with-param>
</xsl:call-template>
</xsl:when>
</xsl:choose>
</li>
</xsl:template>
<xsl:template name="communitySummaryList">
<xsl:param name="handle"/>
<xsl:param name="externalMetadataUrl"/>
<xsl:variable name="metsDoc" select="document($externalMetadataUrl)"/>
<div class="artifact-title">
<a href="{$metsDoc/mets:METS/@OBJID}">
<xsl:choose>
<xsl:when test="dri:list[@n=(concat($handle, ':dc.title'))]">
<xsl:apply-templates select="dri:list[@n=(concat($handle, ':dc.title'))]/dri:item"/>
</xsl:when>
<xsl:otherwise>
<i18n:text>xmlui.dri2xhtml.METS-1.0.no-title</i18n:text>
</xsl:otherwise>
</xsl:choose>
</a>
<!--Display community strengths (item counts) if they exist-->
<xsl:if test="string-length($metsDoc/mets:METS/mets:dmdSec/mets:mdWrap/mets:xmlData/dim:dim/dim:field[@element='format'][@qualifier='extent'][1]) &gt; 0">
<xsl:text> [</xsl:text>
<xsl:value-of
select="$metsDoc/mets:METS/mets:dmdSec/mets:mdWrap/mets:xmlData/dim:dim/dim:field[@element='format'][@qualifier='extent'][1]"/>
<xsl:text>]</xsl:text>
</xsl:if>
</div>
</xsl:template>
<xsl:template name="collectionSummaryList">
<xsl:param name="handle"/>
<xsl:param name="externalMetadataUrl"/>
<xsl:variable name="metsDoc" select="document($externalMetadataUrl)"/>
<div class="artifact-title">
<a href="{$metsDoc/mets:METS/@OBJID}">
<xsl:choose>
<xsl:when test="dri:list[@n=(concat($handle, ':dc.title'))]">
<xsl:apply-templates select="dri:list[@n=(concat($handle, ':dc.title'))]/dri:item"/>
</xsl:when>
<xsl:otherwise>
<i18n:text>xmlui.dri2xhtml.METS-1.0.no-title</i18n:text>
</xsl:otherwise>
</xsl:choose>
</a>
</div>
<!--Display collection strengths (item counts) if they exist-->
<xsl:if test="string-length($metsDoc/mets:METS/mets:dmdSec/mets:mdWrap/mets:xmlData/dim:dim/dim:field[@element='format'][@qualifier='extent'][1]) &gt; 0">
<xsl:text> [</xsl:text>
<xsl:value-of
select="$metsDoc/mets:METS/mets:dmdSec/mets:mdWrap/mets:xmlData/dim:dim/dim:field[@element='format'][@qualifier='extent'][1]"/>
<xsl:text>]</xsl:text>
</xsl:if>
</xsl:template>
<xsl:template name="itemSummaryList">
<xsl:param name="handle"/>
<xsl:param name="externalMetadataUrl"/>
<xsl:variable name="metsDoc" select="document($externalMetadataUrl)"/>
<!--Generates thumbnails (if present)-->
<xsl:apply-templates select="$metsDoc/mets:METS/mets:fileSec" mode="artifact-preview"/>
<div class="artifact-description">
<div class="artifact-title">
<xsl:element name="a">
<xsl:attribute name="href">
<xsl:choose>
<xsl:when test="$metsDoc/mets:METS/mets:dmdSec/mets:mdWrap/mets:xmlData/dim:dim/@withdrawn">
<xsl:value-of select="$metsDoc/mets:METS/@OBJEDIT"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat($context-path, '/handle/', $handle)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xsl:choose>
<xsl:when test="dri:list[@n=(concat($handle, ':dc.title'))]">
<xsl:apply-templates select="dri:list[@n=(concat($handle, ':dc.title'))]/dri:item"/>
</xsl:when>
<xsl:otherwise>
<i18n:text>xmlui.dri2xhtml.METS-1.0.no-title</i18n:text>
</xsl:otherwise>
</xsl:choose>
</xsl:element>
<!-- Generate COinS with empty content per spec but force Cocoon to not create a minified tag -->
<span class="Z3988">
<xsl:attribute name="title">
<xsl:for-each select="$metsDoc/mets:METS/mets:dmdSec/mets:mdWrap/mets:xmlData/dim:dim">
<xsl:call-template name="renderCOinS"/>
</xsl:for-each>
</xsl:attribute>
&#xFEFF; <!-- non-breaking space to force separating the end tag -->
</span>
</div>
<div class="artifact-info">
<span class="author">
<xsl:choose>
<xsl:when test="dri:list[@n=(concat($handle, ':dc.contributor.author'))]">
<xsl:for-each select="dri:list[@n=(concat($handle, ':dc.contributor.author'))]/dri:item">
<xsl:variable name="author">
<xsl:value-of select="."/>
</xsl:variable>
<span>
<!--Check authority in the mets document-->
<xsl:if test="$metsDoc/mets:METS/mets:dmdSec/mets:mdWrap/mets:xmlData/dim:dim/dim:field[@element='contributor' and @qualifier='author' and . = $author]/@authority">
<xsl:attribute name="class">
<xsl:text>ds-dc_contributor_author-authority</xsl:text>
</xsl:attribute>
</xsl:if>
<xsl:apply-templates select="."/>
</span>
<xsl:if test="count(following-sibling::dri:item) != 0">
<xsl:text>; </xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:when>
<xsl:when test="dri:list[@n=(concat($handle, ':dc.creator'))]">
<xsl:for-each select="dri:list[@n=(concat($handle, ':dc.creator'))]/dri:item">
<xsl:apply-templates select="."/>
<xsl:if test="count(following-sibling::dri:item) != 0">
<xsl:text>; </xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:when>
<xsl:when test="dri:list[@n=(concat($handle, ':dc.contributor'))]">
<xsl:for-each select="dri:list[@n=(concat($handle, ':dc.contributor'))]/dri:item">
<xsl:apply-templates select="."/>
<xsl:if test="count(following-sibling::dri:item) != 0">
<xsl:text>; </xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<i18n:text>xmlui.dri2xhtml.METS-1.0.no-author</i18n:text>
</xsl:otherwise>
</xsl:choose>
</span>
<xsl:text> </xsl:text>
<xsl:if test="dri:list[@n=(concat($handle, ':dc.date.issued'))] or dri:list[@n=(concat($handle, ':dc.publisher'))]">
<span class="publisher-date">
<xsl:text>(</xsl:text>
<xsl:if test="dri:list[@n=(concat($handle, ':dc.publisher'))]">
<span class="publisher">
<xsl:apply-templates select="dri:list[@n=(concat($handle, ':dc.publisher'))]/dri:item"/>
</span>
<xsl:text>, </xsl:text>
</xsl:if>
<span class="date">
<xsl:value-of
select="substring(dri:list[@n=(concat($handle, ':dc.date.issued'))]/dri:item,1,10)"/>
</span>
<xsl:text>)</xsl:text>
</span>
</xsl:if>
<xsl:choose>
<xsl:when test="dri:list[@n=(concat($handle, ':dc.description.abstract'))]/dri:item/dri:hi">
<div class="abstract">
<xsl:for-each select="dri:list[@n=(concat($handle, ':dc.description.abstract'))]/dri:item">
<xsl:apply-templates select="."/>
<xsl:text>...</xsl:text>
<br/>
</xsl:for-each>
</div>
</xsl:when>
<xsl:when test="dri:list[@n=(concat($handle, ':fulltext'))]">
<div class="abstract">
<xsl:for-each select="dri:list[@n=(concat($handle, ':fulltext'))]/dri:item">
<xsl:apply-templates select="."/>
<xsl:text>...</xsl:text>
<br/>
</xsl:for-each>
</div>
</xsl:when>
</xsl:choose>
</div>
</div>
</xsl:template>
</xsl:stylesheet>

View File

@@ -169,6 +169,11 @@
<i18n:text>xmlui.dri2xhtml.structural.pagination-next</i18n:text> <i18n:text>xmlui.dri2xhtml.structural.pagination-next</i18n:text>
</a> </a>
</xsl:if> </xsl:if>
<xsl:if test="parent::node()/dri:div[@n = 'masked-page-control']">
<xsl:apply-templates select="parent::node()/dri:div[@n='masked-page-control']/dri:div">
<xsl:with-param name="position" select="$position"/>
</xsl:apply-templates>
</xsl:if>
</div> </div>
</xsl:when> </xsl:when>
</xsl:choose> </xsl:choose>
@@ -245,4 +250,19 @@
<!-- The general "catch-all" template for attributes matched, but not handled above --> <!-- The general "catch-all" template for attributes matched, but not handled above -->
<xsl:template match="@*"></xsl:template> <xsl:template match="@*"></xsl:template>
<xsl:template match="dri:div[@n = 'masked-page-control']">
<!--Do not render this division, this is handled by the xsl-->
</xsl:template>
<xsl:template match="dri:div[@n ='search-controls-gear']">
<xsl:param name="position"/>
<div>
<xsl:call-template name="standardAttributes">
<xsl:with-param name="class"><xsl:value-of select="$position"/></xsl:with-param>
</xsl:call-template>
<xsl:apply-templates/>
</div>
</xsl:template>
</xsl:stylesheet> </xsl:stylesheet>

View File

@@ -482,10 +482,13 @@
<xsl:template match="dri:list[not(@type)]/dri:item" priority="2" mode="nested"> <xsl:template match="dri:list[not(@type)]/dri:item" priority="2" mode="nested">
<li> <li>
<xsl:apply-templates /> <xsl:call-template name="standardAttributes">
<xsl:with-param name="class">ds-simple-list-item</xsl:with-param>
</xsl:call-template>
<!-- Wrap orphaned sub-lists into the preceding item --> <!-- Wrap orphaned sub-lists into the preceding item -->
<xsl:variable name="node-set1" select="./following-sibling::dri:list"/> <xsl:variable name="node-set1" select="./following-sibling::dri:list"/>
<xsl:variable name="node-set2" select="./following-sibling::dri:item[1]/following-sibling::dri:list"/> <xsl:variable name="node-set2" select="./following-sibling::dri:item[1]/following-sibling::dri:list"/>
<xsl:apply-templates />
<xsl:apply-templates select="$node-set1[count(.|$node-set2) != count($node-set2)]"/> <xsl:apply-templates select="$node-set1[count(.|$node-set2) != count($node-set2)]"/>
</li> </li>
</xsl:template> </xsl:template>
@@ -512,6 +515,9 @@
<!-- Generic item handling for cases where nothing special needs to be done --> <!-- Generic item handling for cases where nothing special needs to be done -->
<xsl:template match="dri:item" mode="nested"> <xsl:template match="dri:item" mode="nested">
<li> <li>
<xsl:call-template name="standardAttributes">
<xsl:with-param name="class">ds-simple-list-item</xsl:with-param>
</xsl:call-template>
<xsl:apply-templates /> <xsl:apply-templates />
</li> </li>
</xsl:template> </xsl:template>

View File

@@ -224,20 +224,22 @@
<xsl:when test="dri:field"> <xsl:when test="dri:field">
<xsl:choose> <xsl:choose>
<xsl:when test="preceding-sibling::*[1][local-name()='label']"> <xsl:when test="preceding-sibling::*[1][local-name()='label']">
<label class="ds-form-label"> <xsl:if test="string-length(string(preceding-sibling::*[1][local-name()='label'])) > 0">
<label class="ds-form-label">
<xsl:choose> <xsl:choose>
<xsl:when test="./dri:field/@id"> <xsl:when test="./dri:field/@id">
<xsl:attribute name="for"> <xsl:attribute name="for">
<xsl:value-of select="translate(./dri:field/@id,'.','_')"/> <xsl:value-of select="translate(./dri:field/@id,'.','_')"/>
</xsl:attribute> </xsl:attribute>
</xsl:when> </xsl:when>
<xsl:otherwise></xsl:otherwise> <xsl:otherwise></xsl:otherwise>
</xsl:choose> </xsl:choose>
<xsl:apply-templates select="preceding-sibling::*[1][local-name()='label']"/>&#160; <xsl:apply-templates select="preceding-sibling::*[1][local-name()='label']"/>
</label> </label>
</xsl:if>
</xsl:when> </xsl:when>
<xsl:otherwise> <xsl:otherwise>
<xsl:apply-templates select="preceding-sibling::*[1][local-name()='label']"/>&#160; <xsl:apply-templates select="preceding-sibling::*[1][local-name()='label']"/>
</xsl:otherwise> </xsl:otherwise>
</xsl:choose> </xsl:choose>
</xsl:when> </xsl:when>

View File

@@ -994,7 +994,7 @@
<xsl:apply-templates select="*[not(name()='head')]" mode="nested"/> <xsl:apply-templates select="*[not(name()='head')]" mode="nested"/>
</ul> </ul>
</xsl:template> </xsl:template>
<!-- The item template creates an HTML list item element and places the contents of the DRI item inside it. <!-- The item template creates an HTML list item element and places the contents of the DRI item inside it.
Additionally, it checks to see if the currently viewed item has a label element directly preceeding it, Additionally, it checks to see if the currently viewed item has a label element directly preceeding it,
and if it does, applies the label's template before performing its own actions. This mechanism applies and if it does, applies the label's template before performing its own actions. This mechanism applies
@@ -1007,7 +1007,7 @@
<xsl:apply-templates /> <xsl:apply-templates />
</li> </li>
</xsl:template> </xsl:template>
<!-- The case of nested lists is handled in a similar way across all lists. You match the sub-list based on <!-- The case of nested lists is handled in a similar way across all lists. You match the sub-list based on
its parent, create a list item approtiate to the list type, fill its content from the sub-list's head its parent, create a list item approtiate to the list type, fill its content from the sub-list's head
element and apply the other templates normally. --> element and apply the other templates normally. -->
@@ -1016,8 +1016,8 @@
<xsl:apply-templates select="."/> <xsl:apply-templates select="."/>
</li> </li>
</xsl:template> </xsl:template>
<!-- Second type is the ordered list, which is a list with either labels or names to designate an ordering <!-- Second type is the ordered list, which is a list with either labels or names to designate an ordering
of some kind. --> of some kind. -->
<xsl:template match="dri:list[@type='ordered']" priority="2"> <xsl:template match="dri:list[@type='ordered']" priority="2">
@@ -1031,7 +1031,7 @@
</xsl:apply-templates> </xsl:apply-templates>
</ol> </ol>
</xsl:template> </xsl:template>
<xsl:template match="dri:list[@type='ordered']/dri:item" priority="2" mode="nested"> <xsl:template match="dri:list[@type='ordered']/dri:item" priority="2" mode="nested">
<li> <li>
<xsl:if test="name(preceding-sibling::*[position()=1]) = 'label'"> <xsl:if test="name(preceding-sibling::*[position()=1]) = 'label'">
@@ -1040,14 +1040,14 @@
<xsl:apply-templates /> <xsl:apply-templates />
</li> </li>
</xsl:template> </xsl:template>
<xsl:template match="dri:list[@type='ordered']/dri:list" priority="3" mode="nested"> <xsl:template match="dri:list[@type='ordered']/dri:list" priority="3" mode="nested">
<li> <li>
<xsl:apply-templates select="."/> <xsl:apply-templates select="."/>
</li> </li>
</xsl:template> </xsl:template>
<!-- Progress list used primarily in forms that span several pages. There isn't a template for the nested <!-- Progress list used primarily in forms that span several pages. There isn't a template for the nested
version of this list, mostly because there isn't a use case for it. --> version of this list, mostly because there isn't a use case for it. -->
<xsl:template match="dri:list[@type='progress']" priority="2"> <xsl:template match="dri:list[@type='progress']" priority="2">
@@ -1059,7 +1059,7 @@
<xsl:apply-templates select="dri:item"/> <xsl:apply-templates select="dri:item"/>
</ul> </ul>
</xsl:template> </xsl:template>
<xsl:template match="dri:list[@type='progress']/dri:item" priority="2"> <xsl:template match="dri:list[@type='progress']/dri:item" priority="2">
<li> <li>
<xsl:attribute name="class"> <xsl:attribute name="class">
@@ -1082,8 +1082,8 @@
</li> </li>
</xsl:if> </xsl:if>
</xsl:template> </xsl:template>
<!-- The third type of list is the glossary (gloss) list. It is essentially a list of pairs, consisting of <!-- The third type of list is the glossary (gloss) list. It is essentially a list of pairs, consisting of
a set of labels, each followed by an item. Unlike the ordered and bulleted lists, gloss is implemented a set of labels, each followed by an item. Unlike the ordered and bulleted lists, gloss is implemented
via HTML definition list (dd) element. It can also be changed to work as a two-column table. --> via HTML definition list (dd) element. It can also be changed to work as a two-column table. -->
@@ -1096,13 +1096,13 @@
<xsl:apply-templates select="*[not(name()='head')]" mode="nested"/> <xsl:apply-templates select="*[not(name()='head')]" mode="nested"/>
</dl> </dl>
</xsl:template> </xsl:template>
<xsl:template match="dri:list[@type='gloss']/dri:item" priority="2" mode="nested"> <xsl:template match="dri:list[@type='gloss']/dri:item" priority="2" mode="nested">
<dd> <dd>
<xsl:apply-templates /> <xsl:apply-templates />
</dd> </dd>
</xsl:template> </xsl:template>
<xsl:template match="dri:list[@type='gloss']/dri:label" priority="2" mode="nested"> <xsl:template match="dri:list[@type='gloss']/dri:label" priority="2" mode="nested">
<dt> <dt>
<span> <span>
@@ -1115,14 +1115,14 @@
</span> </span>
</dt> </dt>
</xsl:template> </xsl:template>
<xsl:template match="dri:list[@type='gloss']/dri:list" priority="3" mode="nested"> <xsl:template match="dri:list[@type='gloss']/dri:list" priority="3" mode="nested">
<dd> <dd>
<xsl:apply-templates select="."/> <xsl:apply-templates select="."/>
</dd> </dd>
</xsl:template> </xsl:template>
<!-- The next list type is one without a type attribute. In this case XSL makes a decision: if the items <!-- The next list type is one without a type attribute. In this case XSL makes a decision: if the items
of the list have labels the the list will be made into a table-like structure, otherwise it is considered of the list have labels the the list will be made into a table-like structure, otherwise it is considered
to be a plain unordered list and handled generically. --> to be a plain unordered list and handled generically. -->
@@ -1147,7 +1147,7 @@
</ul> </ul>
</xsl:if> </xsl:if>
</xsl:template> </xsl:template>
<xsl:template match="dri:list[not(@type)]/dri:item" priority="2" mode="labeled"> <xsl:template match="dri:list[not(@type)]/dri:item" priority="2" mode="labeled">
<tr> <tr>
<xsl:attribute name="class"> <xsl:attribute name="class">
@@ -1164,7 +1164,7 @@
</td> </td>
</tr> </tr>
</xsl:template> </xsl:template>
<xsl:template match="dri:list[not(@type)]/dri:label" priority="2" mode="labeled"> <xsl:template match="dri:list[not(@type)]/dri:label" priority="2" mode="labeled">
<td> <td>
<xsl:if test="count(./node())>0"> <xsl:if test="count(./node())>0">
@@ -1179,9 +1179,12 @@
</xsl:if> </xsl:if>
</td> </td>
</xsl:template> </xsl:template>
<xsl:template match="dri:list[not(@type)]/dri:item" priority="2" mode="nested"> <xsl:template match="dri:list[not(@type)]/dri:item" priority="2" mode="nested">
<li> <li>
<xsl:call-template name="standardAttributes">
<xsl:with-param name="class">ds-simple-list-item</xsl:with-param>
</xsl:call-template>
<xsl:apply-templates /> <xsl:apply-templates />
<!-- Wrap orphaned sub-lists into the preceding item --> <!-- Wrap orphaned sub-lists into the preceding item -->
<xsl:variable name="node-set1" select="./following-sibling::dri:list"/> <xsl:variable name="node-set1" select="./following-sibling::dri:list"/>
@@ -1189,18 +1192,18 @@
<xsl:apply-templates select="$node-set1[count(.|$node-set2) != count($node-set2)]"/> <xsl:apply-templates select="$node-set1[count(.|$node-set2) != count($node-set2)]"/>
</li> </li>
</xsl:template> </xsl:template>
<!-- Special treatment of a list type "form", which is used to encode simple forms and give them structure. <!-- Special treatment of a list type "form", which is used to encode simple forms and give them structure.
This is done partly to ensure that the resulting HTML form follows accessibility guidelines. --> This is done partly to ensure that the resulting HTML form follows accessibility guidelines. -->
<xsl:template match="dri:list[@type='form']" priority="3"> <xsl:template match="dri:list[@type='form']" priority="3">
<xsl:choose> <xsl:choose>
<xsl:when test="ancestor::dri:list[@type='form']"> <xsl:when test="ancestor::dri:list[@type='form']">
<li> <li>
<fieldset> <fieldset>
<xsl:call-template name="standardAttributes"> <xsl:call-template name="standardAttributes">
@@ -1217,7 +1220,7 @@
</xsl:with-param> </xsl:with-param>
</xsl:call-template> </xsl:call-template>
<xsl:apply-templates select="dri:head"/> <xsl:apply-templates select="dri:head"/>
<ol> <ol>
<xsl:apply-templates select="*[not(name()='label' or name()='head')]" /> <xsl:apply-templates select="*[not(name()='label' or name()='head')]" />
</ol> </ol>
@@ -1240,7 +1243,7 @@
</xsl:with-param> </xsl:with-param>
</xsl:call-template> </xsl:call-template>
<xsl:apply-templates select="dri:head"/> <xsl:apply-templates select="dri:head"/>
<ol> <ol>
<xsl:apply-templates select="*[not(name()='label' or name()='head')]" /> <xsl:apply-templates select="*[not(name()='label' or name()='head')]" />
</ol> </ol>
@@ -1248,7 +1251,7 @@
</xsl:otherwise> </xsl:otherwise>
</xsl:choose> </xsl:choose>
</xsl:template> </xsl:template>
<!-- TODO: Account for the dri:hi/dri:field kind of nesting here and everywhere else... --> <!-- TODO: Account for the dri:hi/dri:field kind of nesting here and everywhere else... -->
<xsl:template match="dri:list[@type='form']/dri:item" priority="3"> <xsl:template match="dri:list[@type='form']/dri:item" priority="3">
<li> <li>
@@ -1276,7 +1279,7 @@
<xsl:if test="dri:list[@type='form']">sublist </xsl:if> <xsl:if test="dri:list[@type='form']">sublist </xsl:if>
</xsl:with-param> </xsl:with-param>
</xsl:call-template> </xsl:call-template>
<xsl:choose> <xsl:choose>
<xsl:when test="dri:field[@type='composite']"> <xsl:when test="dri:field[@type='composite']">
<xsl:call-template name="pick-label"/> <xsl:call-template name="pick-label"/>
@@ -1300,7 +1303,7 @@
</xsl:choose> </xsl:choose>
</li> </li>
</xsl:template> </xsl:template>
<!-- An item in a nested "form" list --> <!-- An item in a nested "form" list -->
<xsl:template match="dri:list[@type='form']//dri:list[@type='form']/dri:item" priority="3"> <xsl:template match="dri:list[@type='form']//dri:list[@type='form']/dri:item" priority="3">
<li> <li>
@@ -1315,13 +1318,13 @@
<!--<xsl:if test="count(../dri:item) > 3">--> <!--<xsl:if test="count(../dri:item) > 3">-->
<xsl:if test="(count(preceding-sibling::dri:item | ../../preceding-sibling::dri:item/dri:list[@type='form']/dri:item) mod 2 = 0)">even </xsl:if> <xsl:if test="(count(preceding-sibling::dri:item | ../../preceding-sibling::dri:item/dri:list[@type='form']/dri:item) mod 2 = 0)">even </xsl:if>
<xsl:if test="(count(preceding-sibling::dri:item | ../../preceding-sibling::dri:item/dri:list[@type='form']/dri:item) mod 2 = 1)">odd </xsl:if> <xsl:if test="(count(preceding-sibling::dri:item | ../../preceding-sibling::dri:item/dri:list[@type='form']/dri:item) mod 2 = 1)">odd </xsl:if>
</xsl:when> </xsl:when>
<xsl:when test="(count(../../..//dri:item) - count(../../..//dri:list[@type='form'])) mod 2 = 1"> <xsl:when test="(count(../../..//dri:item) - count(../../..//dri:list[@type='form'])) mod 2 = 1">
<!--<xsl:if test="count(../dri:item) > 3">--> <!--<xsl:if test="count(../dri:item) > 3">-->
<xsl:if test="(count(preceding-sibling::dri:item | ../../preceding-sibling::dri:item/dri:list[@type='form']/dri:item) mod 2 = 1)">even </xsl:if> <xsl:if test="(count(preceding-sibling::dri:item | ../../preceding-sibling::dri:item/dri:list[@type='form']/dri:item) mod 2 = 1)">even </xsl:if>
<xsl:if test="(count(preceding-sibling::dri:item | ../../preceding-sibling::dri:item/dri:list[@type='form']/dri:item) mod 2 = 0)">odd </xsl:if> <xsl:if test="(count(preceding-sibling::dri:item | ../../preceding-sibling::dri:item/dri:list[@type='form']/dri:item) mod 2 = 0)">odd </xsl:if>
</xsl:when> </xsl:when>
</xsl:choose> </xsl:choose>
<!-- <!--
@@ -1329,7 +1332,7 @@
--> -->
</xsl:with-param> </xsl:with-param>
</xsl:call-template> </xsl:call-template>
<xsl:call-template name="pick-label"/> <xsl:call-template name="pick-label"/>
<xsl:choose> <xsl:choose>
@@ -1350,7 +1353,7 @@
</xsl:choose> </xsl:choose>
</li> </li>
</xsl:template> </xsl:template>
<xsl:template name="pick-label"> <xsl:template name="pick-label">
<xsl:choose> <xsl:choose>
<xsl:when test="dri:field/dri:label"> <xsl:when test="dri:field/dri:label">
@@ -1382,7 +1385,7 @@
</span> </span>
</xsl:otherwise> </xsl:otherwise>
</xsl:choose> </xsl:choose>
</xsl:when> </xsl:when>
<xsl:when test="dri:field"> <xsl:when test="dri:field">
<xsl:choose> <xsl:choose>
@@ -1411,7 +1414,7 @@
</xsl:otherwise> </xsl:otherwise>
</xsl:choose> </xsl:choose>
</xsl:template> </xsl:template>
<xsl:template match="dri:list[@type='form']/dri:label" priority="3"> <xsl:template match="dri:list[@type='form']/dri:label" priority="3">
<xsl:attribute name="class"> <xsl:attribute name="class">
<xsl:text>ds-form-label</xsl:text> <xsl:text>ds-form-label</xsl:text>
@@ -1431,12 +1434,12 @@
</xsl:choose> </xsl:choose>
<xsl:apply-templates /> <xsl:apply-templates />
</xsl:template> </xsl:template>
<xsl:template match="dri:field/dri:label" mode="formComposite"> <xsl:template match="dri:field/dri:label" mode="formComposite">
<xsl:apply-templates /> <xsl:apply-templates />
</xsl:template> </xsl:template>
<xsl:template match="dri:list[@type='form']/dri:head" priority="5"> <xsl:template match="dri:list[@type='form']/dri:head" priority="5">
<legend> <legend>
<xsl:apply-templates /> <xsl:apply-templates />
@@ -1561,27 +1564,30 @@
<xsl:apply-templates select="*[not(name()='head')]" mode="nested"/> <xsl:apply-templates select="*[not(name()='head')]" mode="nested"/>
</ul> </ul>
</xsl:template> </xsl:template>
<!-- Generic label handling: simply place the text of the element followed by a period and space. --> <!-- Generic label handling: simply place the text of the element followed by a period and space. -->
<xsl:template match="dri:label" priority="1" mode="nested"> <xsl:template match="dri:label" priority="1" mode="nested">
<xsl:copy-of select="./node()"/> <xsl:copy-of select="./node()"/>
</xsl:template> </xsl:template>
<!-- Generic item handling for cases where nothing special needs to be done --> <!-- Generic item handling for cases where nothing special needs to be done -->
<xsl:template match="dri:item" mode="nested"> <xsl:template match="dri:item" mode="nested">
<li> <li>
<xsl:call-template name="standardAttributes">
<xsl:with-param name="class">ds-simple-list-item</xsl:with-param>
</xsl:call-template>
<xsl:apply-templates /> <xsl:apply-templates />
</li> </li>
</xsl:template> </xsl:template>
<xsl:template match="dri:list/dri:list" priority="1" mode="nested"> <xsl:template match="dri:list/dri:list" priority="1" mode="nested">
<li> <li>
<xsl:apply-templates select="."/> <xsl:apply-templates select="."/>
</li> </li>
</xsl:template> </xsl:template>
<!-- From here on out come the templates for supporting elements that are contained within structural <!-- From here on out come the templates for supporting elements that are contained within structural
ones. These include head (in all its myriad forms), rich text container elements (like hi and figure), ones. These include head (in all its myriad forms), rich text container elements (like hi and figure),
@@ -2692,11 +2698,33 @@
<i18n:text>xmlui.dri2xhtml.structural.pagination-next</i18n:text> <i18n:text>xmlui.dri2xhtml.structural.pagination-next</i18n:text>
</a> </a>
</xsl:if> </xsl:if>
<xsl:if test="parent::node()/dri:div[@n = 'masked-page-control']">
<xsl:apply-templates select="parent::node()/dri:div[@n='masked-page-control']/dri:div">
<xsl:with-param name="position" select="$position"/>
</xsl:apply-templates>
</xsl:if>
</div> </div>
</xsl:when> </xsl:when>
</xsl:choose> </xsl:choose>
</xsl:template> </xsl:template>
<xsl:template match="dri:div[@n = 'masked-page-control']" priority="5">
<!--Do not render this division, this is handled by the xsl-->
</xsl:template>
<xsl:template match="dri:div[@n ='search-controls-gear']">
<xsl:param name="position"/>
<div>
<xsl:call-template name="standardAttributes">
<xsl:with-param name="class"><xsl:value-of select="$position"/></xsl:with-param>
</xsl:call-template>
<xsl:apply-templates/>
</div>
</xsl:template>
<!-- A quick helper function used by the @pagination template for repetitive tasks --> <!-- A quick helper function used by the @pagination template for repetitive tasks -->
<xsl:template name="offset-link"> <xsl:template name="offset-link">
<xsl:param name="pageOffset"/> <xsl:param name="pageOffset"/>
@@ -2820,7 +2848,7 @@
</xsl:otherwise> </xsl:otherwise>
</xsl:choose> </xsl:choose>
</xsl:template> </xsl:template>
<!-- First, the detail list case --> <!-- First, the detail list case -->
<xsl:template match="dri:referenceSet[@type = 'detailList']" priority="2"> <xsl:template match="dri:referenceSet[@type = 'detailList']" priority="2">
<xsl:apply-templates select="dri:head"/> <xsl:apply-templates select="dri:head"/>
@@ -2828,15 +2856,15 @@
<xsl:apply-templates select="*[not(name()='head')]" mode="detailList"/> <xsl:apply-templates select="*[not(name()='head')]" mode="detailList"/>
</ul> </ul>
</xsl:template> </xsl:template>
<!-- Next up is the summary view case that at this point applies only to items, since communities and <!-- Next up is the summary view case that at this point applies only to items, since communities and
collections do not have two separate views. --> collections do not have two separate views. -->
<xsl:template match="dri:referenceSet[@type = 'summaryView']" priority="2"> <xsl:template match="dri:referenceSet[@type = 'summaryView']" priority="2">
<xsl:apply-templates select="dri:head"/> <xsl:apply-templates select="dri:head"/>
<xsl:apply-templates select="*[not(name()='head')]" mode="summaryView"/> <xsl:apply-templates select="*[not(name()='head')]" mode="summaryView"/>
</xsl:template> </xsl:template>
<!-- Finally, we have the detailed view case that is applicable to items, communities and collections. <!-- Finally, we have the detailed view case that is applicable to items, communities and collections.
In DRI it constitutes a standard view of collections/communities and a complete metadata listing In DRI it constitutes a standard view of collections/communities and a complete metadata listing
view of items. --> view of items. -->
@@ -3489,4 +3517,272 @@
</td> </td>
</xsl:template> </xsl:template>
<xsl:template match="dri:list[@type='dsolist']" priority="2">
<xsl:apply-templates select="dri:head"/>
<ul class="ds-artifact-list">
<xsl:apply-templates select="*[not(name()='head')]" mode="dsoList"/>
</ul>
</xsl:template>
<xsl:template match="dri:list/dri:list" mode="dsoList" priority="7">
<xsl:apply-templates select="dri:head"/>
<ul>
<xsl:apply-templates select="*[not(name()='head')]" mode="dsoList"/>
</ul>
</xsl:template>
<xsl:template match="dri:list/dri:list/dri:list" mode="dsoList" priority="8">
<li>
<xsl:attribute name="class">
<xsl:text>ds-artifact-item clearfix </xsl:text>
<xsl:choose>
<xsl:when test="position() mod 2 = 0">even</xsl:when>
<xsl:otherwise>odd</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<!--
Retrieve the type from our name, the name contains the following format:
{handle}:{metadata}
-->
<xsl:variable name="handle">
<xsl:value-of select="substring-before(@n, ':')"/>
</xsl:variable>
<xsl:variable name="type">
<xsl:value-of select="substring-after(@n, ':')"/>
</xsl:variable>
<xsl:variable name="externalMetadataURL">
<xsl:text>cocoon://metadata/handle/</xsl:text>
<xsl:value-of select="$handle"/>
<xsl:text>/mets.xml</xsl:text>
<!-- Since this is a summary only grab the descriptive metadata, and the thumbnails -->
<xsl:text>?sections=dmdSec,fileSec&amp;fileGrpTypes=THUMBNAIL</xsl:text>
<!-- An example of requesting a specific metadata standard (MODS and QDC crosswalks only work for items)->
<xsl:if test="@type='DSpace Item'">
<xsl:text>&amp;dmdTypes=DC</xsl:text>
</xsl:if>-->
</xsl:variable>
<xsl:choose>
<xsl:when test="$type='community'">
<xsl:call-template name="communitySummaryList">
<xsl:with-param name="handle">
<xsl:value-of select="$handle"/>
</xsl:with-param>
<xsl:with-param name="externalMetadataUrl">
<xsl:value-of select="$externalMetadataURL"/>
</xsl:with-param>
</xsl:call-template>
</xsl:when>
<xsl:when test="$type='collection'">
<xsl:call-template name="collectionSummaryList">
<xsl:with-param name="handle">
<xsl:value-of select="$handle"/>
</xsl:with-param>
<xsl:with-param name="externalMetadataUrl">
<xsl:value-of select="$externalMetadataURL"/>
</xsl:with-param>
</xsl:call-template>
</xsl:when>
<xsl:when test="$type='item'">
<xsl:call-template name="itemSummaryList">
<xsl:with-param name="handle">
<xsl:value-of select="$handle"/>
</xsl:with-param>
<xsl:with-param name="externalMetadataUrl">
<xsl:value-of select="$externalMetadataURL"/>
</xsl:with-param>
</xsl:call-template>
</xsl:when>
</xsl:choose>
</li>
</xsl:template>
<xsl:template name="communitySummaryList">
<xsl:param name="handle"/>
<xsl:param name="externalMetadataUrl"/>
<xsl:variable name="metsDoc" select="document($externalMetadataUrl)"/>
<div class="artifact-title">
<a href="{$metsDoc/mets:METS/@OBJID}">
<xsl:choose>
<xsl:when test="dri:list[@n=(concat($handle, ':dc.title'))]">
<xsl:apply-templates select="dri:list[@n=(concat($handle, ':dc.title'))]/dri:item"/>
</xsl:when>
<xsl:otherwise>
<i18n:text>xmlui.dri2xhtml.METS-1.0.no-title</i18n:text>
</xsl:otherwise>
</xsl:choose>
</a>
<!--Display community strengths (item counts) if they exist-->
<xsl:if test="string-length($metsDoc/mets:METS/mets:dmdSec/mets:mdWrap/mets:xmlData/dim:dim/dim:field[@element='format'][@qualifier='extent'][1]) &gt; 0">
<xsl:text> [</xsl:text>
<xsl:value-of
select="$metsDoc/mets:METS/mets:dmdSec/mets:mdWrap/mets:xmlData/dim:dim/dim:field[@element='format'][@qualifier='extent'][1]"/>
<xsl:text>]</xsl:text>
</xsl:if>
</div>
</xsl:template>
<xsl:template name="collectionSummaryList">
<xsl:param name="handle"/>
<xsl:param name="externalMetadataUrl"/>
<xsl:variable name="metsDoc" select="document($externalMetadataUrl)"/>
<div class="artifact-title">
<a href="{$metsDoc/mets:METS/@OBJID}">
<xsl:choose>
<xsl:when test="dri:list[@n=(concat($handle, ':dc.title'))]">
<xsl:apply-templates select="dri:list[@n=(concat($handle, ':dc.title'))]/dri:item"/>
</xsl:when>
<xsl:otherwise>
<i18n:text>xmlui.dri2xhtml.METS-1.0.no-title</i18n:text>
</xsl:otherwise>
</xsl:choose>
</a>
</div>
<!--Display collection strengths (item counts) if they exist-->
<xsl:if test="string-length($metsDoc/mets:METS/mets:dmdSec/mets:mdWrap/mets:xmlData/dim:dim/dim:field[@element='format'][@qualifier='extent'][1]) &gt; 0">
<xsl:text> [</xsl:text>
<xsl:value-of
select="$metsDoc/mets:METS/mets:dmdSec/mets:mdWrap/mets:xmlData/dim:dim/dim:field[@element='format'][@qualifier='extent'][1]"/>
<xsl:text>]</xsl:text>
</xsl:if>
</xsl:template>
<xsl:template name="itemSummaryList">
<xsl:param name="handle"/>
<xsl:param name="externalMetadataUrl"/>
<xsl:variable name="metsDoc" select="document($externalMetadataUrl)"/>
<div class="artifact-description">
<div class="artifact-title">
<xsl:element name="a">
<xsl:attribute name="href">
<xsl:choose>
<xsl:when test="$metsDoc/mets:METS/mets:dmdSec/mets:mdWrap/mets:xmlData/dim:dim/@withdrawn">
<xsl:value-of select="$metsDoc/mets:METS/@OBJEDIT"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat($context-path, '/handle/', $handle)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xsl:choose>
<xsl:when test="dri:list[@n=(concat($handle, ':dc.title'))]">
<xsl:apply-templates select="dri:list[@n=(concat($handle, ':dc.title'))]/dri:item"/>
</xsl:when>
<xsl:otherwise>
<i18n:text>xmlui.dri2xhtml.METS-1.0.no-title</i18n:text>
</xsl:otherwise>
</xsl:choose>
</xsl:element>
<!-- Generate COinS with empty content per spec but force Cocoon to not create a minified tag -->
<span class="Z3988">
<xsl:attribute name="title">
<xsl:for-each select="$metsDoc/mets:METS/mets:dmdSec/mets:mdWrap/mets:xmlData/dim:dim">
<xsl:call-template name="renderCOinS"/>
</xsl:for-each>
</xsl:attribute>
&#xFEFF; <!-- non-breaking space to force separating the end tag -->
</span>
</div>
<div class="artifact-info">
<span class="author">
<xsl:choose>
<xsl:when test="dri:list[@n=(concat($handle, ':dc.contributor.author'))]">
<xsl:for-each select="dri:list[@n=(concat($handle, ':dc.contributor.author'))]/dri:item">
<xsl:variable name="author">
<xsl:value-of select="."/>
</xsl:variable>
<span>
<!--Check authority in the mets document-->
<xsl:if test="$metsDoc/mets:METS/mets:dmdSec/mets:mdWrap/mets:xmlData/dim:dim/dim:field[@element='contributor' and @qualifier='author' and . = $author]/@authority">
<xsl:attribute name="class">
<xsl:text>ds-dc_contributor_author-authority</xsl:text>
</xsl:attribute>
</xsl:if>
<xsl:apply-templates select="."/>
</span>
<xsl:if test="count(following-sibling::dri:item) != 0">
<xsl:text>; </xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:when>
<xsl:when test="dri:list[@n=(concat($handle, ':dc.creator'))]">
<xsl:for-each select="dri:list[@n=(concat($handle, ':dc.creator'))]/dri:item">
<xsl:apply-templates select="."/>
<xsl:if test="count(following-sibling::dri:item) != 0">
<xsl:text>; </xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:when>
<xsl:when test="dri:list[@n=(concat($handle, ':dc.contributor'))]">
<xsl:for-each select="dri:list[@n=(concat($handle, ':dc.contributor'))]/dri:item">
<xsl:apply-templates select="."/>
<xsl:if test="count(following-sibling::dri:item) != 0">
<xsl:text>; </xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<i18n:text>xmlui.dri2xhtml.METS-1.0.no-author</i18n:text>
</xsl:otherwise>
</xsl:choose>
</span>
<xsl:text> </xsl:text>
<xsl:if test="dri:list[@n=(concat($handle, ':dc.date.issued'))] or dri:list[@n=(concat($handle, ':dc.publisher'))]">
<span class="publisher-date">
<xsl:text>(</xsl:text>
<xsl:if test="dri:list[@n=(concat($handle, ':dc.publisher'))]">
<span class="publisher">
<xsl:apply-templates select="dri:list[@n=(concat($handle, ':dc.publisher'))]/dri:item"/>
</span>
<xsl:text>, </xsl:text>
</xsl:if>
<span class="date">
<xsl:value-of
select="substring(dri:list[@n=(concat($handle, ':dc.date.issued'))]/dri:item,1,10)"/>
</span>
<xsl:text>)</xsl:text>
</span>
</xsl:if>
<xsl:choose>
<xsl:when test="dri:list[@n=(concat($handle, ':dc.description.abstract'))]/dri:item/dri:hi">
<div class="abstract">
<xsl:for-each select="dri:list[@n=(concat($handle, ':dc.description.abstract'))]/dri:item">
<xsl:apply-templates select="."/>
<xsl:text>...</xsl:text>
<br/>
</xsl:for-each>
</div>
</xsl:when>
<xsl:when test="dri:list[@n=(concat($handle, ':fulltext'))]">
<div class="abstract">
<xsl:for-each select="dri:list[@n=(concat($handle, ':fulltext'))]/dri:item">
<xsl:apply-templates select="."/>
<xsl:text>...</xsl:text>
<br/>
</xsl:for-each>
</div>
</xsl:when>
</xsl:choose>
</div>
</div>
<!--Generates thumbnails (if present)-->
<xsl:apply-templates select="$metsDoc/mets:METS/mets:fileSec" mode="artifact-preview"/>
</xsl:template>
</xsl:stylesheet> </xsl:stylesheet>

View File

@@ -84,9 +84,11 @@ public class List extends AbstractWingElement implements WingMergeableElement,
public static final String TYPE_FORM = "form"; public static final String TYPE_FORM = "form";
public static final String TYPE_DSO_LIST = "dsolist";
/** All the possible list types collected into one array */ /** All the possible list types collected into one array */
public static final String[] TYPES = { TYPE_SIMPLE, TYPE_ORDERED, public static final String[] TYPES = { TYPE_SIMPLE, TYPE_ORDERED,
TYPE_BULLETED, TYPE_GLOSS, TYPE_PROGRESS, TYPE_FORM }; TYPE_BULLETED, TYPE_GLOSS, TYPE_PROGRESS, TYPE_FORM, TYPE_DSO_LIST };
/** The list's name */ /** The list's name */
private String name; private String name;

View File

@@ -8,7 +8,7 @@
search.server = http://localhost:8080/solr/search search.server = http://localhost:8080/solr/search
#Char used to ensure that the sidebar facets are case insensitive #Char used to ensure that the sidebar facets are case insensitive
#solr.facets.split.char=||| #solr.facets.split.char=\n|||\n
#All metadata fields that will not end up in the index, this is a comma separated list #All metadata fields that will not end up in the index, this is a comma separated list
index.ignore=dc.description.provenance index.ignore=dc.description.provenance

View File

@@ -42,9 +42,9 @@
<!--Which sidebar facets are to be displayed--> <!--Which sidebar facets are to be displayed-->
<property name="sidebarFacets"> <property name="sidebarFacets">
<list> <list>
<ref bean="sidebarFacetAuthor" /> <ref bean="searchFilterAuthor" />
<ref bean="sidebarFacetSubject" /> <ref bean="searchFilterSubject" />
<ref bean="sidebarFacetDateIssued" /> <ref bean="searchFilterIssued" />
</list> </list>
</property> </property>
<!--The search filters which can be used on the discovery search page--> <!--The search filters which can be used on the discovery search page-->
@@ -85,6 +85,52 @@
<property name="max" value="5"/> <property name="max" value="5"/>
</bean> </bean>
</property> </property>
<property name="hitHighlightingConfiguration">
<bean class="org.dspace.discovery.configuration.DiscoveryHitHighlightingConfiguration">
<property name="metadataFields">
<list>
<bean class="org.dspace.discovery.configuration.DiscoveryHitHighlightFieldConfiguration">
<property name="field" value="dc.title"/>
<property name="snippets" value="5"/>
</bean>
<bean class="org.dspace.discovery.configuration.DiscoveryHitHighlightFieldConfiguration">
<property name="field" value="dc.contributor.author"/>
<property name="snippets" value="5"/>
</bean>
<bean class="org.dspace.discovery.configuration.DiscoveryHitHighlightFieldConfiguration">
<property name="field" value="dc.description.abstract"/>
<property name="maxSize" value="250"/>
<property name="snippets" value="2"/>
</bean>
<bean class="org.dspace.discovery.configuration.DiscoveryHitHighlightFieldConfiguration">
<property name="field" value="fulltext"/>
<property name="maxSize" value="250"/>
<property name="snippets" value="2"/>
</bean>
</list>
</property>
</bean>
</property>
<property name="moreLikeThisConfiguration">
<bean class="org.dspace.discovery.configuration.DiscoveryMoreLikeThisConfiguration">
<!--When altering this list also alter the "xmlui.Discovery.RelatedItems.help" key as it describes
the metadata fields below-->
<property name="similarityMetadataFields">
<list>
<value>dc.title</value>
<value>dc.contributor.author</value>
<value>dc.creator</value>
<value>dc.subject</value>
</list>
</property>
<!--The minimum number of matching terms across the metadata fields above before an item is found as related -->
<property name="minTermFrequency" value="5"/>
<!--The maximum number of related items displayed-->
<property name="max" value="3"/>
<!--The minimum word length below which words will be ignored-->
<property name="minWordLength" value="5"/>
</bean>
</property>
</bean> </bean>
@@ -97,45 +143,9 @@
<value>dc.title</value> <value>dc.title</value>
</list> </list>
</property> </property>
<property name="fullAutoComplete" value="false"/>
</bean> </bean>
<bean id="searchFilterAuthor" class="org.dspace.discovery.configuration.DiscoverySearchFilter"> <bean id="searchFilterAuthor" class="org.dspace.discovery.configuration.DiscoverySearchFilterFacet">
<property name="indexFieldName" value="author"/>
<property name="metadataFields">
<list>
<value>dc.contributor.author</value>
<value>dc.creator</value>
</list>
</property>
<property name="fullAutoComplete" value="true"/>
</bean>
<bean id="searchFilterSubject" class="org.dspace.discovery.configuration.DiscoverySearchFilter">
<property name="indexFieldName" value="subject"/>
<property name="metadataFields">
<list>
<value>dc.subject.*</value>
</list>
</property>
<property name="fullAutoComplete" value="true"/>
</bean>
<bean id="searchFilterIssued" class="org.dspace.discovery.configuration.DiscoverySearchFilter">
<property name="indexFieldName" value="dateIssued"/>
<property name="metadataFields">
<list>
<value>dc.date.issued</value>
</list>
</property>
<property name="type" value="date"/>
<property name="fullAutoComplete" value="false"/>
</bean>
<!--Sidebar facet configuration beans-->
<bean id="sidebarFacetAuthor" class="org.dspace.discovery.configuration.SidebarFacetConfiguration">
<property name="indexFieldName" value="author"/> <property name="indexFieldName" value="author"/>
<property name="metadataFields"> <property name="metadataFields">
<list> <list>
@@ -147,7 +157,7 @@
<property name="sortOrder" value="COUNT"/> <property name="sortOrder" value="COUNT"/>
</bean> </bean>
<bean id="sidebarFacetSubject" class="org.dspace.discovery.configuration.SidebarFacetConfiguration"> <bean id="searchFilterSubject" class="org.dspace.discovery.configuration.DiscoverySearchFilterFacet">
<property name="indexFieldName" value="subject"/> <property name="indexFieldName" value="subject"/>
<property name="metadataFields"> <property name="metadataFields">
<list> <list>
@@ -158,7 +168,7 @@
<property name="sortOrder" value="COUNT"/> <property name="sortOrder" value="COUNT"/>
</bean> </bean>
<bean id="sidebarFacetDateIssued" class="org.dspace.discovery.configuration.SidebarFacetConfiguration"> <bean id="searchFilterIssued" class="org.dspace.discovery.configuration.DiscoverySearchFilterFacet">
<property name="indexFieldName" value="dateIssued"/> <property name="indexFieldName" value="dateIssued"/>
<property name="metadataFields"> <property name="metadataFields">
<list> <list>
@@ -169,7 +179,6 @@
<property name="sortOrder" value="VALUE"/> <property name="sortOrder" value="VALUE"/>
</bean> </bean>
<!--Sort properties--> <!--Sort properties-->
<bean id="sortTitle" class="org.dspace.discovery.configuration.DiscoverySortFieldConfiguration"> <bean id="sortTitle" class="org.dspace.discovery.configuration.DiscoverySortFieldConfiguration">
<property name="metadataField" value="dc.title"/> <property name="metadataField" value="dc.title"/>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
The contents of this file are subject to the license and copyright
detailed in the LICENSE and NOTICE files at the root of the source
tree and available online at
http://www.dspace.org/license/
-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:annotation-config /> <!-- allows us to use spring annotations in beans -->
<bean class="org.dspace.discovery.SolrServiceResourceRestrictionPlugin" id="solrServiceResourceIndexPlugin" scope="prototype"/>
<alias name="solrServiceResourceIndexPlugin" alias="org.dspace.discovery.SolrServiceResourceRestrictionPlugin"/>
</beans>

File diff suppressed because it is too large Load Diff