[DS-236] Authority control for metadata fields and Choice Authority plugin framework

git-svn-id: http://scm.dspace.org/svn/repo/dspace/trunk@4365 9c30dcfa-912a-0410-8fc2-9e0234be79fd
This commit is contained in:
Larry Stone
2009-10-05 23:52:42 +00:00
parent fa86734005
commit bbe8a2a3d1
142 changed files with 16729 additions and 3390 deletions

View File

@@ -192,6 +192,10 @@
<groupId>org.dspace</groupId>
<artifactId>dspace-services-impl</artifactId>
</dependency>
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -5,7 +5,8 @@
*
* Date: $Date$
*
* Copyright (c) 2002-2009, The DSpace Foundation. All rights reserved.
* Copyright (c) 2002-2005, Hewlett-Packard Company and Massachusetts
* Institute of Technology. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -18,7 +19,8 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the DSpace Foundation nor the names of its
* - Neither the name of the Hewlett-Packard Company nor the name of the
* Massachusetts Institute of Technology nor the names of their
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
@@ -39,11 +41,10 @@
package org.dspace.app.util;
import java.io.File;
import java.util.List;
import java.util.Vector;
import java.util.HashMap;
import java.util.Iterator;
import java.lang.Exception;
import javax.servlet.ServletException;
import org.xml.sax.SAXException;
import org.w3c.dom.*;
import javax.xml.parsers.*;
@@ -134,21 +135,21 @@ public class DCInputsReader
*/
public DCInputsReader()
throws ServletException
throws DCInputsReaderException
{
buildInputs(defsFile);
}
public DCInputsReader(String fileName)
throws ServletException
throws DCInputsReaderException
{
buildInputs(fileName);
}
private void buildInputs(String fileName)
throws ServletException
throws DCInputsReaderException
{
whichForms = new HashMap();
formDefns = new HashMap();
@@ -170,14 +171,24 @@ public class DCInputsReader
}
catch (FactoryConfigurationError fe)
{
throw new ServletException("Cannot create Submission form parser",fe);
throw new DCInputsReaderException("Cannot create Submission form parser",fe);
}
catch (Exception e)
{
throw new ServletException("Error creating submission forms: "+e);
throw new DCInputsReaderException("Error creating submission forms: "+e);
}
}
public Iterator getPairsNameIterator()
{
return valuePairs.keySet().iterator();
}
public List getPairs(String name)
{
return (Vector)valuePairs.get(name);
}
/**
* Returns the set of DC inputs used for a particular collection, or the
* default set if no inputs defined for the collection
@@ -185,11 +196,11 @@ public class DCInputsReader
* @param collectionHandle
* collection's unique Handle
* @return DC input set
* @throws ServletException
* @throws DCInputsReaderException
* if no default set defined
*/
public DCInputSet getInputs(String collectionHandle)
throws ServletException
throws DCInputsReaderException
{
String formName = (String)whichForms.get(collectionHandle);
if (formName == null)
@@ -198,7 +209,7 @@ public class DCInputsReader
}
if (formName == null)
{
throw new ServletException("No form designated as default");
throw new DCInputsReaderException("No form designated as default");
}
// check mini-cache, and return if match
if ( lastInputSet != null && lastInputSet.getFormName().equals( formName ) )
@@ -209,7 +220,7 @@ public class DCInputsReader
Vector pages = (Vector)formDefns.get(formName);
if ( pages == null )
{
throw new ServletException("Missing the " + formName + " form");
throw new DCInputsReaderException("Missing the " + formName + " form");
}
lastInputSet = new DCInputSet(formName, pages, valuePairs);
return lastInputSet;
@@ -219,10 +230,10 @@ public class DCInputsReader
* Return the number of pages the inputs span for a desginated collection
* @param collectionHandle collection's unique Handle
* @return number of pages of input
* @throws ServletException if no default set defined
* @throws DCInputsReaderException if no default set defined
*/
public int getNumberInputPages(String collectionHandle)
throws ServletException
throws DCInputsReaderException
{
return getInputs(collectionHandle).getNumberPages();
}
@@ -233,7 +244,7 @@ public class DCInputsReader
* the display/storage word pairs.
*/
private void doNodes(Node n)
throws SAXException, ServletException
throws SAXException, DCInputsReaderException
{
if (n == null)
{
@@ -270,11 +281,11 @@ public class DCInputsReader
}
if (!foundMap)
{
throw new ServletException("No collection to form map found");
throw new DCInputsReaderException("No collection to form map found");
}
if (!foundDefs)
{
throw new ServletException("No form definition found");
throw new DCInputsReaderException("No form definition found");
}
}
@@ -323,7 +334,7 @@ public class DCInputsReader
* required text, and repeatable flag.
*/
private void processDefinition(Node e)
throws SAXException, ServletException
throws SAXException, DCInputsReaderException
{
int numForms = 0;
NodeList nl = e.getChildNodes();
@@ -380,13 +391,13 @@ public class DCInputsReader
// sanity check number of pages
if (pages.size() < 1)
{
throw new ServletException("Form " + formName + " has no pages");
throw new DCInputsReaderException("Form " + formName + " has no pages");
}
}
}
if (numForms == 0)
{
throw new ServletException("No form definition found");
throw new DCInputsReaderException("No form definition found");
}
}
@@ -434,11 +445,6 @@ public class DCInputsReader
String closedVocabularyString = getAttribute(nd, "closed");
field.put("closedVocabulary", closedVocabularyString);
}
else if (tagName.equals("visibility"))
{
String readOnlyString = getAttribute(nd, "otherwise");
field.put("readonly", readOnlyString);
}
}
}
String missing = null;
@@ -613,11 +619,11 @@ public class DCInputsReader
* Check that all referenced value-pairs are present
* and field is consistent
*
* Throws ServletException if detects a missing value-pair.
* Throws DCInputsReaderException if detects a missing value-pair.
*/
private void checkValues()
throws ServletException
throws DCInputsReaderException
{
// Step through every field of every page of every form
Iterator ki = formDefns.keySet().iterator();
@@ -642,7 +648,7 @@ public class DCInputsReader
if (v == null)
{
String errString = "Cannot find value pairs for " + pairsName;
throw new ServletException(errString);
throw new DCInputsReaderException(errString);
}
}
// if visibility restricted, make sure field is not required
@@ -654,7 +660,7 @@ public class DCInputsReader
{
String errString = "Field '" + (String)fld.get("label") +
"' is required but invisible";
throw new ServletException(errString);
throw new DCInputsReaderException(errString);
}
}
}

View File

@@ -0,0 +1,87 @@
/*
* DCInputsReaderException.java
*
* Version: $Revision: 3761 $
*
* Date: $Date: 2009-05-07 00:18:02 -0400 (Thu, 07 May 2009) $
*
* Copyright (c) 2002-2009, The DSpace Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the DSpace Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
package org.dspace.app.util;
/**
* This is a superclass for exceptions representing a failure when
* importing or exporting a package. E.g., unacceptable package format
* or contents. Implementations should throw one of the more specific
* exceptions. This class is intended for declarations and catch clauses.
*
* @author Larry Stone
* @version $Revision: 3761 $
*/
public class DCInputsReaderException extends Exception
{
/**
* No-args constructor.
*/
public DCInputsReaderException()
{
super();
}
/**
* Constructor for a given message.
* @param message diagnostic message.
*/
public DCInputsReaderException(String message)
{
super(message);
}
/**
* Constructor for a given cause.
* @param cause throwable that caused this exception
*/
public DCInputsReaderException(Throwable cause)
{
super(cause);
}
/**
* Constructor to create a new exception wrapping it around another exception.
* @param message diagnostic message.
* @param cause throwable that caused this exception
*/
public DCInputsReaderException(String message, Throwable cause)
{
super(message, cause);
}
}

View File

@@ -152,7 +152,7 @@ public interface BrowseCreateDAO
* @return the database id of the distinct record
* @throws BrowseException
*/
public int getDistinctID(String table, String value, String sortValue) throws BrowseException;
public int getDistinctID(String table, String value, String authority, String sortValue) throws BrowseException;
/**
* Insert the given value and sort value into the distinct index table. This
@@ -174,7 +174,7 @@ public interface BrowseCreateDAO
* @return the database id of the created record
* @throws BrowseException
*/
public int insertDistinctRecord(String table, String value, String sortValue) throws BrowseException;
public int insertDistinctRecord(String table, String value, String authority, String sortValue) throws BrowseException;
/**
* Update a mapping between an item id and a distinct metadata field such as an author,

View File

@@ -322,6 +322,8 @@ public class BrowseCreateDAOOracle implements BrowseCreateDAO
{
String create = "CREATE TABLE " + table + " (" +
"id INTEGER PRIMARY KEY, " +
"distinct_id INTEGER UNIQUE, " +
"authority VARCHAR2(100), " +
"value " + getValueColumnDefinition() + ", " +
"sort_value " + getSortColumnDefinition() +
")";
@@ -507,19 +509,19 @@ public class BrowseCreateDAOOracle implements BrowseCreateDAO
/* (non-Javadoc)
* @see org.dspace.browse.BrowseCreateDAO#getDistinctID(java.lang.String, java.lang.String, java.lang.String)
*/
public int getDistinctID(String table, String value, String sortValue) throws BrowseException
public int getDistinctID(String table, String value, String authority, String sortValue) throws BrowseException
{
TableRowIterator tri = null;
if (log.isDebugEnabled())
{
log.debug("getDistinctID: table=" + table + ",value=" + value + ",sortValue=" + sortValue);
log.debug("getDistinctID: table=" + table + ",value=" + value + ",authority=" + authority + ",sortValue=" + sortValue);
}
try
{
Object[] params = { value };
String select = "SELECT id FROM " + table;
Object[] params;
String select = "SELECT distinct_id FROM " + table;
if (ConfigurationManager.getBooleanProperty("webui.browse.metadata.case-insensitive", false))
{
@@ -536,15 +538,26 @@ public class BrowseCreateDAOOracle implements BrowseCreateDAO
select = select + " WHERE value=?";
}
if (authority != null)
{
select += " AND authority = ?";
params = new Object[]{ value, authority };
}
else
{
select += " AND authority IS NULL";
params = new Object[]{ value };
}
tri = DatabaseManager.query(context, select, params);
int distinctID = -1;
if (!tri.hasNext())
{
distinctID = insertDistinctRecord(table, value, sortValue);
distinctID = insertDistinctRecord(table, value, authority, sortValue);
}
else
{
distinctID = tri.next().getIntColumn("id");
distinctID = tri.next().getIntColumn("distinct_id");
}
if (log.isDebugEnabled())
@@ -640,7 +653,7 @@ public class BrowseCreateDAOOracle implements BrowseCreateDAO
/* (non-Javadoc)
* @see org.dspace.browse.BrowseCreateDAO#insertDistinctRecord(java.lang.String, java.lang.String, java.lang.String)
*/
public int insertDistinctRecord(String table, String value, String sortValue) throws BrowseException
public int insertDistinctRecord(String table, String value, String authority, String sortValue) throws BrowseException
{
if (log.isDebugEnabled())
{
@@ -652,8 +665,14 @@ public class BrowseCreateDAOOracle implements BrowseCreateDAO
TableRow dr = DatabaseManager.create(context, table);
dr.setColumn("value", utils.truncateValue(value));
dr.setColumn("sort_value", utils.truncateSortValue(sortValue));
DatabaseManager.update(context, dr);
if (authority != null)
{
dr.setColumn("authority", utils.truncateValue(authority,100));
}
int distinctID = dr.getIntColumn("id");
dr.setColumn("distinct_id", distinctID);
DatabaseManager.update(context, dr);
if (log.isDebugEnabled())
{

View File

@@ -223,7 +223,7 @@ public class BrowseCreateDAOPostgres implements BrowseCreateDAO
String create = "CREATE TABLE " + map + " (" +
"map_id integer primary key, " +
"item_id integer references item(item_id), " +
"distinct_id integer references " + table + "(id)" +
"distinct_id integer references " + table + "(distinct_id)" +
");";
if (execute)
@@ -320,6 +320,8 @@ public class BrowseCreateDAOPostgres implements BrowseCreateDAO
{
String create = "CREATE TABLE " + table + " (" +
"id integer primary key, " +
"distinct_id integer UNIQUE, " +
"authority VARCHAR(100), " +
"value " + getValueColumnDefinition() + ", " +
"sort_value " + getSortColumnDefinition() +
");";
@@ -510,7 +512,7 @@ public class BrowseCreateDAOPostgres implements BrowseCreateDAO
/* (non-Javadoc)
* @see org.dspace.browse.BrowseCreateDAO#getDistinctID(java.lang.String, java.lang.String, java.lang.String)
*/
public int getDistinctID(String table, String value, String sortValue)
public int getDistinctID(String table, String value, String authority, String sortValue)
throws BrowseException
{
TableRowIterator tri = null;
@@ -522,27 +524,50 @@ public class BrowseCreateDAOPostgres implements BrowseCreateDAO
try
{
Object[] params = { value };
String select = null;
Object[] params;
String select;
if (authority != null)
{
params = new Object[]{ value, authority };
}
else
{
params = new Object[]{ value };
}
if (ConfigurationManager.getBooleanProperty("webui.browse.metadata.case-insensitive", false))
{
select = "SELECT id FROM " + table + " WHERE UPPER(value) = UPPER(?)";
if (authority != null)
{
select = "SELECT distinct_id FROM " + table + " WHERE UPPER(value) = UPPER(?) and authority = ?";
}
else
{
select = "SELECT distinct_id FROM " + table + " WHERE UPPER(value) = UPPER(?) and authority IS NULL";
}
}
else
{
select = "SELECT id FROM " + table + " WHERE value = ?";
if (authority != null)
{
select = "SELECT distinct_id FROM " + table + " WHERE value = ? and authority = ?";
}
else
{
select = "SELECT distinct_id FROM " + table + " WHERE value = ? and authority IS NULL";
}
}
tri = DatabaseManager.query(context, select, params);
int distinctID = -1;
if (!tri.hasNext())
{
distinctID = insertDistinctRecord(table, value, sortValue);
distinctID = insertDistinctRecord(table, value, authority, sortValue);
}
else
{
distinctID = tri.next().getIntColumn("id");
distinctID = tri.next().getIntColumn("distinct_id");
}
if (log.isDebugEnabled())
@@ -640,17 +665,22 @@ public class BrowseCreateDAOPostgres implements BrowseCreateDAO
/* (non-Javadoc)
* @see org.dspace.browse.BrowseCreateDAO#insertDistinctRecord(java.lang.String, java.lang.String, java.lang.String)
*/
public int insertDistinctRecord(String table, String value, String sortValue)
public int insertDistinctRecord(String table, String value, String authority, String sortValue)
throws BrowseException
{
log.debug("insertDistinctRecord: table=" + table + ",value=" + value+ ",sortValue=" + sortValue);
log.debug("insertDistinctRecord: table=" + table + ",value=" + value+ ",authority=" + authority+",sortValue=" + sortValue);
try
{
TableRow dr = DatabaseManager.create(context, table);
if (authority != null)
{
dr.setColumn("authority", utils.truncateValue(authority,100));
}
dr.setColumn("value", utils.truncateValue(value));
dr.setColumn("sort_value", utils.truncateSortValue(sortValue));
DatabaseManager.update(context, dr);
int distinctID = dr.getIntColumn("id");
dr.setColumn("distinct_id", distinctID);
DatabaseManager.update(context, dr);
log.debug("insertDistinctRecord: return=" + distinctID);
return distinctID;

View File

@@ -412,4 +412,8 @@ public interface BrowseDAO
* @return the name of the table
*/
public String getContainerTable();
public void setAuthorityValue(String value);
public String getAuthorityValue();
}

View File

@@ -97,6 +97,8 @@ public class BrowseDAOOracle implements BrowseDAO
/** value to restrict browse to (e.g. author name) */
private String value = null;
private String authority = null;
/** exact or partial matching of the value */
private boolean valuePartial = false;
@@ -427,8 +429,9 @@ public class BrowseDAOOracle implements BrowseDAO
while (tri.hasNext())
{
TableRow row = tri.next();
String stringResult = row.getStringColumn("value");
results.add(stringResult);
String valueResult = row.getStringColumn("value");
String authorityResult = row.getStringColumn("authority");
results.add(new String[]{valueResult,authorityResult});
}
return results;
@@ -906,10 +909,13 @@ public class BrowseDAOOracle implements BrowseDAO
{
if (tableMap != null && tableDis != null)
{
queryBuf.append(tableMap).append(".distinct_id=").append(tableDis).append(".id");
queryBuf.append(tableMap).append(".distinct_id=").append(tableDis).append(".distinct_id");
queryBuf.append(" AND ");
queryBuf.append(tableDis).append(".sort_value");
if (authority == null)
{
queryBuf.append(tableDis).append(".authority IS NULL");
queryBuf.append(" AND ");
queryBuf.append(tableDis).append(".").append(valueField);
if (valuePartial)
{
queryBuf.append(" LIKE ? ");
@@ -937,6 +943,12 @@ public class BrowseDAOOracle implements BrowseDAO
}
}
}
else
{
queryBuf.append(tableDis).append(".authority=?");
params.add(utils.truncateValue(authority,100));
}
}
if (containerTable != null && containerIDField != null && containerID != -1)
{
@@ -1075,7 +1087,7 @@ public class BrowseDAOOracle implements BrowseDAO
queryBuf.append(table);
if (containerTable != null || (value != null && valueField != null && tableDis != null && tableMap != null))
{
queryBuf.append(", (SELECT ");
queryBuf.append(", (SELECT " + (containerTable != null ? "" : "DISTINCT "));
queryBuf.append(containerTable != null ? containerTable : tableMap).append(".item_id");
queryBuf.append(" FROM ");
buildFocusedSelectTables(queryBuf);
@@ -1379,4 +1391,12 @@ public class BrowseDAOOracle implements BrowseDAO
return queryParams.toArray();
}
public void setAuthorityValue(String value) {
authority = value;
}
public String getAuthorityValue() {
return authority;
}
}

View File

@@ -97,6 +97,8 @@ public class BrowseDAOPostgres implements BrowseDAO
/** value to restrict browse to (e.g. author name) */
private String value = null;
private String authority = null;
/** exact or partial matching of the value */
private boolean valuePartial = false;
@@ -431,8 +433,9 @@ public class BrowseDAOPostgres implements BrowseDAO
while (tri.hasNext())
{
TableRow row = tri.next();
String stringResult = row.getStringColumn("value");
results.add(stringResult);
String valueResult = row.getStringColumn("value");
String authorityResult = row.getStringColumn("authority");
results.add(new String[]{valueResult,authorityResult});
}
return results;
@@ -909,9 +912,13 @@ public class BrowseDAOPostgres implements BrowseDAO
{
if (tableMap != null && tableDis != null)
{
queryBuf.append(tableMap).append(".distinct_id=").append(tableDis).append(".id");
queryBuf.append(tableMap).append(".distinct_id=").append(tableDis).append(".distinct_id");
queryBuf.append(" AND ");
queryBuf.append(tableDis).append(".sort_value");
if (authority == null)
{
queryBuf.append(tableDis).append(".authority IS NULL");
queryBuf.append(" AND ");
queryBuf.append(tableDis).append(".").append(valueField);
if (valuePartial)
{
@@ -940,6 +947,12 @@ public class BrowseDAOPostgres implements BrowseDAO
}
}
}
else
{
queryBuf.append(tableDis).append(".authority=?");
params.add(utils.truncateValue(authority,100));
}
}
if (containerTable != null && containerIDField != null && containerID != -1)
{
@@ -1084,7 +1097,7 @@ public class BrowseDAOPostgres implements BrowseDAO
queryBuf.append(table);
if (containerTable != null || (value != null && valueField != null && tableDis != null && tableMap != null))
{
queryBuf.append(", (SELECT ");
queryBuf.append(", (SELECT " + (containerTable != null ? "" : "DISTINCT "));
queryBuf.append(containerTable != null ? containerTable : tableMap).append(".item_id");
queryBuf.append(" FROM ");
buildFocusedSelectTables(queryBuf);
@@ -1383,4 +1396,12 @@ public class BrowseDAOPostgres implements BrowseDAO
return queryParams.toArray();
}
public void setAuthorityValue(String value) {
authority = value;
}
public String getAuthorityValue() {
return authority;
}
}

View File

@@ -252,9 +252,19 @@ public class BrowseEngine
value = OrderFormat.makeSortString(value, scope.getFilterValueLang(),
scope.getBrowseIndex().getDataType());
dao.setAuthorityValue(scope.getAuthorityValue());
// set the values in the Browse Query
if (scope.isSecondLevel())
{
dao.setFilterValueField("value");
dao.setFilterValue(rawValue);
}
else
{
dao.setFilterValueField("sort_value");
dao.setFilterValue(value);
}
dao.setFilterValuePartial(scope.getFilterValuePartial());
// to apply the filtering, we need the distinct and map tables for the index
@@ -381,6 +391,9 @@ public class BrowseEngine
// set the browse value if there is one
browseInfo.setValue(rawValue);
// set the browse authority key if there is one
browseInfo.setAuthority(scope.getAuthorityValue());
// set the focus value if there is one
browseInfo.setFocus(rawFocusValue);

View File

@@ -602,7 +602,17 @@ public class BrowseIndex
*/
public boolean isMetadataIndex()
{
return "metadata".equals(displayType);
return displayType != null && displayType.startsWith("metadata");
}
/**
* Is the browse index authority value?
*
* @return true if authority, false if not
*/
public boolean isAuthorityIndex()
{
return "metadataAuthority".equals(displayType);
}
/**

View File

@@ -101,6 +101,9 @@ public class BrowseInfo
/** the value browsed upon */
private String value;
/** the authority key browsed upon */
private String authority;
/** is this a "starts_with" browse? */
private boolean startsWith = false;
@@ -232,6 +235,20 @@ public class BrowseInfo
return false;
}
/**
* Is there an authority key associated with this browse
*
* @return true if an authority key, false if not
*/
public boolean hasAuthority()
{
if (this.authority != null)
{
return true;
}
return false;
}
/**
* Are there results for this browse, or was the result set empty?
*
@@ -434,6 +451,22 @@ public class BrowseInfo
this.value = value;
}
/**
* @return Returns the authority key.
*/
public String getAuthority()
{
return authority;
}
/**
* @param value The authority key to set.
*/
public void setAuthority(String authority)
{
this.authority = authority;
}
/**
* is this a top level (0) browse? Examples of this are a full item
* browse or a single browse. Other browse types are considered
@@ -466,8 +499,9 @@ public class BrowseInfo
}
/**
* The results of the Browse. Each member of the list is either a String
* (for the authors browse) or an {@link org.dspace.content.Item}(for the
* The results of the Browse. Each member of the list is either a String array
* (for the authors browse: first element the value, second element the authority key)
* or an {@link org.dspace.content.Item}(for the
* other browses).
*
* @return Result list. This list cannot be modified.
@@ -478,13 +512,14 @@ public class BrowseInfo
}
/**
* Return the results of the Browse as a String array.
* Return the results of the Browse as an array of String array.
* The first element (i.e. index 0) is the value, the second is the authority key
*
* @return The results of the Browse as a String array.
*/
public String[] getStringResults()
public String[][] getStringResults()
{
return (String[]) results.toArray(new String[results.size()]);
return (String[][]) results.toArray(new String[results.size()][2]);
}
/**

View File

@@ -50,7 +50,8 @@ public class BrowseItemDAOOracle implements BrowseItemDAO
private String findAll = "SELECT item_id, in_archive, withdrawn FROM item WHERE in_archive = 1 OR withdrawn = 1";
/** query to get the text value of a metadata element only (qualifier is NULL) */
private String getByMetadataElement = "SELECT text_value,text_lang,element,qualifier FROM metadatavalue, metadatafieldregistry, metadataschemaregistry " +
private String getByMetadataElement = "SELECT authority, confidence, text_value,text_lang,element,qualifier FROM metadatavalue, metadatafieldregistry, metadataschemaregistry " +
"WHERE metadatavalue.item_id = ? " +
" AND metadatavalue.metadata_field_id = metadatafieldregistry.metadata_field_id " +
" AND metadatafieldregistry.element = ? " +
@@ -60,7 +61,7 @@ public class BrowseItemDAOOracle implements BrowseItemDAO
" ORDER BY metadatavalue.metadata_field_id, metadatavalue.place";
/** query to get the text value of a metadata element and qualifier */
private String getByMetadata = "SELECT text_value,text_lang,element,qualifier FROM metadatavalue, metadatafieldregistry, metadataschemaregistry " +
private String getByMetadata = "SELECT authority, confidence, text_value,text_lang,element,qualifier FROM metadatavalue, metadatafieldregistry, metadataschemaregistry " +
"WHERE metadatavalue.item_id = ? " +
" AND metadatavalue.metadata_field_id = metadatafieldregistry.metadata_field_id " +
" AND metadatafieldregistry.element = ? " +
@@ -70,7 +71,7 @@ public class BrowseItemDAOOracle implements BrowseItemDAO
" ORDER BY metadatavalue.metadata_field_id, metadatavalue.place";
/** query to get the text value of a metadata element with the wildcard qualifier (*) */
private String getByMetadataAnyQualifier = "SELECT text_value,text_lang,element,qualifier FROM metadatavalue, metadatafieldregistry, metadataschemaregistry " +
private String getByMetadataAnyQualifier = "SELECT authority, confidence, text_value,text_lang,element,qualifier FROM metadatavalue, metadatafieldregistry, metadataschemaregistry " +
"WHERE metadatavalue.item_id = ? " +
" AND metadatavalue.metadata_field_id = metadatafieldregistry.metadata_field_id " +
" AND metadatafieldregistry.element = ? " +
@@ -151,6 +152,8 @@ public class BrowseItemDAOOracle implements BrowseItemDAO
dcv.qualifier = tr.getStringColumn("qualifier");
dcv.language = tr.getStringColumn("text_lang");
dcv.value = tr.getStringColumn("text_value");
dcv.authority = tr.getStringColumn("authority");
dcv.confidence = tr.getIntColumn("confidence");
values.add(dcv);
}
}

View File

@@ -50,7 +50,7 @@ public class BrowseItemDAOPostgres implements BrowseItemDAO
private String findAll = "SELECT item_id, in_archive, withdrawn FROM item WHERE in_archive = true OR withdrawn = true";
/** query to get the text value of a metadata element only (qualifier is NULL) */
private String getByMetadataElement = "SELECT text_value,text_lang,element,qualifier FROM metadatavalue, metadatafieldregistry, metadataschemaregistry " +
private String getByMetadataElement = "SELECT authority, confidence, text_value,text_lang,element,qualifier FROM metadatavalue, metadatafieldregistry, metadataschemaregistry " +
"WHERE metadatavalue.item_id = ? " +
" AND metadatavalue.metadata_field_id = metadatafieldregistry.metadata_field_id " +
" AND metadatafieldregistry.element = ? " +
@@ -60,7 +60,7 @@ public class BrowseItemDAOPostgres implements BrowseItemDAO
" ORDER BY metadatavalue.metadata_field_id, metadatavalue.place";
/** query to get the text value of a metadata element and qualifier */
private String getByMetadata = "SELECT text_value,text_lang,element,qualifier FROM metadatavalue, metadatafieldregistry, metadataschemaregistry " +
private String getByMetadata = "SELECT authority, confidence, text_value,text_lang,element,qualifier FROM metadatavalue, metadatafieldregistry, metadataschemaregistry " +
"WHERE metadatavalue.item_id = ? " +
" AND metadatavalue.metadata_field_id = metadatafieldregistry.metadata_field_id " +
" AND metadatafieldregistry.element = ? " +
@@ -70,7 +70,7 @@ public class BrowseItemDAOPostgres implements BrowseItemDAO
" ORDER BY metadatavalue.metadata_field_id, metadatavalue.place";
/** query to get the text value of a metadata element with the wildcard qualifier (*) */
private String getByMetadataAnyQualifier = "SELECT text_value,text_lang,element,qualifier FROM metadatavalue, metadatafieldregistry, metadataschemaregistry " +
private String getByMetadataAnyQualifier = "SELECT authority, confidence, text_value,text_lang,element,qualifier FROM metadatavalue, metadatafieldregistry, metadataschemaregistry " +
"WHERE metadatavalue.item_id = ? " +
" AND metadatavalue.metadata_field_id = metadatafieldregistry.metadata_field_id " +
" AND metadatafieldregistry.element = ? " +
@@ -151,6 +151,8 @@ public class BrowseItemDAOPostgres implements BrowseItemDAO
dcv.qualifier = tr.getStringColumn("qualifier");
dcv.language = tr.getStringColumn("text_lang");
dcv.value = tr.getStringColumn("text_value");
dcv.authority = tr.getStringColumn("authority");
dcv.confidence = tr.getIntColumn("confidence");
values.add(dcv);
}
}

View File

@@ -108,6 +108,8 @@ public class BrowserScope
/** the number of items to offset into the result ie. 0 = 1st record */
private int offset = 0;
private String authority = null;
/**
* Construct a new BrowserScope using the given Context
*
@@ -643,4 +645,12 @@ public class BrowserScope
}
return false;
}
public String getAuthorityValue() {
return authority;
}
public void setAuthorityValue(String value) {
authority = value;
}
}

View File

@@ -54,6 +54,8 @@ import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.dspace.content.DCValue;
import org.dspace.content.Item;
import org.dspace.content.authority.ChoiceAuthorityManager;
import org.dspace.content.authority.MetadataAuthorityManager;
import org.dspace.core.Context;
import org.dspace.sort.SortOption;
import org.dspace.sort.SortException;
@@ -436,10 +438,50 @@ public class IndexBrowse
(values[x].qualifier == null ? "" : "." + values[x].qualifier));
}
else
{
if (bis[i].isAuthorityIndex() &&
(values[x].authority == null || values[x].confidence < MetadataAuthorityManager
.getManager().getMinConfidence(values[x].schema, values[x].element, values[x].qualifier)))
{
// if we have an authority index only authored metadata will go here!
break;
}
// is there any valid (with appropriate confidence) authority key?
if (values[x].authority != null
&& values[x].confidence >= MetadataAuthorityManager
.getManager().getMinConfidence(values[x].schema, values[x].element, values[x].qualifier))
{
boolean isValueVariants = false;
List<String> variants = ChoiceAuthorityManager.getManager()
.getVariants(values[x].schema, values[x].element, values[x].qualifier,
values[x].authority, values[x].language);
if (variants != null)
{
for (String var : variants)
{
String nVal = OrderFormat.makeSortString(var, values[x].language, bis[i].getDataType());
distIDSet.add(dao.getDistinctID(bis[i].getDistinctTableName(), var, values[x].authority, nVal));
if (var.equals(values[x].value))
{
isValueVariants = true;
}
}
}
if (!isValueVariants)
{
// get the normalised version of the value
String nVal = OrderFormat.makeSortString(values[x].value, values[x].language, bis[i].getDataType());
distIDSet.add(dao.getDistinctID(bis[i].getDistinctTableName(), values[x].value, nVal));
distIDSet.add(dao.getDistinctID(bis[i].getDistinctTableName(), values[x].value, values[x].authority, nVal));
}
}
else // put it in the browse index as if it hasn't have an authority key
{
// get the normalised version of the value
String nVal = OrderFormat.makeSortString(values[x].value, values[x].language, bis[i].getDataType());
distIDSet.add(dao.getDistinctID(bis[i].getDistinctTableName(), values[x].value, null, nVal));
}
}
}
}

View File

@@ -37,6 +37,8 @@
*/
package org.dspace.content;
import org.dspace.content.authority.Choices;
/**
* Simple data structure-like class representing a Dublin Core value. It has an
* element, qualifier, value and language.
@@ -62,4 +64,10 @@ public class DCValue
/** The schema name of the metadata element */
public String schema;
/** Authority control key */
public String authority = null;
/** Authority control confidence */
public int confidence = Choices.CF_UNSET;
}

View File

@@ -57,9 +57,13 @@ import org.dspace.authorize.AuthorizeManager;
import org.dspace.authorize.ResourcePolicy;
import org.dspace.browse.BrowseException;
import org.dspace.browse.IndexBrowse;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.core.LogManager;
import org.dspace.content.authority.Choices;
import org.dspace.content.authority.ChoiceAuthorityManager;
import org.dspace.content.authority.MetadataAuthorityManager;
import org.dspace.event.Event;
import org.dspace.eperson.EPerson;
import org.dspace.eperson.Group;
@@ -171,6 +175,8 @@ public class Item extends DSpaceObject
dcv.language = resultRow.getStringColumn("text_lang");
//dcv.namespace = schema.getNamespace();
dcv.schema = schema.getName();
dcv.authority = resultRow.getStringColumn("authority");
dcv.confidence = resultRow.getIntColumn("confidence");
// Add it to the list
dublinCore.add(dcv);
@@ -421,6 +427,12 @@ public class Item extends DSpaceObject
return myCollection;
}
// just get the collection ID for internal use
private int getOwningCollectionID()
{
return itemRow.getIntColumn("owning_collection");
}
/**
* Get Dublin Core metadata for the item.
* Passing in a <code>null</code> value for <code>qualifier</code>
@@ -531,7 +543,8 @@ public class Item extends DSpaceObject
copy.value = dcv.value;
copy.language = dcv.language;
copy.schema = dcv.schema;
copy.authority = dcv.authority;
copy.confidence = dcv.confidence;
values.add(copy);
}
}
@@ -634,6 +647,10 @@ public class Item extends DSpaceObject
* Add metadata fields. These are appended to existing values.
* Use <code>clearDC</code> to remove values. The ordering of values
* passed in is maintained.
* <p>
* If metadata authority control is available, try to get authority
* values. The authority confidence depends on whether authority is
* <em>required</em> or not.
* @param schema
* the schema for the metadata field. <em>Must</em> match
* the <code>name</code> of an existing metadata schema.
@@ -652,6 +669,56 @@ public class Item extends DSpaceObject
public void addMetadata(String schema, String element, String qualifier, String lang,
String[] values)
{
MetadataAuthorityManager mam = MetadataAuthorityManager.getManager();
String fieldKey = MetadataAuthorityManager.makeFieldKey(schema, element, qualifier);
if (mam.isAuthorityControlled(fieldKey))
{
String authorities[] = new String[values.length];
int confidences[] = new int[values.length];
for (int i = 0; i < values.length; ++i)
{
Choices c = ChoiceAuthorityManager.getManager().getBestMatch(fieldKey, values[i], getOwningCollectionID(), null);
authorities[i] = c.values.length > 0 ? c.values[0].authority : null;
confidences[i] = c.confidence;
}
addMetadata(schema, element, qualifier, lang, values, authorities, confidences);
}
else
addMetadata(schema, element, qualifier, lang, values, null, null);
}
/**
* Add metadata fields. These are appended to existing values.
* Use <code>clearDC</code> to remove values. The ordering of values
* passed in is maintained.
* @param schema
* the schema for the metadata field. <em>Must</em> match
* the <code>name</code> of an existing metadata schema.
* @param element
* the metadata element name
* @param qualifier
* the metadata qualifer name, or <code>null</code> for
* unqualified
* @param lang
* the ISO639 language code, optionally followed by an underscore
* and the ISO3166 country code. <code>null</code> means the
* value has no language (for example, a date).
* @param values
* the values to add.
* @param authority
* the external authority key for this value (or null)
* @param confidence
* the authority confidence (default 0)
*/
public void addMetadata(String schema, String element, String qualifier, String lang,
String[] values, String authorities[], int confidences[])
{
MetadataAuthorityManager mam = MetadataAuthorityManager.getManager();
ChoiceAuthorityManager cam = ChoiceAuthorityManager.getManager();
boolean authorityControlled = mam.isAuthorityControlled(schema, element, qualifier);
boolean authorityRequired = mam.isAuthorityRequired(schema, element, qualifier);
String fieldName = schema+"."+element+((qualifier==null)? "": "."+qualifier);
// We will not verify that they are valid entries in the registry
// until update() is called.
for (int i = 0; i < values.length; i++)
@@ -661,6 +728,30 @@ public class Item extends DSpaceObject
dcv.element = element;
dcv.qualifier = qualifier;
dcv.language = lang;
// Logic to set Authority and Confidence:
// - normalize an empty string for authority to NULL.
// - if authority key is present, use given confidence or NOVALUE if not given
// - otherwise, preserve confidence if meaningful value was given since it may document a failed authority lookup
// - CF_UNSET signifies no authority nor meaningful confidence.
// - it's possible to have empty authority & CF_ACCEPTED if e.g. user deletes authority key
if (authorityControlled)
{
if (authorities != null && authorities[i] != null && authorities[i].length() > 0)
{
dcv.authority = authorities[i];
dcv.confidence = confidences == null ? Choices.CF_NOVALUE : confidences[i];
}
else
{
dcv.authority = null;
dcv.confidence = confidences == null ? Choices.CF_UNSET : confidences[i];
}
// authority sanity check: if authority is required, was it supplied?
// XXX FIXME? can't throw a "real" exception here without changing all the callers to expect it, so use a runtime exception
if (authorityRequired && (dcv.authority == null || dcv.authority.length() == 0))
throw new IllegalArgumentException("The metadata field \""+fieldName+"\" requires an authority key but none was provided. Vaue=\""+dcv.value+"\"");
}
if (values[i] != null)
{
// remove control unicode char
@@ -683,8 +774,7 @@ public class Item extends DSpaceObject
dcv.value = null;
}
dublinCore.add(dcv);
addDetails(schema+"."+element+((qualifier==null)? "": "."+qualifier));
addDetails(fieldName);
}
if (values.length > 0)
@@ -721,6 +811,42 @@ public class Item extends DSpaceObject
addMetadata(schema, element, qualifier, lang, valArray);
}
/**
* Add a single metadata field. This is appended to existing
* values. Use <code>clearDC</code> to remove values.
*
* @param schema
* the schema for the metadata field. <em>Must</em> match
* the <code>name</code> of an existing metadata schema.
* @param element
* the metadata element name
* @param qualifier
* the metadata qualifer, or <code>null</code> for
* unqualified
* @param lang
* the ISO639 language code, optionally followed by an underscore
* and the ISO3166 country code. <code>null</code> means the
* value has no language (for example, a date).
* @param value
* the value to add.
* @param authority
* the external authority key for this value (or null)
* @param confidence
* the authority confidence (default 0)
*/
public void addMetadata(String schema, String element, String qualifier,
String lang, String value, String authority, int confidence)
{
String[] valArray = new String[1];
String[] authArray = new String[1];
int[] confArray = new int[1];
valArray[0] = value;
authArray[0] = authority;
confArray[0] = confidence;
addMetadata(schema, element, qualifier, lang, valArray, authArray, confArray);
}
/**
* Clear Dublin Core metadata values. As with <code>getDC</code> above,
* passing in <code>null</code> only matches fields where the qualifier or
@@ -1608,6 +1734,17 @@ public class Item extends DSpaceObject
matched = false;
}
// check that authority and confidence match
if (matched)
{
String auth = tr.getStringColumn("authority");
int conf = tr.getIntColumn("confidence");
if (!((dcv.authority == null && auth == null) ||
(dcv.authority != null && auth != null && dcv.authority.equals(auth))
&& dcv.confidence == conf))
matched = false;
}
// If the db record is identical to the in memory values
if (matched)
{
@@ -1649,6 +1786,8 @@ public class Item extends DSpaceObject
metadata.setValue(dcv.value);
metadata.setLanguage(dcv.language);
metadata.setPlace(placeNum[dcIdx]);
metadata.setAuthority(dcv.authority);
metadata.setConfidence(dcv.confidence);
metadata.create(ourContext);
}
}
@@ -2431,4 +2570,34 @@ public class Item extends DSpaceObject
return null;
}
}
/**
* Find all the items in the archive with a given authority key value
* in the indicated metadata field.
*
* @param context DSpace context object
* @param schema metdata field schema
* @param element metdata field element
* @param qualifier metdata field qualifier
* @param value the value of authority key to look for
* @return an iterator over the items matching that authority value
* @throws SQLException, AuthorizeException, IOException
*/
public static ItemIterator findByAuthorityValue(Context context,
String schema, String element, String qualifier, String value)
throws SQLException, AuthorizeException, IOException
{
MetadataSchema mds = MetadataSchema.find(context, schema);
if (mds == null)
throw new IllegalArgumentException("No such metadata schema: "+schema);
MetadataField mdf = MetadataField.findByElement(context, mds.getSchemaID(), element, qualifier);
if (mdf == null)
throw new IllegalArgumentException("No such metadata field: schema="+schema+", element="+element+", qualifier="+qualifier);
TableRowIterator rows = DatabaseManager.queryTable(context, "item",
"SELECT item.* FROM metadatavalue,item WHERE item.in_archive='1' "+
"AND item.item_id = metadatavalue.item_id AND metadata_field_id = ? AND authority = ?",
mdf.getFieldID(), value);
return new ItemIterator(context, rows);
}
}

View File

@@ -79,6 +79,12 @@ public class MetadataValue
/** The position of the record. */
public int place = 1;
/** Authority key, if any */
public String authority = null;
/** Authority confidence value -- see Choices class for values */
public int confidence = 0;
/** log4j logger */
private static Logger log = Logger.getLogger(MetadataValue.class);
@@ -100,6 +106,8 @@ public class MetadataValue
value = row.getStringColumn("text_value");
language = row.getStringColumn("text_lang");
place = row.getIntColumn("place");
authority = row.getStringColumn("authority");
confidence = row.getIntColumn("confidence");
this.row = row;
}
}
@@ -231,6 +239,46 @@ public class MetadataValue
this.value = value;
}
/**
* Get the metadata authority
*
* @return metadata authority
*/
public String getAuthority ()
{
return authority ;
}
/**
* Set the metadata authority
*
* @param value new metadata authority
*/
public void setAuthority (String value)
{
this.authority = value;
}
/**
* Get the metadata confidence
*
* @return metadata confidence
*/
public int getConfidence()
{
return confidence;
}
/**
* Set the metadata confidence
*
* @param value new metadata confidence
*/
public void setConfidence(int value)
{
this.confidence = value;
}
/**
* Creates a new metadata value.
*
@@ -248,6 +296,8 @@ public class MetadataValue
row.setColumn("text_value", value);
row.setColumn("text_lang", language);
row.setColumn("place", place);
row.setColumn("authority", authority);
row.setColumn("confidence", confidence);
DatabaseManager.insert(context, row);
// Remember the new row number
@@ -352,6 +402,8 @@ public class MetadataValue
row.setColumn("text_value", value);
row.setColumn("text_lang", language);
row.setColumn("place", place);
row.setColumn("authority", authority);
row.setColumn("confidence", confidence);
DatabaseManager.update(context, row);
log.info(LogManager.getHeader(context, "update_metadatavalue",

View File

@@ -0,0 +1,16 @@
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.dspace.content.authority;
import java.util.List;
/**
*
* @author bollini
*/
public interface AuthorityVariantsSupport {
public List<String> getVariants(String key, String locale);
}

View File

@@ -0,0 +1,68 @@
/*
* Choice.java
*
* Version: $Revision: 3705 $
*
* Date: $Date: 2009-04-11 13:02:24 -0400 (Sat, 11 Apr 2009) $
*
* Copyright (c) 2002-2009, The DSpace Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the DSpace Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
package org.dspace.content.authority;
/**
* Record class to hold the data describing one option, or choice, for an
* authority-controlled metadata value.
*
* @author Larry Stone
* @see Choices
*/
public class Choice
{
/** Authority key for this value */
public String authority = null;
/** Label to display for this value (e.g. to present in UI menu) */
public String label = null;
/** The canonical text value to insert into MetadataValue's text field */
public String value = null;
public Choice()
{
}
public Choice(String authority, String value, String label)
{
this.authority = authority;
this.value = value;
this.label = label;
}
}

View File

@@ -0,0 +1,101 @@
/*
* ChoiceAuthority.java
*
* Version: $Revision: 3705 $
*
* Date: $Date: 2009-04-11 13:02:24 -0400 (Sat, 11 Apr 2009) $
*
* Copyright (c) 2002-2009, The DSpace Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the DSpace Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
package org.dspace.content.authority;
/**
* Plugin interface that supplies an authority control mechanism for
* one metadata field.
*
* @author Larry Stone
* @see ChoiceAuthorityManager, MetadataAuthorityManager
*/
public interface ChoiceAuthority
{
/**
* Get all values from the authority that match the proferred value.
* Note that the offering was entered by the user and may contain
* mixed/incorrect case, whitespace, etc so the plugin should be careful
* to clean up user data before making comparisons.
*
* Value of a "Name" field will be in canonical DSpace person name format,
* which is "Lastname, Firstname(s)", e.g. "Smith, John Q.".
*
* Some authorities with a small set of values may simply return the whole
* set for any sample value, although it's a good idea to set the
* defaultSelected index in the Choices instance to the choice, if any,
* that matches the value.
*
* @param text user's value to match
* @param collection database ID of Collection for context (owner of Item)
* @param start choice at which to start, 0 is first.
* @param limit maximum number of choices to return, 0 for no limit.
* @param locale explicit localization key if available, or null
* @return a Choices object (never null).
*/
public Choices getMatches(String text, int collection, int start, int limit, String locale);
/**
* Get the single "best" match (if any) of a value in the authority
* to the given user value. The "confidence" element of Choices is
* expected to be set to a meaningful value about the circumstances of
* this match.
*
* This call is typically used in non-interactive metadata ingest
* where there is no interactive agent to choose from among options.
*
* @param text user's value to match
* @param collection database ID of Collection for context (owner of Item)
* @param locale explicit localization key if available, or null
* @return a Choices object (never null) with 1 or 0 values.
*/
public Choices getBestMatch(String text, int collection, String locale);
/**
* Get the canonical user-visible "label" (i.e. short descriptive text)
* for a key in the authority. Can be localized given the implicit
* or explicit locale specification.
*
* This may get called many times while populating a Web page so it should
* be implemented as efficiently as possible.
*
* @param key authority key known to this authority.
* @param locale explicit localization key if available, or null
* @return descriptive label - should always return something, never null.
*/
public String getLabel(String key, String locale);
}

View File

@@ -0,0 +1,326 @@
/*
* ChoiceAuthorityManager.java
*
* Version: $Revision: 3705 $
*
* Date: $Date: 2009-04-11 13:02:24 -0400 (Sat, 11 Apr 2009) $
*
* Copyright (c) 2002-2009, The DSpace Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the DSpace Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
package org.dspace.content.authority;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.Enumeration;
import org.apache.log4j.Logger;
import org.dspace.content.MetadataField;
import org.dspace.content.Collection;
import org.dspace.content.ItemIterator;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.PluginManager;
/**
* Broker for ChoiceAuthority plugins, and for other information configured
* about the choice aspect of authority control for a metadata field.
*
* Configuration keys, per metadata field (e.g. "dc.contributer.author")
*
* # names the ChoiceAuthority plugin called for this field
* choices.plugin.<FIELD> = name-of-plugin
*
* # mode of UI presentation desired in submission UI:
* # "select" is dropdown menu, "lookup" is popup with selector, "suggest" is autocomplete/suggest
* choices.presentation.<FIELD> = "select" | "suggest"
*
* # is value "closed" to the set of these choices or are non-authority values permitted?
* choices.closed.<FIELD> = true | false
*
* @author Larry Stone
* @see ChoiceAuthority
*/
public class ChoiceAuthorityManager
{
private static Logger log = Logger.getLogger(ChoiceAuthorityManager.class);
private static ChoiceAuthorityManager cached = null;
// map of field key to authority plugin
private Map<String,ChoiceAuthority> controller = new HashMap<String,ChoiceAuthority>();
// map of field key to presentation type
private Map<String,String> presentation = new HashMap<String,String>();
// map of field key to closed value
private Map<String,Boolean> closed = new HashMap<String,Boolean>();
private ChoiceAuthorityManager()
{
Enumeration pn = ConfigurationManager.propertyNames();
final String choicesPrefix = "choices.";
final String choicesPlugin = "choices.plugin.";
final String choicesPresentation = "choices.presentation.";
final String choicesClosed = "choices.closed.";
property:
while (pn.hasMoreElements())
{
String key = (String)pn.nextElement();
if (key.startsWith(choicesPrefix))
{
if (key.startsWith(choicesPlugin))
{
String fkey = config2fkey(key.substring(choicesPlugin.length()));
if (fkey == null)
{
log.warn("Skipping invalid ChoiceAuthority configuration property: "+key+": does not have schema.element.qualifier");
continue property;
}
// XXX FIXME maybe add sanity check, call
// MetadataField.findByElement to maek sure it's a real field.
ChoiceAuthority ma = (ChoiceAuthority)
PluginManager.getNamedPlugin(ChoiceAuthority.class, ConfigurationManager.getProperty(key));
if (ma == null)
{
log.warn("Skipping invalid configuration for "+key+" because named plugin not found: "+ConfigurationManager.getProperty(key));
continue property;
}
controller.put(fkey, ma);
log.debug("Choice Control: For field="+fkey+", Plugin="+ma);
}
else if (key.startsWith(choicesPresentation))
{
String fkey = config2fkey(key.substring(choicesPresentation.length()));
if (fkey == null)
{
log.warn("Skipping invalid ChoiceAuthority configuration property: "+key+": does not have schema.element.qualifier");
continue property;
}
presentation.put(fkey, ConfigurationManager.getProperty(key));
}
else if (key.startsWith(choicesClosed))
{
String fkey = config2fkey(key.substring(choicesClosed.length()));
if (fkey == null)
{
log.warn("Skipping invalid ChoiceAuthority configuration property: "+key+": does not have schema.element.qualifier");
continue property;
}
closed.put(fkey, new Boolean(ConfigurationManager.getBooleanProperty(key)));
}
else
log.error("Illegal configuration property: "+key);
}
}
}
/** Factory method */
public static ChoiceAuthorityManager getManager()
{
if (cached == null)
{
cached = new ChoiceAuthorityManager();
}
return cached;
}
// translate tail of configuration key (supposed to be schema.element.qual)
// into field key
private String config2fkey(String field)
{
// field is expected to be "schema.element.qualifier"
int dot = field.indexOf(".");
if (dot < 0)
return null;
String schema = field.substring(0, dot);
String element = field.substring(dot+1);
String qualifier = null;
dot = element.indexOf(".");
if (dot >= 0)
{
qualifier = element.substring(dot+1);
element = element.substring(0, dot);
}
return makeFieldKey(schema, element, qualifier);
}
/**
* Wrapper that calls getMatches method of the plugin corresponding to
* the metadata field defined by schema,element,qualifier.
*
* @see ChoiceAuthority.getMatches
* @param schema schema of metadata field
* @param element element of metadata field
* @param qualifier qualifier of metadata field
* @param text user's value to match
* @param collection database ID of Collection for context (owner of Item)
* @param start choice at which to start, 0 is first.
* @param limit maximum number of choices to return, 0 for no limit.
* @param locale explicit localization key if available, or null
* @return a Choices object (never null).
*/
public Choices getMatches(String schema, String element, String qualifier,
String query, int collection, int start, int limit, String locale)
{
return getMatches(makeFieldKey(schema, element, qualifier), query, collection, start, limit, locale);
}
/**
* Wrapper calls getMatches method of the plugin corresponding to
* the metadata field defined by single field key.
*
* @see ChoiceAuthority.getMatches
* @param fieldKey single string identifying metadata field
* @param text user's value to match
* @param collection database ID of Collection for context (owner of Item)
* @param start choice at which to start, 0 is first.
* @param limit maximum number of choices to return, 0 for no limit.
* @param locale explicit localization key if available, or null
* @return a Choices object (never null).
*/
public Choices getMatches(String fieldKey, String query, int collection, int start, int limit, String locale)
{
ChoiceAuthority ma = controller.get(fieldKey);
if (ma == null)
throw new IllegalArgumentException("No choices plugin was configured for field \""+fieldKey+"\".");
return ma.getMatches(query, collection, start, limit, locale);
}
/**
* Wrapper that calls getBestMatch method of the plugin corresponding to
* the metadata field defined by single field key.
*
* @see ChoiceAuthority.getBestMatch
* @param fieldKey single string identifying metadata field
* @param text user's value to match
* @param collection database ID of Collection for context (owner of Item)
* @param locale explicit localization key if available, or null
* @return a Choices object (never null) with 1 or 0 values.
*/
public Choices getBestMatch(String fieldKey, String query, int collection, String locale)
{
ChoiceAuthority ma = controller.get(fieldKey);
if (ma == null)
throw new IllegalArgumentException("No choices plugin was configured for field \""+fieldKey+"\".");
return ma.getBestMatch(query, collection, locale);
}
/**
* Wrapper that calls getLabel method of the plugin corresponding to
* the metadata field defined by schema,element,qualifier.
*/
public String getLabel(String schema, String element, String qualifier,
String authKey, String locale)
{
return getLabel(makeFieldKey(schema, element, qualifier), authKey, locale);
}
/**
* Wrapper that calls getLabel method of the plugin corresponding to
* the metadata field defined by single field key.
*/
public String getLabel(String fieldKey, String authKey, String locale)
{
ChoiceAuthority ma = controller.get(fieldKey);
if (ma == null)
throw new IllegalArgumentException("No choices plugin was configured for field \""+fieldKey+"\".");
return ma.getLabel(authKey, locale);
}
/**
* Predicate, is there a Choices configuration of any kind for the
* given metadata field?
* @return true if choices are configured for this field.
*/
public boolean isChoicesConfigured(String fieldKey)
{
return controller.containsKey(fieldKey);
}
/**
* Get the presentation keyword (should be "lookup", "select" or "suggest", but this
* is an informal convention so it can be easily extended) for this field.
*
* @return configured presentation type for this field, or null if none found
*/
public String getPresentation(String fieldKey)
{
return presentation.get(fieldKey);
}
/**
* Get the configured "closed" value for this field.
*
* @return true if choices are closed for this field.
*/
public boolean isClosed(String fieldKey)
{
return closed.containsKey(fieldKey) ? closed.get(fieldKey).booleanValue() : false;
}
/**
* Construct a single key from the tuple of schema/element/qualifier
* that describes a metadata field. Punt to the function we use for
* submission UI input forms, for now.
*/
public static String makeFieldKey(String schema, String element, String qualifier)
{
return MetadataField.formKey(schema, element, qualifier);
}
/**
* Construct a single key from the "dot" notation e.g. "dc.rights"
*/
public static String makeFieldKey(String dotty)
{
return dotty.replace(".", "_");
}
/**
* Wrapper to call plugin's getVariants().
*/
public List<String> getVariants(String schema, String element, String qualifier,
String authorityKey, String language)
{
ChoiceAuthority ma = controller.get(makeFieldKey(schema, element, qualifier));
if (ma instanceof AuthorityVariantsSupport)
{
AuthorityVariantsSupport avs = (AuthorityVariantsSupport) ma;
return avs.getVariants(authorityKey, language);
}
return null;
}
}

View File

@@ -0,0 +1,216 @@
/*
* Choices.java
*
* Version: $Revision: 3705 $
*
* Date: $Date: 2009-04-11 13:02:24 -0400 (Sat, 11 Apr 2009) $
*
* Copyright (c) 2002-2009, The DSpace Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the DSpace Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
package org.dspace.content.authority;
/**
* Record class to hold a set of Choices returned by an authority in response
* to a search.
*
* @author Larry Stone
* @see Choice
*/
public class Choices
{
/** -------------- Class fields ----------------- **/
/** Canonical values of the confidence metric. Higher is better. */
/** This authority value has been confirmed as accurate by an
interactive user or authoritative policy */
public static final int CF_ACCEPTED = 600;
/** Value is singular and valid but has not been seen and accepted
by a human, so its provenance is uncertain. */
public static final int CF_UNCERTAIN = 500;
/** There are multiple matching authority values of equal validity. */
public static final int CF_AMBIGUOUS = 400;
/** There are no matching answers from the authority. */
public static final int CF_NOTFOUND = 300;
/** The authority encountered an internal failure - this preserves a
record in the metadata of why there is no value. */
public static final int CF_FAILED = 200;
/** The authority recommends this submission be rejected. */
public static final int CF_REJECTED = 100;
/** No reasonable confidence value is available */
public static final int CF_NOVALUE = 0;
/** Value has not been set (DB default). */
public static final int CF_UNSET = -1;
/** descriptive labels for confidence values */
private static final int confidenceValue[] = {
CF_UNSET,
CF_NOVALUE,
CF_REJECTED,
CF_FAILED,
CF_NOTFOUND,
CF_AMBIGUOUS,
CF_UNCERTAIN,
CF_ACCEPTED,
};
private static final String confidenceText[] = {
"UNSET",
"NOVALUE",
"REJECTED",
"FAILED",
"NOTFOUND",
"AMBIGUOUS",
"UNCERTAIN",
"ACCEPTED"
};
/** -------------- Instance fields ----------------- **/
/** The set of values returned by the authority */
public Choice values[] = null;
/** The confidence level that applies to all values in this result set */
public int confidence = CF_NOVALUE;
/** Index of start of this result wrt. all results; 0 is start of
complete result. Note that length is implicit in values.length. */
public int start = 0;
/** Count of total results available */
public int total = 0;
/** Index of value to be selected by default, if any. -1 means none selected. */
public int defaultSelected = -1;
/** true when there are more values to be sent after this result. */
public boolean more = false;
/** -------------- Methods ----------------- **/
/**
* Constructor for general purpose
*/
public Choices(Choice values[], int start, int total, int confidence, boolean more)
{
super();
this.values = values;
this.start = start;
this.total = total;
this.confidence = confidence;
this.more = more;
}
/**
* Constructor for general purpose
*/
public Choices(Choice values[], int start, int total, int confidence, boolean more, int defaultSelected)
{
super();
this.values = values;
this.start = start;
this.total = total;
this.confidence = confidence;
this.more = more;
this.defaultSelected = defaultSelected;
}
/**
* Constructor for error results
*/
public Choices(int confidence)
{
this.values = new Choice[0];
this.confidence = confidence;
}
/**
* Constructor for simple empty or error results
*/
public Choices(boolean isError)
{
this.values = new Choice[0];
this.confidence = isError ? CF_FAILED : CF_NOVALUE;
}
/**
* Predicate, did this result encounter an error?
* @return true if this Choices result encountered an error
*/
public boolean isError()
{
return confidence == CF_FAILED || confidence == CF_REJECTED;
}
/**
* Get the symbolic name corresponding to a confidence value, or CF_NOVALUE's
* name if the value is unknown.
*
* @param cv confidence value
* @return String with symbolic name corresponding to value (never null)
*/
public static String getConfidenceText(int cv)
{
String novalue = null;
for (int i = 0; i < confidenceValue.length; ++i)
{
if (confidenceValue[i] == cv)
return confidenceText[i];
else if (confidenceValue[i] == CF_NOVALUE)
novalue = confidenceText[i];
}
return novalue;
}
/**
* Get the value corresponding to a symbolic name of a confidence
* value, or CF_NOVALUE if the symbol is unknown.
*
* @param ct symbolic name in String
* @return corresponding value or CF_NOVALUE if not found
*/
public static int getConfidenceValue(String ct)
{
for (int i = 0; i < confidenceText.length; ++i)
{
if (confidenceText[i].equalsIgnoreCase(ct))
return confidenceValue[i];
}
return CF_NOVALUE;
}
}

View File

@@ -0,0 +1,143 @@
/*
* ChoicesXMLGenerator.java
*
* Version: $Revision: 3705 $
*
* Date: $Date: 2009-04-11 13:02:24 -0400 (Sat, 11 Apr 2009) $
*
* Copyright (c) 2002-2009, The DSpace Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the DSpace Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
package org.dspace.content.authority;
import org.dspace.content.authority.Choices;
import org.dspace.content.authority.Choice;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.ext.LexicalHandler;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.AttributesImpl;
/**
* Record class to hold a set of Choices returned by an authority in response
* to a search.
*
* @author Larry Stone
* @see Choice
*/
public class ChoicesXMLGenerator
{
// use the XHTML NS, even though this is a fragment.
private static final String NS_URI = "http://www.w3.org/1999/xhtml";
private static final String NS_NAME = "";
public static void generate(Choices result, String format, ContentHandler contentHandler)
throws SAXException
{
Attributes noAtts = new AttributesImpl();
AttributesImpl resultAtts = new AttributesImpl();
if (result.more)
resultAtts.addAttribute("", "more", "more", "boolean", "true");
if (result.isError())
resultAtts.addAttribute("", "error", "error", "boolean", "true");
resultAtts.addAttribute("", "start", "start", "int", String.valueOf(result.start));
resultAtts.addAttribute("", "total", "total", "int", String.valueOf(result.total));
contentHandler.startDocument();
// "select" HTML format for DSpace popup
if (format != null && format.equalsIgnoreCase("select"))
{
contentHandler.startElement(NS_URI, NS_NAME, "select", resultAtts);
for (int i = 0; i < result.values.length; ++i)
{
Choice mdav = result.values[i];
AttributesImpl va = new AttributesImpl();
va.addAttribute("", "authority", "authority", "string", mdav.authority == null ? "":mdav.authority);
va.addAttribute("", "value", "value", "string", mdav.value);
if (result.defaultSelected == i)
va.addAttribute("", "selected", "selected", "boolean", "");
contentHandler.startElement(NS_URI, NS_NAME, "option", va);
contentHandler.characters(mdav.label.toCharArray(), 0, mdav.label.length());
contentHandler.endElement(NS_URI, NS_NAME, "option");
}
contentHandler.endElement(NS_URI, NS_NAME, "select");
}
// "ul" HTML format (required by Scriptactulous autocomplete)
else if (format != null && format.equalsIgnoreCase("ul"))
{
AttributesImpl classLabel = new AttributesImpl();
classLabel.addAttribute("", "class", "class", "string", "label");
AttributesImpl classValue = new AttributesImpl();
classValue.addAttribute("", "class", "class", "string", "value");
contentHandler.startElement(NS_URI, NS_NAME, "ul", resultAtts);
for (int i = 0; i < result.values.length; ++i)
{
Choice mdav = result.values[i];
AttributesImpl va = new AttributesImpl();
va.addAttribute("", "authority", "authority", "string", mdav.authority == null ? "":mdav.authority);
if (result.defaultSelected == i)
va.addAttribute("", "selected", "selected", "boolean", "");
contentHandler.startElement(NS_URI, NS_NAME, "li", va);
contentHandler.startElement(NS_URI, NS_NAME, "span", classLabel);
contentHandler.characters(mdav.label.toCharArray(), 0, mdav.label.length());
contentHandler.endElement(NS_URI, NS_NAME, "span");
contentHandler.startElement(NS_URI, NS_NAME, "span", classValue);
contentHandler.characters(mdav.value.toCharArray(), 0, mdav.value.length());
contentHandler.endElement(NS_URI, NS_NAME, "span");
contentHandler.endElement(NS_URI, NS_NAME, "li");
}
contentHandler.endElement(NS_URI, NS_NAME, "ul");
}
// default is XML format, Choices/Choice
else
{
contentHandler.startElement(NS_URI, NS_NAME, "Choices", resultAtts);
for (int i = 0; i < result.values.length; ++i)
{
Choice mdav = result.values[i];
AttributesImpl va = new AttributesImpl();
va.addAttribute("", "authority", "authority", "string", mdav.authority == null ? "":mdav.authority);
va.addAttribute("", "value", "value", "string", mdav.value);
if (result.defaultSelected == i)
va.addAttribute("", "selected", "selected", "boolean", "");
contentHandler.startElement(NS_URI, NS_NAME, "Choice", va);
contentHandler.characters(mdav.label.toCharArray(), 0, mdav.label.length());
contentHandler.endElement(NS_URI, NS_NAME, "Choice");
}
contentHandler.endElement(NS_URI, NS_NAME, "Choices");
}
contentHandler.endDocument();
}
}

View File

@@ -0,0 +1,167 @@
/*
* DCInputAuthority.java
*
* Version: $Revision: 1.1 $
*
* Date: $Date: 2009/07/23 05:07:01 $
*
* Copyright (c) 2002-2009, The DSpace Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the DSpace Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
package org.dspace.content.authority;
import java.util.Iterator;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.Logger;
import org.dspace.app.util.DCInputsReader;
import org.dspace.app.util.DCInputsReaderException;
import org.dspace.core.SelfNamedPlugin;
/**
* ChoiceAuthority source that reads the same input-forms which drive
* configurable submission.
*
* Configuration:
* This MUST be configured aas a self-named plugin, e.g.:
* plugin.selfnamed.org.dspace.content.authority.ChoiceAuthority = \
* org.dspace.content.authority.DCInputAuthority
*
* It AUTOMATICALLY configures a plugin instance for each <value-pairs>
* element (within <form-value-pairs>) of the input-forms.xml. The name
* of the instance is the "value-pairs-name" attribute, e.g.
* the element: <value-pairs value-pairs-name="common_types" dc-term="type">
* defines a plugin instance "common_types".
*
* IMPORTANT NOTE: Since these value-pairs do NOT include authority keys,
* the choice lists derived from them do not include authority values.
* So you should not use them as the choice source for authority-controlled
* fields.
*/
public class DCInputAuthority extends SelfNamedPlugin implements ChoiceAuthority
{
private static Logger log = Logger.getLogger(DCInputAuthority.class);
private String values[] = null;
private String labels[] = null;
private static DCInputsReader dci = null;
private static String pluginNames[] = null;
public DCInputAuthority()
{
super();
}
public static String[] getPluginNames()
{
if (pluginNames == null)
{
try
{
if (dci == null)
dci = new DCInputsReader();
}
catch (DCInputsReaderException e)
{
log.error("Failed reading DCInputs initialization: ",e);
}
List<String> names = new ArrayList<String>();
Iterator pi = dci.getPairsNameIterator();
while (pi.hasNext())
names.add((String)pi.next());
pluginNames = names.toArray(new String[names.size()]);
log.debug("Got plugin names = "+Arrays.deepToString(pluginNames));
}
return pluginNames;
}
// once-only load of values and labels
private void init()
{
if (values == null)
{
String pname = this.getPluginInstanceName();
List<String> pairs = (List<String>)dci.getPairs(pname);
if (pairs != null)
{
values = new String[pairs.size()/2];
labels = new String[pairs.size()/2];
for (int i = 0; i < pairs.size(); i += 2)
{
labels[i/2] = pairs.get(i);
values[i/2] = pairs.get(i+1);
}
log.debug("Found pairs for name="+pname);
}
else
log.error("Failed to find any pairs for name="+pname, new IllegalStateException());
}
}
public Choices getMatches(String query, int collection, int start, int limit, String locale)
{
init();
int dflt = -1;
Choice v[] = new Choice[values.length];
for (int i = 0; i < values.length; ++i)
{
v[i] = new Choice(values[i], values[i], labels[i]);
if (values[i].equalsIgnoreCase(query))
dflt = i;
}
return new Choices(v, 0, v.length, Choices.CF_AMBIGUOUS, false, dflt);
}
public Choices getBestMatch(String text, int collection, String locale)
{
init();
for (int i = 0; i < values.length; ++i)
{
if (text.equalsIgnoreCase(values[i]))
{
Choice v[] = new Choice[1];
v[0] = new Choice(String.valueOf(i), values[i], labels[i]);
return new Choices(v, 0, v.length, Choices.CF_UNCERTAIN, false, 0);
}
}
return new Choices(Choices.CF_NOTFOUND);
}
public String getLabel(String key, String locale)
{
init();
return labels[Integer.parseInt(key)];
}
}

View File

@@ -0,0 +1,374 @@
/*
* LCNameAuthority.java
*
* Version: $Revision: 3705 $
*
* Date: $Date: 2009-04-11 13:02:24 -0400 (Sat, 11 Apr 2009) $
*
* Copyright (c) 2002-2009, The DSpace Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the DSpace Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
package org.dspace.content.authority;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.FileReader;
import java.io.BufferedReader;
import java.util.Enumeration;
import java.util.List;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.XMLReader;
import org.xml.sax.InputSource;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXParseException;
import org.apache.log4j.Logger;
import org.dspace.core.ConfigurationManager;
import org.dspace.content.DCPersonName;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.util.EncodingUtil;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.HttpException;
/**
* Sample personal name authority based on Library of Congress Name Authority
* Also serves as an example of an SRU client as authority.
*
* This is tuned for the data in the LC Name Authority test instance, see
* http://alcme.oclc.org/srw/search/lcnaf
*
* WARNING: This is just a proof-of-concept implementation. It would need
* WARNING: lots of refinement to be used in production, because it is very
* WARNING: sloppy about digging through the MARC/XML results. No doubt
* WARNING: it is losing a lot of valid results and information.
* WARNING: Could also do a better job including more info (title, life dates
* WARNING: etc) in the label instead of just the name.
*
* Reads these DSpace Config properties:
*
* lcname.url = http://alcme.oclc.org/srw/search/lcnaf
*
* TODO: make # of results to ask for (and return) configurable.
*
* @author Larry Stone
* @version $Revision $
*/
public class LCNameAuthority implements ChoiceAuthority
{
private static Logger log = Logger.getLogger(LCNameAuthority.class);
// get these from configuration
private static String url = null;
// NS URI for SRU respones
private static final String NS_SRU = "http://www.loc.gov/zing/srw/";
// NS URI for MARC/XML
private static final String NS_MX = "http://www.loc.gov/MARC21/slim";
// constructor does static init too..
public LCNameAuthority()
{
if (url == null)
{
url = ConfigurationManager.getProperty("lcname.url");
// sanity check
if (url == null)
throw new IllegalStateException("Missing DSpace configuration keys for LCName Query");
}
}
// punt! this is a poor implementation..
public Choices getBestMatch(String text, int collection, String locale)
{
return getMatches(text, collection, 0, 2, locale);
}
/**
* Match a proposed value against name authority records
* Value is assumed to be in "Lastname, Firstname" format.
*/
public Choices getMatches(String text, int collection, int start, int limit, String locale)
{
boolean error = false;
Choices result = queryPerson(text, start, limit);
if (result == null)
result = new Choices(true);
return result;
}
// punt; supposed to get the canonical display form of a metadata authority key
// XXX FIXME implement this with a query on the authority key, cache results
public String getLabel(String key, String locale)
{
return key;
}
/**
* Guts of the implementation, returns a complete Choices result, or
* null for a failure.
*/
private Choices queryPerson(String text, int start, int limit)
{
// punt if there is no query text
if (text == null || text.trim().length() == 0)
return new Choices(true);
// 1. build CQL query
DCPersonName pn = new DCPersonName(text);
StringBuilder query = new StringBuilder();
query.append("local.FirstName = \"").append(pn.getFirstNames()).
append("\" and local.FamilyName = \"").append(pn.getLastName()).
append("\"");
// XXX arbitrary default limit - should be configurable?
if (limit == 0)
limit = 50;
NameValuePair args[] = new NameValuePair[6];
args[0] = new NameValuePair("operation", "searchRetrieve");
args[1] = new NameValuePair("version", "1.1");
args[2] = new NameValuePair("recordSchema", "info:srw/schema/1/marcxml-v1.1");
args[3] = new NameValuePair("query", query.toString());
args[4] = new NameValuePair("maximumRecords", String.valueOf(limit));
args[5] = new NameValuePair("startRecord", String.valueOf(start+1));
HttpClient hc = new HttpClient();
String srUrl = url + "?" + EncodingUtil.formUrlEncode(args, "UTF8");
GetMethod get = new GetMethod(srUrl);
log.debug("Trying SRU query, URL="+srUrl);
// 2. web request
try
{
int status = hc.executeMethod(get);
if (status == 200)
{
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();
XMLReader xr = sp.getXMLReader();
SRUHandler handler = new SRUHandler();
// XXX FIXME: should turn off validation here explicitly, but
// it seems to be off by default.
xr.setFeature("http://xml.org/sax/features/namespaces", true);
xr.setContentHandler(handler);
xr.setErrorHandler(handler);
xr.parse(new InputSource(get.getResponseBodyAsStream()));
// this probably just means more results available..
if (handler.hits != handler.result.size())
log.warn("Discrepency in results, result.length="+handler.result.size()+
", yet expected results="+handler.hits);
boolean more = handler.hits > (start + handler.result.size());
// XXX add non-auth option; perhaps the UI should do this?
// XXX it's really a policy matter if they allow unauth result.
// XXX good, stop it.
// handler.result.add(new Choice("", text, "Non-Authority: \""+text+"\""));
int confidence;
if (handler.hits == 0)
confidence = Choices.CF_NOTFOUND;
else if (handler.hits == 1)
confidence = Choices.CF_UNCERTAIN;
else
confidence = Choices.CF_AMBIGUOUS;
return new Choices(handler.result.toArray(new Choice[handler.result.size()]),
start, handler.hits, confidence, more);
}
}
catch (HttpException e)
{
log.error("SRU query failed: ", e);
return new Choices(true);
}
catch (IOException e)
{
log.error("SRU query failed: ", e);
return new Choices(true);
}
catch (ParserConfigurationException e)
{
log.warn("Failed parsing SRU result: ", e);
return new Choices(true);
}
catch (SAXException e)
{
log.warn("Failed parsing SRU result: ", e);
return new Choices(true);
}
finally
{
get.releaseConnection();
}
return new Choices(true);
}
/**
* XXX FIXME TODO: Very sloppy MARC/XML parser.
* This only reads subfields 010.a (for LCCN, to use as key)
* and 100.a (for "established personal name")
* Maybe look at Indicator on 100 too.
* Should probably read other 100 subfields to build a more detailed label.
*/
private static class SRUHandler
extends DefaultHandler
{
private List<Choice> result = new ArrayList<Choice>();
private int hits = -1;
private String textValue = null;
private String name = null;
private String lccn = null;
private String lastTag = null;
private String lastCode = null;
// NOTE: text value MAY be presented in multiple calls, even if
// it all one word, so be ready to splice it together.
// BEWARE: subclass's startElement method should call super()
// to null out 'value'. (Don't you miss the method combination
// options of a real object system like CLOS?)
public void characters(char[] ch, int start, int length)
throws SAXException
{
String newValue = new String(ch, start, length);
if (newValue.length() > 0)
{
if (textValue == null)
textValue = newValue;
else
textValue += newValue;
}
}
public void endElement(String namespaceURI, String localName,
String qName)
throws SAXException
{
if (localName.equals("numberOfRecords") &&
namespaceURI.equals(NS_SRU))
{
hits = Integer.parseInt(textValue.trim());
if (hits > 0)
{
name = null;
lccn = null;
log.debug("Expecting "+hits+" records in results.");
}
}
// after record get next hit ready
else if (localName.equals("record") &&
namespaceURI.equals(NS_SRU))
{
if (name != null && lccn != null)
{
// HACK: many LC name entries end with ',' ...trim it.
if (name.endsWith(","))
name = name.substring(0, name.length()-1);
// XXX DEBUG
// log.debug("Got result, name="+name+", lccn="+lccn);
result.add(new Choice(lccn, name, name));
}
else
log.warn("Got anomalous result, at least one of these null: lccn="+lccn+", name="+name);
name = null;
lccn = null;
}
else if (localName.equals("subfield") &&
namespaceURI.equals(NS_MX))
{
if (lastTag != null && lastCode != null)
{
// 010.a is lccn, "authority code"
if (lastTag.equals("010") && lastCode.equals("a"))
lccn = textValue;
// 100.a is the personal name
else if (lastTag.equals("100") && lastCode.equals("a"))
name = textValue;
}
}
}
// subclass overriding this MUST call it with super()
public void startElement(String namespaceURI, String localName,
String qName, Attributes atts)
throws SAXException
{
textValue = null;
if (localName.equals("datafield") &&
namespaceURI.equals(NS_MX))
{
lastTag = atts.getValue("tag");
if (lastTag == null)
log.warn("MARC datafield without tag attribute!");
}
else if (localName.equals("subfield") &&
namespaceURI.equals(NS_MX))
{
lastCode = atts.getValue("code");
if (lastCode == null)
log.warn("MARC subfield without code attribute!");
}
}
public void error(SAXParseException exception)
throws SAXException
{
throw new SAXException(exception);
}
public void fatalError(SAXParseException exception)
throws SAXException
{
throw new SAXException(exception);
}
}
}

View File

@@ -0,0 +1,205 @@
/*
* MetadataAuthorityManager.java
*
* Version: $Revision: 3705 $
*
* Date: $Date: 2009-04-11 13:02:24 -0400 (Sat, 11 Apr 2009) $
*
* Copyright (c) 2002-2009, The DSpace Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the DSpace Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
package org.dspace.content.authority;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.Enumeration;
import org.apache.log4j.Logger;
import org.dspace.content.MetadataField;
import org.dspace.content.Collection;
import org.dspace.content.ItemIterator;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.PluginManager;
/**
* Broker for metadata authority settings configured for each metadata field.
*
* Configuration keys, per metadata field (e.g. "dc.contributer.author")
*
* # is field authority controlled (i.e. store authority, confidence values)?
* authority.controlled.<FIELD> = true
*
* # is field required to have an authority value, or may it be empty?
* # default is false.
* authority.required.<FIELD> = true | false
*
* NOTE: There is *expected* to be a "choices" (see ChoiceAuthorityManager)
* configuration for each authority-controlled field.
*
* @see ChoiceAuthorityManager
* @author Larry Stone
*/
public class MetadataAuthorityManager
{
private static Logger log = Logger.getLogger(MetadataAuthorityManager.class);
private static MetadataAuthorityManager cached = null;
// map of field key to authority plugin
private Map<String,Boolean> controlled = new HashMap<String,Boolean>();
// map of field key to answer of whether field is required to be controlled
private Map<String,Boolean> isAuthorityRequired = new HashMap<String,Boolean>();
/**
* map of field key to answer of which is the min acceptable confidence
* value for a field with authority
*/
private Map<String, Integer> minConfidence = new HashMap<String, Integer>();
private MetadataAuthorityManager()
{
Enumeration pn = ConfigurationManager.propertyNames();
final String authPrefix = "authority.controlled.";
property:
while (pn.hasMoreElements())
{
String key = (String)pn.nextElement();
if (key.startsWith(authPrefix))
{
// field is expected to be "schema.element.qualifier"
String field = key.substring(authPrefix.length());
int dot = field.indexOf(".");
if (dot < 0)
{
log.warn("Skipping invalid MetadataAuthority configuration property: "+key+": does not have schema.element.qualifier");
continue property;
}
String schema = field.substring(0, dot);
String element = field.substring(dot+1);
String qualifier = null;
dot = element.indexOf(".");
if (dot >= 0)
{
qualifier = element.substring(dot+1);
element = element.substring(0, dot);
}
String fkey = makeFieldKey(schema, element, qualifier);
boolean ctl = ConfigurationManager.getBooleanProperty(key, true);
boolean req = ConfigurationManager.getBooleanProperty("authority.required."+field, false);
controlled.put(fkey, Boolean.valueOf(ctl));
isAuthorityRequired.put(fkey, Boolean.valueOf(req));
if (ConfigurationManager.getProperty("authority.minconfidence."+field) != null)
{
minConfidence.put(fkey, ConfigurationManager.getIntProperty("authority.minconfidence." + field));
}
log.debug("Authority Control: For schema="+schema+", elt="+element+", qual="+qualifier+", controlled="+ctl+", required="+req);
}
}
}
// factory method
public static MetadataAuthorityManager getManager()
{
if (cached == null)
{
cached = new MetadataAuthorityManager();
}
return cached;
}
/** Predicate - is field authority-controlled? */
public boolean isAuthorityControlled(String schema, String element, String qualifier)
{
return isAuthorityControlled(makeFieldKey(schema, element, qualifier));
}
/** Predicate - is field authority-controlled? */
public boolean isAuthorityControlled(String fieldKey)
{
return controlled.containsKey(fieldKey) && controlled.get(fieldKey).booleanValue();
}
/** Predicate - is authority value required for field? */
public boolean isAuthorityRequired(String schema, String element, String qualifier)
{
return isAuthorityRequired(makeFieldKey(schema, element, qualifier));
}
/** Predicate - is authority value required for field? */
public boolean isAuthorityRequired(String fieldKey)
{
Boolean result = isAuthorityRequired.get(fieldKey);
return (result == null) ? false : result.booleanValue();
}
/**
* Construct a single key from the tuple of schema/element/qualifier
* that describes a metadata field. Punt to the function we use for
* submission UI input forms, for now.
*/
public static String makeFieldKey(String schema, String element, String qualifier)
{
return MetadataField.formKey(schema, element, qualifier);
}
/**
* Give the minimal level of confidence required to consider valid an authority value
* for the given metadata.
* @return the minimal valid level of confidence for the given metadata
*/
public int getMinConfidence(String schema, String element, String qualifier) {
Integer result = minConfidence.get(makeFieldKey(schema, element, qualifier));
return result == null?Choices.CF_ACCEPTED:result.intValue();
}
/**
* Return the list of metadata field with authority control. The strings
* are in the form <code>schema.element[.qualifier]</code>
*
* @return the list of metadata field with authority control
*/
public List<String> getAuthorityMetadata() {
List<String> copy = new ArrayList<String>();
for (String s : controlled.keySet())
{
copy.add(s.replaceAll("_","."));
}
return copy;
}
}

View File

@@ -0,0 +1,115 @@
/*
* SHERPARoMEOJournalTitle.java
*
* Version: $Revision: 3705 $
*
* Date: $Date: 2009-04-11 13:02:24 -0400 (Sat, 11 Apr 2009) $
*
* Copyright (c) 2002-2009, The DSpace Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the DSpace Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
package org.dspace.content.authority;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.FileReader;
import java.io.BufferedReader;
import java.util.Enumeration;
import java.util.List;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.XMLReader;
import org.xml.sax.InputSource;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXParseException;
import org.apache.log4j.Logger;
import org.dspace.core.ConfigurationManager;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.util.EncodingUtil;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.HttpException;
/**
* Sample Journal-name authority based on SHERPA/RoMEO
*
* WARNING: This is a very crude and incomplete implementation, done mainly
* as a proof-of-concept. Any site that actually wants to use it will
* probably have to refine it (and give patches back to dspace.org).
*
* @see SHERPARoMEOProtocol
* @author Larry Stone
* @version $Revision $
*/
public class SHERPARoMEOJournalTitle extends SHERPARoMEOProtocol
{
private static final String RESULT = "journal";
private static final String LABEL = "jtitle";
private static final String AUTHORITY = "issn";
public SHERPARoMEOJournalTitle()
{
super();
}
public Choices getMatches(String text, int collection, int start, int limit, String locale)
{
// punt if there is no query text
if (text == null || text.trim().length() == 0)
return new Choices(true);
// query args to add to SHERPA/RoMEO request URL
NameValuePair args[] = new NameValuePair[2];
args[0] = new NameValuePair("jtitle", text);
args[1] = new NameValuePair("qtype","contains"); // OR: starts, exact
Choices result = query(RESULT, LABEL, AUTHORITY, args, start, limit);
if (result == null)
{
result = new Choices(true);
}
return result;
}
}

View File

@@ -0,0 +1,297 @@
/*
* SHERPARoMEOProtocol.java
*
* Version: $Revision: 3705 $
*
* Date: $Date: 2009-04-11 13:02:24 -0400 (Sat, 11 Apr 2009) $
*
* Copyright (c) 2002-2009, The DSpace Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the DSpace Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
package org.dspace.content.authority;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.FileReader;
import java.io.BufferedReader;
import java.util.Enumeration;
import java.util.List;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.XMLReader;
import org.xml.sax.InputSource;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXParseException;
import org.apache.log4j.Logger;
import org.dspace.core.ConfigurationManager;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.util.EncodingUtil;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.HttpException;
/**
* Choice Authority based on SHERPA/RoMEO - for Publishers and Journals
* See the subclasses SHERPARoMEOPublisher and SHERPARoMEOJournalTitle
* for actual choice plugin implementations. This is a superclass
* containing all the common prototcol logic.
*
* Reads these DSpace Config properties:
*
* # contact URL for server
* sherpa.romeo.url = http://www.sherpa.ac.uk/romeoapi11.php
*
* WARNING: This is a very crude and incomplete implementation, done mainly
* as a proof-of-concept. Any site that actually wants to use it will
* probably have to refine it (and give patches back to dspace.org).
*
* @see SHERPARoMEOPublisher, SHERPARoMEOJournalTitle
* @author Larry Stone
* @version $Revision $
*/
public abstract class SHERPARoMEOProtocol implements ChoiceAuthority
{
private static Logger log = Logger.getLogger(SHERPARoMEOProtocol.class);
// contact URL from configuration
private static String url = null;
public SHERPARoMEOProtocol()
{
if (url == null)
{
url = ConfigurationManager.getProperty("sherpa.romeo.url");
// sanity check
if (url == null)
throw new IllegalStateException("Missing DSpace configuration keys for SHERPA/RoMEO Query");
}
}
// this implements the specific RoMEO API args and XML tag naming
public abstract Choices getMatches(String text, int collection, int start, int limit, String locale);
public Choices getBestMatch(String text, int collection, String locale)
{
return getMatches(text, collection, 0, 2, locale);
}
// XXX FIXME just punt, returning value, never got around to
// implementing a reverse query.
public String getLabel(String key, String locale)
{
return key;
}
// NOTE - ignore limit and start for now
protected Choices query(String result, String label, String authority,
NameValuePair[] args, int start, int limit)
{
HttpClient hc = new HttpClient();
String srUrl = url + "?" + EncodingUtil.formUrlEncode(args, "UTF8");
GetMethod get = new GetMethod(srUrl);
log.debug("Trying SHERPA/RoMEO Query, URL="+srUrl);
try
{
int status = hc.executeMethod(get);
if (status == 200)
{
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();
XMLReader xr = sp.getXMLReader();
SRHandler handler = new SRHandler(result, label, authority);
// XXX FIXME: should turn off validation here explicitly, but
// it seems to be off by default.
xr.setFeature("http://xml.org/sax/features/namespaces", true);
xr.setContentHandler(handler);
xr.setErrorHandler(handler);
xr.parse(new InputSource(get.getResponseBodyAsStream()));
int confidence;
if (handler.total == 0)
confidence = Choices.CF_NOTFOUND;
else if (handler.total == 1)
confidence = Choices.CF_UNCERTAIN;
else
confidence = Choices.CF_AMBIGUOUS;
return new Choices(handler.result, start, handler.total, confidence, false);
}
}
catch (HttpException e)
{
log.error("SHERPA/RoMEO query failed: ", e);
return null;
}
catch (IOException e)
{
log.error("SHERPA/RoMEO query failed: ", e);
return null;
}
catch (ParserConfigurationException e)
{
log.warn("Failed parsing SHERPA/RoMEO result: ", e);
return null;
}
catch (SAXException e)
{
log.warn("Failed parsing SHERPA/RoMEO result: ", e);
return null;
}
finally
{
get.releaseConnection();
}
return null;
}
// SAX handler to grab SHERPA/RoMEO (and eventually other details) from result
private static class SRHandler
extends DefaultHandler
{
private Choice result[] = null;
int rindex = 0; // result index
int total = 0;
// name of element containing a result, e.g. <journal>
private String resultElement = null;
// name of element containing the label e.g. <name>
private String labelElement = null;
// name of element containing the authority value e.g. <issn>
private String authorityElement = null;
protected String textValue = null;
public SRHandler(String result, String label, String authority)
{
super();
resultElement = result;
labelElement = label;
authorityElement = authority;
}
// NOTE: text value MAY be presented in multiple calls, even if
// it all one word, so be ready to splice it together.
// BEWARE: subclass's startElement method should call super()
// to null out 'value'. (Don't you miss the method combination
// options of a real object system like CLOS?)
public void characters(char[] ch, int start, int length)
throws SAXException
{
String newValue = new String(ch, start, length);
if (newValue.length() > 0)
{
if (textValue == null)
textValue = newValue;
else
textValue += newValue;
}
}
// if this was the FIRST "numhits" element, it's size of results:
public void endElement(String namespaceURI, String localName,
String qName)
throws SAXException
{
if (localName.equals("numhits"))
{
String stotal = textValue.trim();
if (stotal.length() > 0)
{
total = Integer.parseInt(stotal);
result = new Choice[total];
if (total > 0)
{
result[0] = new Choice();
log.debug("Got "+total+" records in results.");
}
}
}
// after start of result element, get next hit ready
else if (localName.equals(resultElement))
{
if (++rindex < result.length)
result[rindex] = new Choice();
}
// plug in label value
else if (localName.equals(labelElement) && textValue != null)
result[rindex].value =
result[rindex].label = textValue.trim();
// plug in authority value
else if (authorityElement != null &&
localName.equals(authorityElement) && textValue != null)
result[rindex].authority = textValue.trim();
// error message
else if (localName.equals("message") && textValue != null)
log.warn("SHERPA/RoMEO response error message: "+textValue.trim());
}
// subclass overriding this MUST call it with super()
public void startElement(String namespaceURI, String localName,
String qName, Attributes atts)
throws SAXException
{
textValue = null;
}
public void error(SAXParseException exception)
throws SAXException
{
throw new SAXException(exception);
}
public void fatalError(SAXParseException exception)
throws SAXException
{
throw new SAXException(exception);
}
}
}

View File

@@ -0,0 +1,116 @@
/*
* SHERPARoMEOPublisher.java
*
* Version: $Revision: 3705 $
*
* Date: $Date: 2009-04-11 13:02:24 -0400 (Sat, 11 Apr 2009) $
*
* Copyright (c) 2002-2009, The DSpace Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the DSpace Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
package org.dspace.content.authority;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.FileReader;
import java.io.BufferedReader;
import java.util.Enumeration;
import java.util.List;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.XMLReader;
import org.xml.sax.InputSource;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXParseException;
import org.apache.log4j.Logger;
import org.dspace.core.ConfigurationManager;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.util.EncodingUtil;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.HttpException;
/**
* Sample Publisher name authority based on SHERPA/RoMEO
*
*
* WARNING: This is a very crude and incomplete implementation, done mainly
* as a proof-of-concept. Any site that actually wants to use it will
* probably have to refine it (and give patches back to dspace.org).
*
* @see SHERPARoMEOProtocol
* @author Larry Stone
* @version $Revision $
*/
public class SHERPARoMEOPublisher extends SHERPARoMEOProtocol
{
private static final String RESULT = "publisher";
private static final String LABEL = "name";
// note: the publisher records have nothing we can use as authority code.
private static final String AUTHORITY = null;
public SHERPARoMEOPublisher()
{
super();
}
public Choices getMatches(String text, int collection, int start, int limit, String locale)
{
// punt if there is no query text
if (text == null || text.trim().length() == 0)
return new Choices(true);
// query args to add to SHERPA/RoMEO request URL
NameValuePair args[] = new NameValuePair[2];
args[0] = new NameValuePair("pub", text);
args[1] = new NameValuePair("qtype","all"); // OR: starts, exact
Choices result = query(RESULT, LABEL, AUTHORITY, args, start, limit);
if (result == null)
{
result = new Choices(true);
}
return result;
}
}

View File

@@ -0,0 +1,99 @@
/*
* SampleAuthority.java
*
* Version: $Revision: 3705 $
*
* Date: $Date: 2009-04-11 13:02:24 -0400 (Sat, 11 Apr 2009) $
*
* Copyright (c) 2002-2009, The DSpace Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the DSpace Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
package org.dspace.content.authority;
import java.util.List;
/**
* This is a *very* stupid test fixture for authority control, and also
* serves as a trivial example of an authority plugin implementation.
*/
public class SampleAuthority implements ChoiceAuthority
{
private static String values[] = {
"sun",
"mon",
"tue",
"wed",
"thu",
"fri",
"sat"
};
private static String labels[] = {
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday"
};
public Choices getMatches(String query, int collection, int start, int limit, String locale)
{
int dflt = -1;
Choice v[] = new Choice[values.length];
for (int i = 0; i < values.length; ++i)
{
v[i] = new Choice(String.valueOf(i), values[i], labels[i]);
if (values[i].equalsIgnoreCase(query))
dflt = i;
}
return new Choices(v, 0, v.length, Choices.CF_AMBIGUOUS, false, dflt);
}
public Choices getBestMatch(String text, int collection, String locale)
{
for (int i = 0; i < values.length; ++i)
{
if (text.equalsIgnoreCase(values[i]))
{
Choice v[] = new Choice[1];
v[0] = new Choice(String.valueOf(i), values[i], labels[i]);
return new Choices(v, 0, v.length, Choices.CF_UNCERTAIN, false, 0);
}
}
return new Choices(Choices.CF_NOTFOUND);
}
public String getLabel(String key, String locale)
{
return labels[Integer.parseInt(key)];
}
}

View File

@@ -49,6 +49,7 @@ import org.dspace.authorize.AuthorizeException;
import org.dspace.content.DCValue;
import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
import org.dspace.content.authority.Choices;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.Constants;
import org.jdom.Document;
@@ -252,6 +253,11 @@ public class XSLTDisseminationCrosswalk
field.setAttribute("lang", dc[i].language);
if (dc[i].value != null)
field.setText(dc[i].value);
if (dc[i].authority != null)
{
field.setAttribute("authority", dc[i].authority);
field.setAttribute("confidence", Choices.getConfidenceText(dc[i].confidence));
}
dim.addContent(field);
}
return dim;

View File

@@ -50,6 +50,8 @@ import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
import org.dspace.content.MetadataField;
import org.dspace.content.MetadataSchema;
import org.dspace.content.MetadataValue;
import org.dspace.content.authority.Choices;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.core.PluginManager;
@@ -116,9 +118,21 @@ public class XSLTIngestionCrosswalk
String element = field.getAttributeValue("element");
String qualifier = field.getAttributeValue("qualifier");
String lang = field.getAttributeValue("lang");
String authority = field.getAttributeValue("authority");
String sconf = field.getAttributeValue("confidence");
if ((authority != null && authority.length() > 0) ||
(sconf != null && sconf.length() > 0))
{
int confidence = (sconf != null && sconf.length() > 0) ?
Choices.getConfidenceValue(sconf) : Choices.CF_UNSET;
item.addMetadata(schema, element, qualifier, lang, field.getText(), authority, confidence);
}
else
{
item.addMetadata(schema, element, qualifier, lang, field.getText());
}
}
/**
* Translate metadata with XSL stylesheet and ingest it.

View File

@@ -55,6 +55,7 @@ import java.util.Vector;
import java.text.SimpleDateFormat;
import java.text.ParseException;
import java.util.List;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.OptionBuilder;
@@ -79,6 +80,8 @@ import org.dspace.content.DCValue;
import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
import org.dspace.content.ItemIterator;
import org.dspace.content.authority.ChoiceAuthorityManager;
import org.dspace.content.authority.MetadataAuthorityManager;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.Constants;
import org.dspace.core.Context;
@@ -998,6 +1001,46 @@ public class DSIndexer
}
}
else
{
List<String> variants = null;
if (mydc[j].authority != null && mydc[j].confidence >= MetadataAuthorityManager.getManager()
.getMinConfidence(mydc[j].schema, mydc[j].element, mydc[j].qualifier))
{
variants = ChoiceAuthorityManager.getManager()
.getVariants(mydc[j].schema, mydc[j].element, mydc[j].qualifier,
mydc[j].authority, mydc[j].language);
doc.add( new Field(indexConfigArr[i].indexName+"_authority",
mydc[j].authority,
Field.Store.NO,
Field.Index.UN_TOKENIZED));
boolean valueAlreadyIndexed = false;
if (variants != null)
{
for (String var : variants)
{
// TODO: use a delegate to allow custom 'types' to be used to reformat the field
doc.add( new Field(indexConfigArr[i].indexName,
var,
Field.Store.NO,
Field.Index.TOKENIZED));
if (var.equals(mydc[j].value))
{
valueAlreadyIndexed = true;
}
else
{ // add to default index too...
// (only variants, main value is already take)
doc.add( new Field("default",
var,
Field.Store.NO,
Field.Index.TOKENIZED));
}
}
}
if (!valueAlreadyIndexed)
{
// TODO: use a delegate to allow custom 'types' to be used to reformat the field
doc.add( new Field(indexConfigArr[i].indexName,
@@ -1005,6 +1048,16 @@ public class DSIndexer
Field.Store.NO,
Field.Index.TOKENIZED));
}
}
else
{
// TODO: use a delegate to allow custom 'types' to be used to reformat the field
doc.add( new Field(indexConfigArr[i].indexName,
mydc[j].value,
Field.Store.NO,
Field.Index.TOKENIZED));
}
}
doc.add( new Field("default", mydc[j].value, Field.Store.NO, Field.Index.TOKENIZED));
}

View File

@@ -49,6 +49,7 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.dspace.app.util.DCInputsReader;
import org.dspace.app.util.DCInputsReaderException;
import org.dspace.app.util.DCInput;
import org.dspace.app.util.SubmissionInfo;
import org.dspace.app.util.Util;
@@ -60,6 +61,9 @@ import org.dspace.content.DCSeriesNumber;
import org.dspace.content.DCValue;
import org.dspace.content.Item;
import org.dspace.content.MetadataField;
import org.dspace.content.authority.MetadataAuthorityManager;
import org.dspace.content.authority.ChoiceAuthorityManager;
import org.dspace.content.authority.Choices;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.Context;
import org.dspace.submit.AbstractProcessingStep;
@@ -87,7 +91,7 @@ public class DescribeStep extends AbstractProcessingStep
private static Logger log = Logger.getLogger(DescribeStep.class);
/** hash of all submission forms details */
private static DCInputsReader inputsReader;
private static DCInputsReader inputsReader = null;
/***************************************************************************
* STATUS / ERROR FLAGS (returned by doProcessing() if an error occurs or
@@ -151,10 +155,18 @@ public class DescribeStep extends AbstractProcessingStep
// lookup applicable inputs
Collection c = subInfo.getSubmissionItem().getCollection();
DCInput[] inputs = inputsReader.getInputs(c.getHandle()).getPageRows(
DCInput[] inputs = null;
try
{
inputs = inputsReader.getInputs(c.getHandle()).getPageRows(
currentPage - 1,
subInfo.getSubmissionItem().hasMultipleTitles(),
subInfo.getSubmissionItem().isPublishedBefore());
}
catch (DCInputsReaderException e)
{
throw new ServletException(e);
}
// Step 1:
// clear out all item metadata defined on this page
@@ -176,6 +188,10 @@ public class DescribeStep extends AbstractProcessingStep
qualifier, Item.ANY);
}
// Clear required-field errors first since missing authority
// values can add them too.
clearErrorFields(request);
// Step 2:
// now update the item metadata.
String fieldName;
@@ -200,6 +216,8 @@ public class DescribeStep extends AbstractProcessingStep
fieldName = schema + "_" + element;
}
String fieldKey = MetadataAuthorityManager.makeFieldKey(schema, element, qualifier);
ChoiceAuthorityManager cmgr = ChoiceAuthorityManager.getManager();
String inputType = inputs[j].getInputType();
if (inputType.equals("name"))
{
@@ -210,6 +228,25 @@ public class DescribeStep extends AbstractProcessingStep
{
readDate(request, item, schema, element, qualifier);
}
// choice-controlled input with "select" presentation type is
// always rendered as a dropdown menu
else if (inputType.equals("dropdown") || inputType.equals("list") ||
(cmgr.isChoicesConfigured(fieldKey) &&
"select".equals(cmgr.getPresentation(fieldKey))))
{
String[] vals = request.getParameterValues(fieldName);
if (vals != null)
{
for (int z = 0; z < vals.length; z++)
{
if (!vals[z].equals(""))
{
item.addMetadata(schema, element, qualifier, LANGUAGE_QUALIFIER,
vals[z]);
}
}
}
}
else if (inputType.equals("series"))
{
readSeriesNumbers(request, item, schema, element, qualifier,
@@ -238,21 +275,6 @@ public class DescribeStep extends AbstractProcessingStep
}
}
}
else if (inputType.equals("dropdown") || inputType.equals("list"))
{
String[] vals = request.getParameterValues(fieldName);
if (vals != null)
{
for (int z = 0; z < vals.length; z++)
{
if (!vals[z].equals(""))
{
item.addMetadata(schema, element, qualifier, LANGUAGE_QUALIFIER,
vals[z]);
}
}
}
}
else if ((inputType.equals("onebox"))
|| (inputType.equals("twobox"))
|| (inputType.equals("textarea")))
@@ -289,7 +311,6 @@ public class DescribeStep extends AbstractProcessingStep
|| buttonPressed.equals(PREVIOUS_BUTTON)
|| buttonPressed.equals(CANCEL_BUTTON))
{
clearErrorFields(request);
for (int i = 0; i < inputs.length; i++)
{
DCValue[] values = item.getMetadata(inputs[i].getSchema(),
@@ -352,12 +373,6 @@ public class DescribeStep extends AbstractProcessingStep
public int getNumberOfPages(HttpServletRequest request,
SubmissionInfo subInfo) throws ServletException
{
if (inputsReader == null)
{
// read configurable submissions forms data
inputsReader = new DCInputsReader();
}
// by default, use the "default" collection handle
String collectionHandle = DCInputsReader.DEFAULT_COLLECTION;
@@ -368,7 +383,14 @@ public class DescribeStep extends AbstractProcessingStep
}
// get number of input pages (i.e. "Describe" pages)
return inputsReader.getNumberInputPages(collectionHandle);
try
{
return getInputsReader().getNumberInputPages(collectionHandle);
}
catch (DCInputsReaderException e)
{
throw new ServletException(e);
}
}
/**
@@ -381,8 +403,15 @@ public class DescribeStep extends AbstractProcessingStep
if (inputsReader == null)
{
// read configurable submissions forms data
try
{
inputsReader = new DCInputsReader();
}
catch (DCInputsReaderException e)
{
throw new ServletException(e);
}
}
return inputsReader;
}
@@ -393,8 +422,15 @@ public class DescribeStep extends AbstractProcessingStep
* @return the current DCInputsReader
*/
public static DCInputsReader getInputsReader(String filename) throws ServletException
{
try
{
inputsReader = new DCInputsReader(filename);
}
catch (DCInputsReaderException e)
{
throw new ServletException(e);
}
return inputsReader;
}
@@ -465,9 +501,14 @@ public class DescribeStep extends AbstractProcessingStep
String metadataField = MetadataField
.formKey(schema, element, qualifier);
String fieldKey = MetadataAuthorityManager.makeFieldKey(schema, element, qualifier);
boolean isAuthorityControlled = MetadataAuthorityManager.getManager().isAuthorityControlled(fieldKey);
// Names to add
List firsts = new LinkedList();
List lasts = new LinkedList();
List auths = new LinkedList();
List confs = new LinkedList();
if (repeated)
{
@@ -475,6 +516,10 @@ public class DescribeStep extends AbstractProcessingStep
+ "_first");
lasts = getRepeatedParameter(request, metadataField, metadataField
+ "_last");
auths = getRepeatedParameter(request, metadataField, metadataField
+ "_authority");
confs = getRepeatedParameter(request, metadataField, metadataField
+ "_confidence");
// Find out if the relevant "remove" button was pressed
// TODO: These separate remove buttons are only relevant
@@ -490,6 +535,8 @@ public class DescribeStep extends AbstractProcessingStep
firsts.remove(valToRemove);
lasts.remove(valToRemove);
auths.remove(valToRemove);
confs.remove(valToRemove);
}
}
else
@@ -497,11 +544,15 @@ public class DescribeStep extends AbstractProcessingStep
// Just a single name
String lastName = request.getParameter(metadataField + "_last");
String firstNames = request.getParameter(metadataField + "_first");
String authority = request.getParameter(metadataField + "_authority");
String confidence = request.getParameter(metadataField + "_confidence");
if (lastName != null)
lasts.add(lastName);
if (firstNames != null)
firsts.add(firstNames);
auths.add(authority == null ? "" : authority);
confs.add(confidence == null ? "" : confidence);
}
// Remove existing values, already done in doProcessing see also bug DS-203
@@ -539,7 +590,24 @@ public class DescribeStep extends AbstractProcessingStep
}
}
// Add to the database
// Add to the database -- unless required authority is missing
if (isAuthorityControlled)
{
String authKey = auths.size() > i ? (String)auths.get(i) : null;
String sconf = (authKey != null && confs.size() > i) ? (String)confs.get(i) : null;
if (MetadataAuthorityManager.getManager().isAuthorityRequired(fieldKey) &&
(authKey == null || authKey.length() == 0))
{
log.warn("Skipping value of "+metadataField+" because the required Authority key is missing or empty.");
addErrorField(request, metadataField);
}
else
item.addMetadata(schema, element, qualifier, null,
new DCPersonName(l, f).toString(), authKey,
(sconf != null && sconf.length() > 0) ?
Choices.getConfidenceValue(sconf) : Choices.CF_ACCEPTED);
}
else
item.addMetadata(schema, element, qualifier, null,
new DCPersonName(l, f).toString());
}
@@ -586,12 +654,22 @@ public class DescribeStep extends AbstractProcessingStep
String metadataField = MetadataField
.formKey(schema, element, qualifier);
String fieldKey = MetadataAuthorityManager.makeFieldKey(schema, element, qualifier);
boolean isAuthorityControlled = MetadataAuthorityManager.getManager().isAuthorityControlled(fieldKey);
// Values to add
List vals = new LinkedList();
List vals = null;
List auths = null;
List confs = null;
if (repeated)
{
vals = getRepeatedParameter(request, metadataField, metadataField);
if (isAuthorityControlled)
{
auths = getRepeatedParameter(request, metadataField, metadataField+"_authority");
confs = getRepeatedParameter(request, metadataField, metadataField+"_confidence");
}
// Find out if the relevant "remove" button was pressed
// TODO: These separate remove buttons are only relevant
@@ -611,10 +689,19 @@ public class DescribeStep extends AbstractProcessingStep
else
{
// Just a single name
vals = new LinkedList();
String value = request.getParameter(metadataField);
if (value != null)
vals.add(value.trim());
if (isAuthorityControlled)
{
auths = new LinkedList();
confs = new LinkedList();
String av = request.getParameter(metadataField+"_authority");
String cv = request.getParameter(metadataField+"_confidence");
auths.add(av == null ? "":av.trim());
confs.add(cv == null ? "":cv.trim());
}
}
// Remove existing values, already done in doProcessing see also bug DS-203
@@ -625,9 +712,24 @@ public class DescribeStep extends AbstractProcessingStep
{
// Add to the database if non-empty
String s = (String) vals.get(i);
if ((s != null) && !s.equals(""))
{
if (isAuthorityControlled)
{
String authKey = auths.size() > i ? (String)auths.get(i) : null;
String sconf = (authKey != null && confs.size() > i) ? (String)confs.get(i) : null;
if (MetadataAuthorityManager.getManager().isAuthorityRequired(fieldKey) &&
(authKey == null || authKey.length() == 0))
{
log.warn("Skipping value of "+metadataField+" because the required Authority key is missing or empty.");
addErrorField(request, metadataField);
}
else
item.addMetadata(schema, element, qualifier, lang, s,
authKey, (sconf != null && sconf.length() > 0) ?
Choices.getConfidenceValue(sconf) : Choices.CF_ACCEPTED);
}
else
item.addMetadata(schema, element, qualifier, lang, s);
}
}
@@ -806,9 +908,6 @@ public class DescribeStep extends AbstractProcessingStep
int i = 1; //start index at the first of the previously entered values
boolean foundLast = false;
log.debug("getRepeatedParameter: metadataField=" + metadataField
+ " param=" + metadataField);
// Iterate through the values in the form.
while (!foundLast)
{
@@ -857,6 +956,9 @@ public class DescribeStep extends AbstractProcessingStep
i++;
}
log.debug("getRepeatedParameter: metadataField=" + metadataField
+ " param=" + metadataField + ", return count = "+vals.size());
return vals;
}

View File

@@ -1123,6 +1123,7 @@ jsp.tools.edit-item-form.reinstate.button = Reinstate
jsp.tools.edit-item-form.replacecc.button = Replace Creative Commons License
jsp.tools.edit-item-form.title = Edit Item
jsp.tools.edit-item-form.withdraw-w-confirm.button = Withdraw...
jsp.tools.edit-item-form.unlock = Unlock the authority key value for manual editing, or toggle it locked again
jsp.tools.eperson-list.close.button = Close
jsp.tools.eperson-list.heading = E-people {0}-{1} of {2}
jsp.tools.eperson-list.info1 = Clicking on the 'Add' button next to an e-person will add that e-person to the list on the main form.
@@ -1394,3 +1395,76 @@ search.sort-by.title
search.sort-by.dateissued = Issue Date
search.sort-by.dateaccessioned = Submit Date
search.update = Update
jsp.layout.navbar-admin.authority = Authority control<br/> management
#org.dspace.app.webui.AuthorityManagementServlet
org.dspace.app.webui.AuthorityManagementServlet.submit_reject = The selected potential matches has been rejected!
org.dspace.app.webui.AuthorityManagementServlet.submit_accept = The selected potential matches has been confirmed!
#dspace-admin/auhtority.jsp
jsp.dspace-admin.authority = Authority management
jsp.dspace-admin.authority-heading = Statistics about the authority for the metadata {0}
jsp.dspace-admin.authority-statistics.label = Stat
jsp.dspace-admin.authority-statistics.value = # of ...
jsp.dspace-admin.authority-statistics.numTotMetadata = # of metadata
jsp.dspace-admin.authority-statistics.numTotMetadata-level = # of metadata grouped by confidence
jsp.dspace-admin.authority-statistics.numAuthorityKey = # of in-use authority keys
jsp.dspace-admin.authority-statistics.numAuthorityIssued = # of authority keys pending approval
jsp.dspace-admin.authority-statistics.numItems = # of items with authority key
jsp.dspace-admin.authority-statistics.numIssuedItems = # of issued items
jsp.common.authority-level0 = No Value
jsp.common.authority-level1 = Rejected
jsp.common.authority-level2 = Failed
jsp.common.authority-level3 = Not Found
jsp.common.authority-level4 = Ambiguous
jsp.common.authority-level5 = Uncertain
jsp.common.authority-level6 = Accepted
jsp.dspace-admin.authority-statistics.numTotMetadata-value = #
#dspace-admin/auhtority-issued.jsp
jsp.dspace-admin.authority-issued = List of authority key pending approval for the metadata: {0}
#dspace-admin/auhtority-key.jsp
jsp.dspace-admin.authority-key.title = Issued item of the authority key {0}
jsp.dspace-admin.authority-key.heading = Issued item of the authority key {0}
jsp.dspace-admin.authority-key.items-heading = List of items pending approval
jsp.dspace-admin.authority-key.info-heading = Information about the authority
jsp.dspace-admin.authority-key.label = Label
jsp.dspace-admin.authority-key.key = Authority key
jsp.dspace-admin.authority-key.variants = Variants
jsp.dspace-admin.authority-key.accept = Accept
jsp.dspace-admin.authority-key.reject = Reject
jsp.dspace-admin.authority-key.previous = Previous
jsp.dspace-admin.authority-key.list = Return to the list
jsp.dspace-admin.authority-key.next = Next
# authority-control confidence levels, descriptions:
jsp.authority.confidence.description.unset = Confidence was never recorded for this value
jsp.authority.confidence.description.novalue = No reasonable confidence value was returned from the authority
jsp.authority.confidence.description.rejected = The authority recommends this submission be rejected
jsp.authority.confidence.description.failed = The authority encountered an internal failure
jsp.authority.confidence.description.notfound = There are no matching answers in the authority
jsp.authority.confidence.description.ambiguous = There are multiple matching authority values of equal validity
jsp.authority.confidence.description.uncertain = Value is singular and valid but has not been seen and accepted by a human so it is still uncertain
jsp.authority.confidence.description.accepted = This authority value has been confirmed as accurate by an interactive user
jsp.tools.lookup.title = DSpace Value Lookup
jsp.tools.lookup.heading = Looking Up Value
jsp.tools.lookup.accept = Accept
jsp.tools.lookup.add = Add
jsp.tools.lookup.cancel = Cancel
jsp.tools.lookup.more = See More Results
jsp.tools.lookup.fail = Failed to load choice data:
jsp.tools.lookup.results = Results @1@ to @2@ of @3@ for "@4@"
jsp.tools.lookup.lookup = Lookup this value
# choice lookup example for dc.publisher
jsp.tools.lookup.field.dc_publisher.help = Name of Publisher
jsp.tools.lookup.field.dc_publisher.title = Look up Publisher
jsp.tools.lookup.field.dc_publisher.nonauthority = Non-authority value: @1@
# choice lookup example for dc.contributor.author
jsp.tools.lookup.field.dc_contributor_author.help = Name in "Last, First" format
jsp.tools.lookup.field.dc_contributor_author.help.last = Last name, e.g. "Smith"
jsp.tools.lookup.field.dc_contributor_author.help.first = First name(s) e.g. "Fred"
jsp.tools.lookup.field.dc_contributor_author.title = LC Name Authority author lookup
jsp.tools.lookup.field.dc_contributor_author.nonauthority = Local value '@1@' (not in Naming Authority)

View File

@@ -66,8 +66,10 @@ import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.sql.SQLException;
import java.util.StringTokenizer;
import org.dspace.content.authority.MetadataAuthorityManager;
/**
* Tag for display a list of items
@@ -532,19 +534,36 @@ public class BrowseListTag extends TagSupport
String endLink = "";
if (!StringUtils.isEmpty(browseType[colIdx]) && !disableCrossLinks)
{
String argument = "value";
String argument;
String value;
if (metadataArray[j].authority != null &&
metadataArray[j].confidence >= MetadataAuthorityManager.getManager()
.getMinConfidence(metadataArray[j].schema, metadataArray[j].element, metadataArray[j].qualifier))
{
argument = "authority";
value = metadataArray[j].authority;
}
else
{
argument = "value";
value = metadataArray[j].value;
}
if (viewFull[colIdx])
{
argument = "vfocus";
}
startLink = "<a href=\"" + hrq.getContextPath() + "/browse?type=" + browseType[colIdx] + "&amp;" +
argument + "=" + Utils.addEntities(metadataArray[j].value);
argument + "=" + URLEncoder.encode(value,"UTF-8");
if (metadataArray[j].language != null)
{
startLink = startLink + "&amp;" +
argument + "_lang=" + Utils.addEntities(metadataArray[j].language) +
"\">";
argument + "_lang=" + URLEncoder.encode(metadataArray[j].language, "UTF-8");
}
if ("authority".equals(argument))
{
startLink += "\" class=\"authority " +browseType[colIdx] + "\">";
}
else
{

View File

@@ -70,6 +70,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.sql.SQLException;
import java.util.StringTokenizer;
@@ -80,6 +81,7 @@ import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.jstl.fmt.LocaleSupport;
import javax.servlet.jsp.tagext.TagSupport;
import org.dspace.content.authority.MetadataAuthorityManager;
/**
* Tag for display a list of items
@@ -501,19 +503,36 @@ public class ItemListTag extends TagSupport
String endLink = "";
if (!StringUtils.isEmpty(browseType[colIdx]) && !disableCrossLinks)
{
String argument = "value";
String argument;
String value;
if (metadataArray[j].authority != null &&
metadataArray[j].confidence >= MetadataAuthorityManager.getManager()
.getMinConfidence(metadataArray[j].schema, metadataArray[j].element, metadataArray[j].qualifier))
{
argument = "authority";
value = metadataArray[j].authority;
}
else
{
argument = "value";
value = metadataArray[j].value;
}
if (viewFull[colIdx])
{
argument = "vfocus";
}
startLink = "<a href=\"" + hrq.getContextPath() + "/browse?type=" + browseType[colIdx] + "&amp;" +
argument + "=" + Utils.addEntities(metadataArray[j].value);
argument + "=" + URLEncoder.encode(value,"UTF-8");
if (metadataArray[j].language != null)
{
startLink = startLink + "&amp;" +
argument + "_lang=" + Utils.addEntities(metadataArray[j].language) +
"\">";
argument + "_lang=" + URLEncoder.encode(metadataArray[j].language, "UTF-8");
}
if ("authority".equals(argument))
{
startLink += "\" class=\"authority " +browseType[colIdx] + "\">";
}
else
{

View File

@@ -65,6 +65,7 @@ import org.dspace.content.Collection;
import org.dspace.content.DCDate;
import org.dspace.content.DCValue;
import org.dspace.content.Item;
import org.dspace.content.authority.MetadataAuthorityManager;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.Constants;
import org.dspace.core.I18nUtil;
@@ -547,8 +548,22 @@ public class ItemTag extends TagSupport
}
else if (browseIndex != null)
{
out.print("<a href=\"" + request.getContextPath() + "/browse?type=" + browseIndex + "&amp;value="
+ URLEncoder.encode(values[j].value, "UTF-8") + "\">" + Utils.addEntities(values[j].value)
String argument, value;
if ( values[j].authority != null &&
values[j].confidence >= MetadataAuthorityManager.getManager()
.getMinConfidence( values[j].schema, values[j].element, values[j].qualifier))
{
argument = "authority";
value = values[j].authority;
}
else
{
argument = "value";
value = values[j].value;
}
out.print("<a class=\"" + ("authority".equals(argument)?"authority ":"") + browseIndex + "\""
+ "href=\"" + request.getContextPath() + "/browse?type=" + browseIndex + "&amp;" + argument + "="
+ URLEncoder.encode(value, "UTF-8") + "\">" + Utils.addEntities(values[j].value)
+ "</a>");
}
else

View File

@@ -120,6 +120,7 @@ public abstract class AbstractBrowserServlet extends DSpaceServlet
String startsWith = request.getParameter("starts_with");
String valueFocus = request.getParameter("vfocus");
String valueFocusLang = request.getParameter("vfocus_lang");
String authority = request.getParameter("authority");
int focus = UIUtil.getIntParameter(request, "focus");
int offset = UIUtil.getIntParameter(request, "offset");
int resultsperpage = UIUtil.getIntParameter(request, "rpp");
@@ -229,7 +230,7 @@ public abstract class AbstractBrowserServlet extends DSpaceServlet
// determine which level of the browse we are at: 0 for top, 1 for second
int level = 0;
if (value != null)
if (value != null || authority != null)
{
level = 1;
}
@@ -281,7 +282,7 @@ public abstract class AbstractBrowserServlet extends DSpaceServlet
BrowserScope scope = new BrowserScope(context);
scope.setBrowseIndex(bi);
scope.setOrder(order);
scope.setFilterValue(value);
scope.setFilterValue(value != null?value:authority);
scope.setFilterValueLang(valueLang);
scope.setJumpToItem(focus);
scope.setJumpToValue(valueFocus);
@@ -292,6 +293,7 @@ public abstract class AbstractBrowserServlet extends DSpaceServlet
scope.setSortBy(sortBy);
scope.setBrowseLevel(level);
scope.setEtAl(etAl);
scope.setAuthorityValue(authority);
// assign the scope of either Community or Collection if necessary
if (community != null)

View File

@@ -0,0 +1,105 @@
/*
*
*/
package org.dspace.app.webui.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.Properties;
import java.sql.SQLException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.xml.sax.SAXException;
import org.apache.commons.digester.plugins.PluginAssertionFailure;
import org.dspace.app.webui.util.UIUtil;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.authority.Choice;
import org.dspace.content.authority.ChoiceAuthorityManager;
import org.dspace.content.authority.Choices;
import org.dspace.content.authority.MetadataAuthorityManager;
import org.dspace.content.authority.ChoicesXMLGenerator;
import org.dspace.core.Context;
import org.apache.xml.serializer.SerializerFactory;
import org.apache.xml.serializer.Serializer;
import org.apache.xml.serializer.OutputPropertiesFactory;
import org.apache.xml.serializer.Method;
/**
*
* @author bollini
*/
public class AuthorityChooseServlet extends DSpaceServlet {
@Override
protected void doDSGet(Context context, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, SQLException, AuthorizeException {
process(context, request, response);
}
@Override
protected void doDSPost(Context context, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, SQLException, AuthorizeException {
process(context, request, response);
}
/**
* Generate the AJAX response Document.
*
* Looks for request parameters:
* field - MD field key, i.e. form key, REQUIRED - derivated from url.
* query - string to match
* collection - db ID of Collection ot serve as context
* start - index to start from, default 0.
* limit - max number of lines, default 1000.
* format - opt. result XML/XHTML format: "select", "ul", "xml"(default)
* locale - explicit locale, pass to choice plugin
*/
private void process(Context context, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, SQLException, AuthorizeException {
String[] paths = request.getPathInfo().split("/");
String field = paths[paths.length-1];
ChoiceAuthorityManager cam = ChoiceAuthorityManager.getManager();
String query = request.getParameter("query");
String format = request.getParameter("format");
int collection = UIUtil.getIntParameter(request, "collection");
int start = UIUtil.getIntParameter(request, "start");
int limit = UIUtil.getIntParameter(request, "limit");
Choices result = cam.getMatches(field, query, collection, start, limit, null);
// Choice[] testValues = {
// new Choice("rp0001", "VALUE1","TEST LABEL1"),
// new Choice("rp0002", "VALUE2","TEST LABEL2"),
// new Choice("rp0003", "VALUE3","TEST LABEL3"),
// new Choice("rp0004", "VALUE COGN, LABEL1","TEST COGN, LABEL1"),
// new Choice("rp0005", "VALUE COGN, LABEL2","TEST COGN, LABEL2"),
// new Choice("rp0006", "VALUE COGN, LABEL3","TEST COGN, LABEL3")
// };
//
// Choices result = new Choices(testValues,start,testValues.length,Choices.CF_ACCEPTED,false);
Writer writer = response.getWriter();
// borrow xalan's serializer to let us use SAX choice menu generator
Properties props =
OutputPropertiesFactory.getDefaultMethodProperties(Method.XML);
Serializer ser = SerializerFactory.getSerializer(props);
ser.setWriter(writer);
try
{
ChoicesXMLGenerator.generate(result, format, ser.asContentHandler());
}
catch(SAXException e)
{
throw new IOException(e.toString());
}
finally
{
ser.reset();
}
writer.flush();
}
}

View File

@@ -76,6 +76,7 @@ import org.dspace.content.FormatIdentifier;
import org.dspace.content.Item;
import org.dspace.content.MetadataField;
import org.dspace.content.MetadataSchema;
import org.dspace.content.authority.Choices;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.core.LogManager;
@@ -605,16 +606,33 @@ public class EditItemServlet extends DSpaceServlet
language = null;
}
// Get the authority key if any
String authority = request.getParameter("choice_" + key + "_authority_"
+ sequenceNumber);
// Empty string authority = null
if ((authority != null) && authority.equals(""))
{
authority = null;
}
// Get the authority confidence value, passed as symbolic name
String sconfidence = request.getParameter("choice_" + key + "_confidence_" + sequenceNumber);
int confidence = (sconfidence == null || sconfidence.equals("")) ?
Choices.CF_NOVALUE : Choices.getConfidenceValue(sconfidence);
// Get the value
String value = request.getParameter(p).trim();
// If remove button pressed for this value, we don't add it
// back to the item. We also don't add empty values.
if (!(value.equals("") || button.equals("submit_remove_" + key
// back to the item. We also don't add empty values
// (if no authority is specified).
if (!((value.equals("") && authority == null) || button.equals("submit_remove_" + key
+ "_" + sequenceNumber)))
{
// Value is empty, or remove button for this wasn't pressed
item.addMetadata(schema, element, qualifier, language, value);
item.addMetadata(schema, element, qualifier, language, value,
authority, confidence);
}
}
else if (p.startsWith("bitstream_name"))

View File

@@ -50,6 +50,8 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.dspace.app.util.DCInputsReader;
import org.dspace.app.util.DCInputsReaderException;
import org.dspace.app.util.SubmissionInfo;
import org.dspace.app.webui.submit.JSPStep;
import org.dspace.app.webui.submit.JSPStepManager;
@@ -238,8 +240,16 @@ public class JSPDescribeStep extends JSPStep
Collection c = subInfo.getSubmissionItem().getCollection();
// requires configurable form info per collection
try
{
request.setAttribute("submission.inputs", DescribeStep.getInputsReader(formFileName).getInputs(c
.getHandle()));
}
catch (DCInputsReaderException e)
{
throw new ServletException(e);
}
// forward to edit-metadata JSP
JSPStepManager.showJSP(request, response, subInfo, DISPLAY_JSP);

View File

@@ -49,6 +49,7 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.dspace.app.util.DCInputsReader;
import org.dspace.app.util.DCInputsReaderException;
import org.dspace.app.util.SubmissionInfo;
import org.dspace.app.webui.submit.JSPStep;
import org.dspace.app.webui.submit.JSPStepManager;
@@ -233,12 +234,19 @@ public class JSPInitialQuestionsStep extends JSPStep
// determine collection
Collection c = subInfo.getSubmissionItem().getCollection();
try
{
// read configurable submissions forms data
DCInputsReader inputsReader = new DCInputsReader();
// load the proper submission inputs to be used by the JSP
request.setAttribute("submission.inputs", inputsReader.getInputs(c
.getHandle()));
}
catch (DCInputsReaderException e)
{
throw new ServletException(e);
}
// forward to initial questions JSP
JSPStepManager.showJSP(request, response, subInfo, INITIAL_QUESTIONS_JSP);

View File

@@ -53,6 +53,7 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.dspace.app.util.DCInputsReader;
import org.dspace.app.util.DCInputsReaderException;
import org.dspace.app.util.Util;
import org.dspace.app.webui.submit.JSPStep;
import org.dspace.app.webui.submit.JSPStepManager;
@@ -161,10 +162,17 @@ public class JSPUploadStep extends JSPStep
if (subInfo != null)
{
Collection c = subInfo.getSubmissionItem().getCollection();
try
{
DCInputsReader inputsReader = new DCInputsReader();
request.setAttribute("submission.inputs", inputsReader.getInputs(c
.getHandle()));
}
catch (DCInputsReaderException e)
{
throw new ServletException(e);
}
}
// show whichever upload page is appropriate
// (based on if this item already has files or not)
@@ -253,12 +261,20 @@ public class JSPUploadStep extends JSPStep
{
// We need to show the file upload error page
if (subInfo != null)
{
try
{
Collection c = subInfo.getSubmissionItem().getCollection();
DCInputsReader inputsReader = new DCInputsReader();
request.setAttribute("submission.inputs", inputsReader
.getInputs(c.getHandle()));
}
catch (DCInputsReaderException e)
{
throw new ServletException(e);
}
}
JSPStepManager.showJSP(request, response, subInfo, UPLOAD_ERROR_JSP);
}
}

View File

@@ -135,6 +135,11 @@
<groupId>org.dspace</groupId>
<artifactId>dspace-jspui-api</artifactId>
</dependency>
<dependency>
<groupId>org.dspace</groupId>
<artifactId>dspace-ui-shared</artifactId>
<type>war</type>
</dependency>
</dependencies>
</project>

View File

@@ -449,6 +449,10 @@
<servlet-class>org.dspace.app.webui.servlet.ControlledVocabularySearchServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>AuthorityChooseServlet</servlet-name>
<servlet-class>org.dspace.app.webui.servlet.AuthorityChooseServlet</servlet-class>
</servlet>
<!-- shibbolized dspace -->
<servlet>
@@ -724,6 +728,10 @@
<url-pattern>/subject-search</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>AuthorityChooseServlet</servlet-name>
<url-pattern>/choices/*</url-pattern>
</servlet-mapping>
<!-- Icon MIME type -->
<mime-mapping>

View File

@@ -331,14 +331,14 @@
<%
// Row: toggles between Odd and Even
String row = "odd";
String[] results = bi.getStringResults();
String[][] results = bi.getStringResults();
for (int i = 0; i < results.length; i++)
{
%>
<tr>
<td class="<%= row %>RowOddCol">
<a href="<%= sharedLink %>&amp;value=<%= URLEncoder.encode(results[i], "UTF-8") %>"><%= Utils.addEntities(results[i]) %></a>
<a href="<%= sharedLink %><% if (results[i][1] != null) { %>&amp;authority=<%= URLEncoder.encode(results[i][1], "UTF-8") %>" class="authority <%= bix.getName() %>"><%= Utils.addEntities(results[i][0]) %></a> <% } else { %>&amp;value=<%= URLEncoder.encode(results[i][0], "UTF-8") %>"><%= Utils.addEntities(results[i][0]) %></a> <% } %>
</td>
</tr>
<%

Binary file not shown.

After

Width:  |  Height:  |  Size: 779 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 774 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@@ -0,0 +1,28 @@
The following icon files:
- book_key.png
- zoom.png
- bug.png
are taken from
Silk icon set 1.3
_________________________________________
Mark James
http://www.famfamfam.com/lab/icons/silk/
_________________________________________
This work is licensed under a
Creative Commons Attribution 2.5 License.
[ http://creativecommons.org/licenses/by/2.5/ ]
This means you may use it for any purpose,
and make any changes you like.
All I ask is that you include a link back
to this page in your credits.
Are you using this icon set? Send me an email
(including a link or picture if available) to
mjames@gmail.com
Any other questions about this icon set please
contact mjames@gmail.com

Binary file not shown.

After

Width:  |  Height:  |  Size: 692 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 645 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 587 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 320 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 595 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 626 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 546 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 599 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 537 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 579 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 628 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 558 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 588 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 599 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 B

View File

@@ -0,0 +1,46 @@
16x16 Free Application Icons
This icon set is free for use in personal and commercial projects.
License Agreement
By purchasing icons from Aha-Soft, You (the purchaser)
agree to the terms of this agreement, as detailed below.
You may use the icons from Aha-Soft in commercial and
personal design projects, software or Internet products.
Icons can be displayed in documentation, help files, and
advertising materials. You are free to sell and distribute
products and projects using purchased icons without further
royalty fees.
All icon files are provided 'as is'. Aha-Soft cannot be
held liable for any negative issues that may occur as a
result of using the icons.
You agree that all ownership and copyright of the icons
remains the property of Aha-Soft. You may not resell,
distribute, lease, license or sub-license the icons or
modified icons (or a subset of the icons), to any third
party unless they are incorporated into your software or
design products.
If you have any questions regarding copyright or licensing,
including whether another license is required for icon use
within products, please contact us here: www.aha-soft.com/support.htm
Product page: http://www.small-icons.com/stock-icons/16x16-free-application-icons.htm
Icon Design Service
We can design custom icons for you. Please find the basic information
about ordering icons, pricing and the portfolio here:
www.aha-soft.com/customdev/design.htm
Notice
Web-site small-icons.com belongs to Aha-Soft.
Support page: http://www.aha-soft.com/support.htm
Copyright <20> 2009 Aha-Soft. All rights reserved.

Binary file not shown.

After

Width:  |  Height:  |  Size: 904 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 905 B

View File

@@ -0,0 +1,51 @@
<%--
-- footer-home.jsp
--
-- Version: $Revision: 3705 $
--
-- Date: $Date: 2009-04-11 13:02:24 -0400 (Sat, 11 Apr 2009) $
--
-- Copyright (c) 2002, Hewlett-Packard Company and Massachusetts
-- Institute of Technology. All rights reserved.
--
-- Redistribution and use in source and binary forms, with or without
-- modification, are permitted provided that the following conditions are
-- met:
--
-- - Redistributions of source code must retain the above copyright
-- notice, this list of conditions and the following disclaimer.
--
-- - Redistributions in binary form must reproduce the above copyright
-- notice, this list of conditions and the following disclaimer in the
-- documentation and/or other materials provided with the distribution.
--
-- - Neither the name of the Hewlett-Packard Company nor the name of the
-- Massachusetts Institute of Technology nor the names of their
-- contributors may be used to endorse or promote products derived from
-- this software without specific prior written permission.
--
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-- ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-- HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
-- BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
-- OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
-- TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-- USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
-- DAMAGE.
--%>
<%--
- Footer for home page
--%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<%@ page contentType="text/html;charset=UTF-8" %>
</body>
</html>

View File

@@ -103,6 +103,11 @@
%>
<script type="text/javascript" src="<%= request.getContextPath() %>/utils.js"></script>
<script type="text/javascript" src="<%= request.getContextPath() %>/static/js/scriptaculous/prototype.js"> </script>
<script type="text/javascript" src="<%= request.getContextPath() %>/static/js/scriptaculous/effects.js"> </script>
<script type="text/javascript" src="<%= request.getContextPath() %>/static/js/scriptaculous/builder.js"> </script>
<script type="text/javascript" src="<%= request.getContextPath() %>/static/js/scriptaculous/controls.js"> </script>
<script type="text/javascript" src="<%= request.getContextPath() %>/static/js/choice-support.js"> </script>
</head>
<%-- HACK: leftmargin, topmargin: for non-CSS compliant Microsoft IE browser --%>

View File

@@ -0,0 +1,104 @@
<%--
- header-home.jsp
-
- Version: $Revision: 4254 $
-
- Date: $Date: 2009-09-11 11:59:19 -0400 (Fri, 11 Sep 2009) $
-
- Copyright (c) 2002, Hewlett-Packard Company and Massachusetts
- Institute of Technology. All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are
- met:
-
- - Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
- - Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- - Neither the name of the Hewlett-Packard Company nor the name of the
- Massachusetts Institute of Technology nor the names of their
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
- USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
- DAMAGE.
--%>
<%--
- HTML header for main home page
--%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<%@ taglib uri="http://www.dspace.org/dspace-tags.tld" prefix="dspace" %>
<%@ page contentType="text/html;charset=UTF-8" %>
<%@ page import="java.util.List"%>
<%@ page import="java.util.Enumeration"%>
<%@ page import="org.dspace.app.webui.util.JSPManager" %>
<%@ page import="org.dspace.core.ConfigurationManager" %>
<%@ page import="javax.servlet.jsp.jstl.core.*" %>
<%@ page import="javax.servlet.jsp.jstl.fmt.*" %>
<%
String title = (String) request.getAttribute("dspace.layout.title");
String navbar = (String) request.getAttribute("dspace.layout.navbar");
boolean locbar = ((Boolean) request.getAttribute("dspace.layout.locbar")).booleanValue();
String siteName = ConfigurationManager.getProperty("dspace.name");
String feedRef = (String)request.getAttribute("dspace.layout.feedref");
List parts = (List)request.getAttribute("dspace.layout.linkparts");
String extraHeadData = (String)request.getAttribute("dspace.layout.head");
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title><%= siteName %>: <%= title %></title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="Generator" content="DSpace" />
<link rel="stylesheet" href="<%= request.getContextPath() %>/styles.css.jsp" type="text/css" />
<link rel="stylesheet" href="<%= request.getContextPath() %>/print.css" media="print" type="text/css" />
<link rel="shortcut icon" href="<%= request.getContextPath() %>/favicon.ico" type="image/x-icon"/>
<%
if (extraHeadData != null)
{ %>
<%= extraHeadData %>
<%
}
%>
<script type="text/javascript" src="<%= request.getContextPath() %>/utils.js"></script>
<script type="text/javascript" src="<%= request.getContextPath() %>/static/js/scriptaculous/prototype.js"> </script>
<script type="text/javascript" src="<%= request.getContextPath() %>/static/js/scriptaculous/effects.js"> </script>
<script type="text/javascript" src="<%= request.getContextPath() %>/static/js/scriptaculous/builder.js"> </script>
<script type="text/javascript" src="<%= request.getContextPath() %>/static/js/scriptaculous/controls.js"> </script>
<script type="text/javascript" src="<%= request.getContextPath() %>/static/js/choice-support.js"> </script>
</head>
<%-- HACK: leftmargin, topmargin: for non-CSS compliant Microsoft IE browser --%>
<%-- HACK: marginwidth, marginheight: for non-CSS compliant Netscape browser --%>
<body>
<%-- Localization --%>
<%-- <c:if test="${param.locale != null}">--%>
<%-- <fmt:setLocale value="${param.locale}" scope="session" /> --%>
<%-- </c:if> --%>
<%-- <fmt:setBundle basename="Messages" scope="session"/> --%>
<%-- Page contents --%>

View File

@@ -669,3 +669,106 @@ img.controlledvocabulary {
margin-top: 5px;
margin-bottom: 5px;
}
<%-- styles added by authority control --%>
div.autocomplete {
background-color:white;
border:1px solid #888888;
margin:0;
padding:0;
position:absolute;
width:250px;
}
div.autocomplete ul {
list-style-type:none;
margin:0;
padding:0;
}
div.autocomplete ul li {
cursor:pointer;
}
div.autocomplete ul li.selected {
text-decoration: underline;
}
div.autocomplete ul li:hover {
text-decoration: underline;
}
div.autocomplete ul li span.value {
display:none;
}
/* this magic gets the 16x16 icon to show up.. setting height/width didn't
do it, but adding padding actually made it show up. */
img.ds-authority-confidence,
span.ds-authority-confidence
{ width: 16px; height: 16px; margin: 5px; background-repeat: no-repeat;
padding: 0px 2px; vertical-align: bottom; color: transparent;}
img.ds-authority-confidence.cf-unset,
span.ds-authority-confidence.cf-unset
{ background-image: url(<%= request.getContextPath() %>/image/authority/bug.png);}
img.ds-authority-confidence.cf-novalue,
span.ds-authority-confidence.cf-novalue
{ background-image: url(<%= request.getContextPath() %>/image/confidence/0-unauthored.gif);}
img.ds-authority-confidence.cf-rejected,
img.ds-authority-confidence.cf-failed,
span.ds-authority-confidence.cf-rejected,
span.ds-authority-confidence.cf-failed
{ background-image: url(<%= request.getContextPath() %>/image/confidence/2-errortriangle.gif); }
img.ds-authority-confidence.cf-notfound,
span.ds-authority-confidence.cf-notfound
{ background-image: url(<%= request.getContextPath() %>/image/confidence/3-thumb1.gif); }
img.ds-authority-confidence.cf-ambiguous,
span.ds-authority-confidence.cf-ambiguous
{ background-image: url(<%= request.getContextPath() %>/image/confidence/4-question.gif); }
img.ds-authority-confidence.cf-uncertain,
span.ds-authority-confidence.cf-uncertain
{ background-image: url(<%= request.getContextPath() %>/image/confidence/5-pinion.gif); }
img.ds-authority-confidence.cf-accepted,
span.ds-authority-confidence.cf-accepted
{ background-image: url(<%= request.getContextPath() %>/image/confidence/6-greencheck.gif); }
/* hide authority-value inputs in forms */
input.ds-authority-value { display:none; }
/** XXX Change to this to get the authority value to show up for debugging:
input.ds-authority-value { display:inline; }
**/
/* ..except, show authority-value inputs in on the Item EditMetadata page */
table.miscTable input.ds-authority-value { display: inline; }
table.authority-statistics {padding: 5px; margin-bottom: 15px;}
table.authority-statistics table {float: left; text-align: center;}
div.authority-key-nav-link, div.authority-page-nav-link {margin-top: 20px;}
div#authority-message {
width: 80%;
display:block;
text-align: center;
margin-left: 10%;
padding: 10px;
border: 1px dashed #FFCC00;
background-color: #FFF4C8;
}
a.authority {
background: transparent url(<%= request.getContextPath() %>/image/authority/book_key.png) no-repeat;
background-position: top right;
padding-right: 20px;
}
/* for edit-item-form lock button */
input.ds-authority-lock
{ vertical-align: bottom; height: 24px; width: 24px; margin-right: 8px;
background-repeat: no-repeat; background-color: transparent; }
input.ds-authority-lock.is-locked
{ background-image: url(<%= request.getContextPath() %>/image/lock24.png); }
input.ds-authority-lock.is-unlocked
{ background-image: url(<%= request.getContextPath() %>/image/unlock24.png); }

View File

@@ -77,6 +77,9 @@
<%@ page import="org.dspace.content.DCSeriesNumber" %>
<%@ page import="org.dspace.content.DCValue" %>
<%@ page import="org.dspace.content.Item" %>
<%@ page import="org.dspace.content.authority.MetadataAuthorityManager" %>
<%@ page import="org.dspace.content.authority.ChoiceAuthorityManager" %>
<%@ page import="org.dspace.content.authority.Choices" %>
<%@ page import="org.dspace.core.ConfigurationManager" %>
<%@ taglib uri="http://www.dspace.org/dspace-tags.tld" prefix="dspace" %>
@@ -85,9 +88,13 @@
request.setAttribute("LanguageSwitch", "hide");
%>
<%!
// required by Controlled Vocabulary add-on
// required by Controlled Vocabulary add-on and authority addon
String contextPath;
// An unknown value of confidence for new, empty input fields,
// so no icon appears yet.
int unknownConfidence = Choices.CF_UNSET - 100;
// This method is resposible for showing a link next to an input box
// that pops up a window that to display a controlled vocabulary.
// It should be called from the doOneBox and doTwoBox methods.
@@ -131,10 +138,135 @@
return has;
}
// is this field going to be rendered as Choice-driven <select>?
boolean isSelectable(String fieldKey)
{
ChoiceAuthorityManager cam = ChoiceAuthorityManager.getManager();
return (cam.isChoicesConfigured(fieldKey) &&
"select".equals(cam.getPresentation(fieldKey)));
}
// Render the choice/authority controlled entry, or, if not indicated,
// returns the given default inputBlock
StringBuffer doAuthority(PageContext pageContext, String fieldName,
int idx, int fieldCount, String fieldInput, String authorityValue,
int confidenceValue, boolean isName, boolean repeatable,
DCValue[] dcvs, StringBuffer inputBlock, int collectionID)
{
MetadataAuthorityManager mam = MetadataAuthorityManager.getManager();
ChoiceAuthorityManager cam = ChoiceAuthorityManager.getManager();
StringBuffer sb = new StringBuffer();
if (cam.isChoicesConfigured(fieldName))
{
boolean authority = mam.isAuthorityControlled(fieldName);
boolean required = authority && mam.isAuthorityRequired(fieldName);
boolean isSelect = "select".equals(cam.getPresentation(fieldName)) && !isName;
// if this is not the only or last input, append index to input @names
String authorityName = fieldName + "_authority";
String confidenceName = fieldName + "_confidence";
if (repeatable && !isSelect && idx != fieldCount-1)
{
fieldInput += '_'+String.valueOf(idx+1);
authorityName += '_'+String.valueOf(idx+1);
confidenceName += '_'+String.valueOf(idx+1);
}
String confidenceSymbol = confidenceValue == unknownConfidence ? "blank" : Choices.getConfidenceText(confidenceValue).toLowerCase();
String confIndID = fieldInput+"_confidence_indicator_id";
if (authority)
{
sb.append(" <img id=\""+confIndID+"\" title=\"")
.append(LocaleSupport.getLocalizedMessage(pageContext, "jsp.authority.confidence.description."+confidenceSymbol))
.append("\" class=\"ds-authority-confidence cf-")
// set confidence to cf-blank if authority is empty
.append(authorityValue==null||authorityValue.length()==0 ? "blank" : confidenceSymbol)
.append(" \" src=\"").append(contextPath).append("/image/confidence/invisible.gif\" />")
.append("<input type=\"text\" value=\"").append(authorityValue!=null?authorityValue:"")
.append("\" id=\"").append(authorityName)
.append("\" name=\"").append(authorityName).append("\" class=\"ds-authority-value\"/>")
.append("<input type=\"hidden\" value=\"").append(confidenceSymbol)
.append("\" id=\"").append(confidenceName)
.append("\" name=\"").append(confidenceName)
.append("\" class=\"ds-authority-confidence-input\"/>");
}
// suggest is not supported for name input type
if ("suggest".equals(cam.getPresentation(fieldName)) && !isName)
{
if (inputBlock != null)
sb.insert(0, inputBlock);
sb.append("<span id=\"").append(fieldInput).append("_indicator\" style=\"display: none;\">")
.append("<img src=\"").append(contextPath).append("/image/authority/load-indicator.gif\" alt=\"Loading...\"/>")
.append("</span><div id=\"").append(fieldInput).append("_autocomplete\" class=\"autocomplete\" style=\"display: none;\"> </div>");
sb.append("<script type=\"text/javascript\">")
.append("var gigo = DSpaceSetupAutocomplete('edit_metadata',")
.append("{ metadataField: '").append(fieldName).append("', isClosed: '").append(required?"true":"false").append("', inputName: '")
.append(fieldInput).append("', authorityName: '").append(authorityName).append("', containerID: '")
.append(fieldInput).append("_autocomplete', indicatorID: '").append(fieldInput).append("_indicator', ")
.append("contextPath: '").append(contextPath)
.append("', confidenceName: '").append(confidenceName)
.append("', confidenceIndicatorID: '").append(confIndID)
.append("', collection: ").append(String.valueOf(collectionID))
.append(" }); </script>");
}
// put up a SELECT element containing all choices
else if (isSelect)
{
sb.append("<select id=\"").append(fieldInput)
.append("_id\" name=\"").append(fieldInput)
.append("\" size=\"").append(String.valueOf(repeatable ? 6 : 1))
.append(repeatable ? "\" multiple>\n" :"\">\n");
Choices cs = cam.getMatches(fieldName, "", collectionID, 0, 0, null);
// prepend unselected empty value when nothing can be selected.
if (!repeatable && cs.defaultSelected < 0 && dcvs.length == 0)
sb.append("<option value=\"\"><!-- empty --></option>\n");
for (int i = 0; i < cs.values.length; ++i)
{
boolean selected = false;
for (DCValue dcv : dcvs)
{
if (dcv.value.equals(cs.values[i].value))
selected = true;
}
sb.append("<option value=\"")
.append(cs.values[i].value.replaceAll("\"", "\\\""))
.append("\"")
.append(selected ? " selected>":">")
.append(cs.values[i].label).append("</option>\n");
}
sb.append("</select>\n");
}
// use lookup for any other presentation style (i.e "select")
else
{
if (inputBlock != null)
sb.insert(0, inputBlock);
sb.append("<input type=\"image\" name=\"").append(fieldInput).append("_lookup\" ")
.append("onclick=\"javascript: return DSpaceChoiceLookup('")
.append(contextPath).append("/tools/lookup.jsp','")
.append(fieldName).append("','edit_metadata','")
.append(fieldInput).append("','").append(authorityName).append("','")
.append(confIndID).append("',")
.append(String.valueOf(collectionID)).append(",")
.append(String.valueOf(isName)).append(",false);\"")
.append(" title=\"")
.append(LocaleSupport.getLocalizedMessage(pageContext, "jsp.tools.lookup.lookup"))
.append("\" width=\"16px\" height=\"16px\" src=\""+contextPath+"/image/authority/zoom.png\" />");
}
}
else if (inputBlock != null)
sb = inputBlock;
return sb;
}
void doPersonalName(javax.servlet.jsp.JspWriter out, Item item,
String fieldName, String schema, String element, String qualifier, boolean repeatable,
boolean readonly, int fieldCountIncr, String label, PageContext pageContext)
boolean readonly, int fieldCountIncr, String label, PageContext pageContext, int collectionID)
throws java.io.IOException
{
@@ -143,6 +275,8 @@
StringBuffer headers = new StringBuffer();
StringBuffer sb = new StringBuffer();
org.dspace.content.DCPersonName dpn;
String auth;
int conf = 0;
StringBuffer name = new StringBuffer();
StringBuffer first = new StringBuffer();
StringBuffer last = new StringBuffer();
@@ -169,12 +303,12 @@
{
first.setLength(0);
first.append(fieldName).append("_first");
if (repeatable && i != fieldCount)
if (repeatable && i != fieldCount-1)
first.append('_').append(i+1);
last.setLength(0);
last.append(fieldName).append("_last");
if (repeatable && i != fieldCount)
if (repeatable && i != fieldCount-1)
last.append('_').append(i+1);
if (i == 0)
@@ -185,9 +319,17 @@
sb.append("<tr><td>&nbsp;</td>");
if (i < defaults.length)
{
dpn = new org.dspace.content.DCPersonName(defaults[i].value);
auth = defaults[i].authority;
conf = defaults[i].confidence;
}
else
{
dpn = new org.dspace.content.DCPersonName();
auth = "";
conf = unknownConfidence;
}
sb.append("<td><input type=\"text\" name=\"")
.append(last.toString())
@@ -198,7 +340,7 @@
}
sb.append("value=\"")
.append(dpn.getLastName().replaceAll("\"", "&quot;")) // Encode "
.append("\"/></td>\n<td><input type=\"text\" name=\"")
.append("\"/></td>\n<td nowrap=\"nowrap\"><input type=\"text\" name=\"")
.append(first.toString())
.append("\" size=\"23\" ");
if (readonly)
@@ -206,7 +348,10 @@
sb.append("disabled=\"disabled\" ");
}
sb.append("value=\"")
.append(dpn.getFirstNames()).append("\"/></td>\n");
.append(dpn.getFirstNames()).append("\"/>")
.append(doAuthority(pageContext, fieldName, i, fieldCount, fieldName,
auth, conf, true, repeatable, defaults, null, collectionID))
.append("</td>\n");
if (repeatable && !readonly && i < defaults.length)
{
@@ -469,14 +614,15 @@
void doTextArea(javax.servlet.jsp.JspWriter out, Item item,
String fieldName, String schema, String element, String qualifier, boolean repeatable, boolean readonly,
int fieldCountIncr, String label, PageContext pageContext, String vocabulary, boolean closedVocabulary)
int fieldCountIncr, String label, PageContext pageContext, String vocabulary, boolean closedVocabulary, int collectionID)
throws java.io.IOException
{
DCValue[] defaults = item.getMetadata(schema, element, qualifier, Item.ANY);
int fieldCount = defaults.length + fieldCountIncr;
StringBuffer sb = new StringBuffer();
String val;
String val, auth;
int conf = unknownConfidence;
if (fieldCount == 0)
fieldCount = 1;
@@ -491,20 +637,29 @@
sb.append("<tr><td>&nbsp;</td>");
if (i < defaults.length)
{
val = defaults[i].value;
auth = defaults[i].authority;
conf = defaults[i].confidence;
}
else
{
val = "";
sb.append("<td colspan=\"2\"><textarea name=\"")
.append(fieldName);
if (repeatable && i!= fieldCount)
sb.append("_").append(i+1);
sb.append("\" rows=\"4\" cols=\"45\"")
auth = "";
}
sb.append("<td colspan=\"2\">\n");
String fieldNameIdx = fieldName + ((repeatable && i != fieldCount-1)?"_" + (i+1):"");
StringBuffer inputBlock = new StringBuffer().append("<textarea name=\"").append(fieldNameIdx)
.append("\" rows=\"4\" cols=\"45\" id=\"")
.append(fieldNameIdx).append("_id\" ")
.append((hasVocabulary(vocabulary)&&closedVocabulary)||readonly?" disabled=\"disabled\" ":"")
.append(">")
.append(val)
.append("</textarea>")
.append(doControlledVocabulary(fieldName + (repeatable?"_" + i:""), pageContext, vocabulary, readonly))
.append("</textarea>\n")
.append(doControlledVocabulary(fieldNameIdx, pageContext, vocabulary, readonly));
sb.append(doAuthority(pageContext, fieldName, i, fieldCount, fieldName,
auth, conf, false, repeatable,
defaults, inputBlock, collectionID))
.append("</td>\n");
if (repeatable && !readonly && i < defaults.length)
@@ -541,14 +696,15 @@
void doOneBox(javax.servlet.jsp.JspWriter out, Item item,
String fieldName, String schema, String element, String qualifier, boolean repeatable, boolean readonly,
int fieldCountIncr, String label, PageContext pageContext, String vocabulary, boolean closedVocabulary)
int fieldCountIncr, String label, PageContext pageContext, String vocabulary, boolean closedVocabulary, int collectionID)
throws java.io.IOException
{
DCValue[] defaults = item.getMetadata(schema, element, qualifier, Item.ANY);
int fieldCount = defaults.length + fieldCountIncr;
StringBuffer sb = new StringBuffer();
String val;
String val, auth;
int conf= 0;
if (fieldCount == 0)
fieldCount = 1;
@@ -563,23 +719,34 @@
sb.append("<tr><td>&nbsp;</td>");
if (i < defaults.length)
{
val = defaults[i].value.replaceAll("\"", "&quot;");
auth = defaults[i].authority;
conf = defaults[i].confidence;
}
else
{
val = "";
auth = "";
conf= unknownConfidence;
}
sb.append("<td colspan=\"2\"><input type=\"text\" name=\"")
.append(fieldName);
if (repeatable && i!= fieldCount)
sb.append("_").append(i+1);
sb.append("\" size=\"50\" value=\"")
sb.append("<td colspan=\"2\">");
String fieldNameIdx = fieldName + ((repeatable && i != fieldCount-1)?"_" + (i+1):"");
StringBuffer inputBlock = new StringBuffer("<input type=\"text\" name=\"")
.append(fieldNameIdx)
.append("\" id=\"")
.append(fieldNameIdx).append("\" size=\"50\" value=\"")
.append(val +"\"")
.append((hasVocabulary(vocabulary)&&closedVocabulary) || readonly?" disabled=\"disabled\" ":"")
.append("/>")
.append(doControlledVocabulary(fieldName + (repeatable&& i!= fieldCount?"_" + (i+1):""), pageContext, vocabulary, readonly))
.append(doControlledVocabulary(fieldNameIdx, pageContext, vocabulary, readonly))
.append("\n");
sb.append(doAuthority(pageContext, fieldName, i, fieldCount,
fieldName, auth, conf, false, repeatable,
defaults, inputBlock, collectionID))
.append("</td>\n");
if (repeatable && !readonly && i < defaults.length)
{
// put a remove button next to filled in values
@@ -823,7 +990,7 @@
sb.append("<td colspan=\"2\"><select name=\"")
.append(fieldName)
.append("_qualifier");
if (repeatable && j!= fieldCount)
if (repeatable && j!= fieldCount-1)
sb.append("_").append(j+1);
if (readonly)
{
@@ -847,7 +1014,7 @@
sb.append("</select>&nbsp;<input type=\"text\" name=\"")
.append(fieldName)
.append("_value");
if (repeatable && j!= fieldCount)
if (repeatable && j!= fieldCount-1)
sb.append("_").append(j+1);
if (readonly)
{
@@ -938,6 +1105,27 @@
out.write(sb.toString());
}
void doChoiceSelect(javax.servlet.jsp.JspWriter out, PageContext pageContext, Item item,
String fieldName, String schema, String element, String qualifier, boolean repeatable,
boolean readonly, List valueList, String label, int collectionID)
throws java.io.IOException
{
DCValue[] defaults = item.getMetadata(schema, element, qualifier, Item.ANY);
StringBuffer sb = new StringBuffer();
sb.append("<tr><td class=\"submitFormLabel\">")
.append(label)
.append("</td>");
sb.append("<td colspan=\"2\">")
.append(doAuthority(pageContext, fieldName, 0, defaults.length,
fieldName, null, Choices.CF_UNSET, false, repeatable,
defaults, null, collectionID))
.append("</td></tr>");
out.write(sb.toString());
}
/** Display Checkboxes or Radio buttons, depending on if repeatable! **/
void doList(javax.servlet.jsp.JspWriter out, Item item,
@@ -1024,7 +1212,8 @@
sb.append("</td></tr>");
out.write(sb.toString());
}//end doList%>
}//end doList
%>
<%
// Obtain DSpace context
@@ -1047,6 +1236,9 @@
// for later use, determine whether we are in submit or workflow mode
String scope = si.isInWorkflow() ? "workflow" : "submit";
// owning Collection ID for choice authority calls
int collectionID = si.getSubmissionItem().getCollection().getID();
%>
<dspace:layout locbar="off" navbar="off" titlekey="jsp.submit.edit-metadata.title">
@@ -1057,7 +1249,7 @@
<form action="<%= request.getContextPath() %>/submit#<%= si.getJumpToField()%>" method="post" name="edit_metadata" onkeydown="return disableEnterKey(event);">
<form action="<%= request.getContextPath() %>/submit#<%= si.getJumpToField()%>" method="post" name="edit_metadata" id="edit_metadata" onkeydown="return disableEnterKey(event);">
<jsp:include page="/submit/progressbar.jsp"></jsp:include>
@@ -1167,7 +1359,12 @@
if (inputType.equals("name"))
{
doPersonalName(out, item, fieldName, dcSchema, dcElement, dcQualifier,
repeatable, readonly, fieldCountIncr, label, pageContext);
repeatable, readonly, fieldCountIncr, label, pageContext, collectionID);
}
else if (isSelectable(fieldName))
{
doChoiceSelect(out, pageContext, item, fieldName, dcSchema, dcElement, dcQualifier,
repeatable, readonly, inputs[z].getPairs(), label, collectionID);
}
else if (inputType.equals("date"))
{
@@ -1188,7 +1385,7 @@
{
doTextArea(out, item, fieldName, dcSchema, dcElement, dcQualifier,
repeatable, readonly, fieldCountIncr, label, pageContext, vocabulary,
closedVocabulary);
closedVocabulary, collectionID);
}
else if (inputType.equals("dropdown"))
{
@@ -1210,7 +1407,7 @@
{
doOneBox(out, item, fieldName, dcSchema, dcElement, dcQualifier,
repeatable, readonly, fieldCountIncr, label, pageContext, vocabulary,
closedVocabulary);
closedVocabulary, collectionID);
}
if (hasVocabulary(vocabulary) && !readonly)

View File

@@ -56,6 +56,7 @@
<%@ page import="org.dspace.content.InProgressSubmission" %>
<%@ page import="org.dspace.app.webui.util.UIUtil" %>
<%@ page import="org.dspace.app.util.DCInputsReader" %>
<%@ page import="org.dspace.app.util.DCInputsReaderException" %>
<%@ page import="org.dspace.app.util.DCInputSet" %>
<%@ page import="org.dspace.app.util.DCInput" %>
<%@ page import="org.dspace.content.Collection" %>
@@ -66,6 +67,8 @@
<%@ page import="org.dspace.core.Context" %>
<%@ page import="org.dspace.core.Utils" %>
<%@ page import="org.dspace.content.authority.MetadataAuthorityManager" %>
<%@ page import="javax.servlet.jsp.jstl.fmt.LocaleSupport" %>
<%@ page import="javax.servlet.jsp.PageContext" %>
@@ -93,14 +96,23 @@
Item item = subInfo.getSubmissionItem().getItem();
//get the inputs reader
DCInputsReader inputsReader = DescribeStep.getInputsReader();
// determine collection
Collection c = subInfo.getSubmissionItem().getCollection();
DCInputSet inputSet = null;
try
{
//get the inputs reader
DCInputsReader inputsReader = DescribeStep.getInputsReader();
//load the input set for the current collection
DCInputSet inputSet = inputsReader.getInputs(c.getHandle());
inputSet = inputsReader.getInputs(c.getHandle());
}
catch (DCInputsReaderException e)
{
throw new ServletException(e);
}
%>
<%!void layoutSection(HttpServletRequest request,
@@ -118,6 +130,10 @@
DCInput[] inputs = inputSet.getPageRows(pageNum-1,
ip.hasMultipleTitles(),
ip.isPublishedBefore());
MetadataAuthorityManager mam = MetadataAuthorityManager.getManager();
for (int z = 0; z < inputs.length; z++)
{
String scope = subInfo.isInWorkflow() ? DCInput.WORKFLOW_SCOPE : DCInput.SUBMISSION_SCOPE;
@@ -151,6 +167,9 @@
}
else
{
boolean isAuthorityControlled = mam.isAuthorityControlled(inputs[z].getSchema(),
inputs[z].getElement(),inputs[z].getQualifier());
for (int i = 0; i < values.length; i++)
{
boolean newline = true;
@@ -200,7 +219,12 @@
{
row.append(Utils.addEntities(values[i].value));
}
if (isAuthorityControlled)
{
row.append("<span class=\"ds-authority-confidence cf-")
.append(values[i].confidence).append("\">")
.append(" </span>");
}
if (newline)
{
row.append("<br />");

View File

@@ -75,6 +75,9 @@
<%@ page import="org.dspace.core.ConfigurationManager" %>
<%@ page import="org.dspace.eperson.EPerson" %>
<%@ page import="org.dspace.core.Utils" %>
<%@ page import="org.dspace.content.authority.MetadataAuthorityManager" %>
<%@ page import="org.dspace.content.authority.ChoiceAuthorityManager" %>
<%@ page import="org.dspace.content.authority.Choices" %>
<%
Item item = (Item) request.getAttribute("item");
@@ -111,8 +114,96 @@
Boolean reinstate = (Boolean)request.getAttribute("reinstate_button");
boolean bReinstate = (reinstate == null ? false : reinstate.booleanValue());
%>
// owning Collection ID for choice authority calls
int collectionID = -1;
if (collections.length > 0)
collectionID = collections[0].getID();
%>
<%!
StringBuffer doAuthority(MetadataAuthorityManager mam, ChoiceAuthorityManager cam,
PageContext pageContext,
String contextPath, String fieldName, String idx,
DCValue dcv, int collectionID)
{
StringBuffer sb = new StringBuffer();
if (cam.isChoicesConfigured(fieldName))
{
boolean authority = mam.isAuthorityControlled(fieldName);
boolean required = authority && mam.isAuthorityRequired(fieldName);
String fieldNameIdx = "value_" + fieldName + "_" + idx;
String authorityName = "choice_" + fieldName + "_authority_" + idx;
String confidenceName = "choice_" + fieldName + "_confidence_" + idx;
// put up a SELECT element containing all choices
if ("select".equals(cam.getPresentation(fieldName)))
{
sb.append("<select id=\"").append(fieldNameIdx)
.append("\" name=\"").append(fieldNameIdx)
.append("\" size=\"1\">");
Choices cs = cam.getMatches(fieldName, dcv.value, collectionID, 0, 0, null);
if (cs.defaultSelected < 0)
sb.append("<option value=\"").append(dcv.value).append("\" selected>")
.append(dcv.value).append("</option>\n");
for (int i = 0; i < cs.values.length; ++i)
{
sb.append("<option value=\"").append(cs.values[i].value).append("\"")
.append(i == cs.defaultSelected ? " selected>":">")
.append(cs.values[i].label).append("</option>\n");
}
sb.append("</select>\n");
}
// use lookup for any other presentation style (i.e "select")
else
{
String confidenceIndicator = "indicator_"+confidenceName;
sb.append("<textarea id=\"").append(fieldNameIdx).append("\" name=\"").append(fieldNameIdx)
.append("\" rows=\"3\" cols=\"50\">")
.append(dcv.value).append("</textarea>\n<br/>\n");
if (authority)
{
String confidenceSymbol = Choices.getConfidenceText(dcv.confidence).toLowerCase();
sb.append("<img id=\""+confidenceIndicator+"\" title=\"")
.append(LocaleSupport.getLocalizedMessage(pageContext, "jsp.authority.confidence.description."+confidenceSymbol))
.append("\" class=\"ds-authority-confidence cf-"+ confidenceSymbol)
.append("\" src=\"").append(contextPath).append("/image/confidence/invisible.gif\" />")
.append("<input type=\"text\" readonly value=\"")
.append(dcv.authority != null ? dcv.authority : "")
.append("\" id=\"").append(authorityName)
.append("\" onChange=\"javascript: return DSpaceAuthorityOnChange(this, '")
.append(confidenceName).append("','").append(confidenceIndicator)
.append("');\" name=\"").append(authorityName).append("\" class=\"ds-authority-value ds-authority-visible \"/>")
.append("<input type=\"image\" class=\"ds-authority-lock is-locked \" ")
.append(" src=\"").append(contextPath).append("/image/confidence/invisible.gif\" ")
.append(" onClick=\"javascript: return DSpaceToggleAuthorityLock(this, '").append(authorityName).append("');\" ")
.append(" title=\"")
.append(LocaleSupport.getLocalizedMessage(pageContext, "jsp.tools.edit-item-form.unlock"))
.append("\" >")
.append("<input type=\"hidden\" value=\"").append(confidenceSymbol).append("\" id=\"").append(confidenceName)
.append("\" name=\"").append(confidenceName)
.append("\" class=\"ds-authority-confidence-input\"/>");
}
sb.append("<input type=\"image\" name=\"").append(fieldNameIdx).append("_lookup\" ")
.append("onclick=\"javascript: return DSpaceChoiceLookup('")
.append(contextPath).append("/tools/lookup.jsp','")
.append(fieldName).append("','edit_metadata','")
.append(fieldNameIdx).append("','").append(authorityName).append("','")
.append(confidenceIndicator).append("',")
.append(String.valueOf(collectionID)).append(",")
.append("false").append(",false);\"")
.append(" title=\"")
.append(LocaleSupport.getLocalizedMessage(pageContext, "jsp.tools.lookup.lookup"))
.append("\" width=\"16px\" height=\"16px\" src=\""+contextPath+"/image/authority/zoom.png\" />");
}
}
return sb;
}
%>
<dspace:layout titlekey="jsp.tools.edit-item-form.title"
navbar="admin"
@@ -260,7 +351,7 @@
<p>&nbsp;</p>
<form method="post" action="<%= request.getContextPath() %>/tools/edit-item">
<form id="edit_metadata" name="edit_metadata" method="post" action="<%= request.getContextPath() %>/tools/edit-item">
<table class="miscTable" summary="Edit item withdrawn table">
<tr>
<%-- <th class="oddRowOddCol"><strong>Element</strong></th>
@@ -276,6 +367,8 @@
<th id="t5" class="oddRowEvenCol">&nbsp;</th>
</tr>
<%
MetadataAuthorityManager mam = MetadataAuthorityManager.getManager();
ChoiceAuthorityManager cam = ChoiceAuthorityManager.getManager();
DCValue[] dcv = item.getMetadata(Item.ANY, Item.ANY, Item.ANY, Item.ANY);
String row = "even";
@@ -288,8 +381,7 @@
{
// Find out how many values with this element/qualifier we've found
String key = dcv[i].schema + "_" + dcv[i].element +
(dcv[i].qualifier == null ? "" : "_" + dcv[i].qualifier);
String key = ChoiceAuthorityManager.makeFieldKey(dcv[i].schema, dcv[i].element, dcv[i].qualifier);
Integer count = (Integer) dcCounter.get(key);
if (count == null)
@@ -316,7 +408,17 @@
<td headers="t1" class="<%= row %>RowEvenCol"><%= dcv[i].element %>&nbsp;&nbsp;</td>
<td headers="t2" class="<%= row %>RowOddCol"><%= (dcv[i].qualifier == null ? "" : dcv[i].qualifier) %></td>
<td headers="t3" class="<%= row %>RowEvenCol">
<textarea name="value_<%= key %>_<%= sequenceNumber %>" rows="3" cols="50"><%= Utils.addEntities(dcv[i].value) %></textarea>
<%
if (cam.isChoicesConfigured(key))
{
%>
<%=
doAuthority(mam, cam, pageContext, request.getContextPath(), key, sequenceNumber,
dcv[i], collectionID).toString()
%>
<% } else { %>
<textarea id="value_<%= key %>_<%= sequenceNumber %>" name="value_<%= key %>_<%= sequenceNumber %>" rows="3" cols="50"><%= dcv[i].value %></textarea>
<% } %>
</td>
<td headers="t4" class="<%= row %>RowOddCol">
<input type="text" name="language_<%= key %>_<%= sequenceNumber %>" value="<%= (dcv[i].language == null ? "" : dcv[i].language) %>" size="5"/>

View File

@@ -0,0 +1,174 @@
<%--
- lookup.jsp
-
- Version: $Revision: 3705 $
-
- Date: $Date: 2009-04-11 13:02:24 -0400 (Sat, 11 Apr 2009) $
-
- Copyright (c) 2002, Hewlett-Packard Company and Massachusetts
- Institute of Technology. All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are
- met:
-
- - Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
- - Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- - Neither the name of the Hewlett-Packard Company nor the name of the
- Massachusetts Institute of Technology nor the names of their
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
- USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
- DAMAGE.
--%>
<%--
- Form requesting a Handle or internal item ID for item editing
-
- Attributes:
- invalid.id - if this attribute is present, display error msg
--%>
<%@ page contentType="text/html;charset=UTF-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt"
prefix="fmt" %>
<%@ taglib uri="http://www.dspace.org/dspace-tags.tld" prefix="dspace" %>
<%@ page import="javax.servlet.jsp.jstl.fmt.LocaleSupport" %>
<%@ page import="javax.servlet.http.HttpServletRequest" %>
<%@ page import="javax.servlet.jsp.tagext.TagSupport" %>
<%@ page import="javax.servlet.jsp.PageContext" %>
<%@ page import="javax.servlet.ServletException" %>
<%@ page import="org.dspace.core.ConfigurationManager" %>
<%-- invoke "popup" style which elides all the header and footer stuff.
--%>
<%!
// get request parameter but return a default value if not present.
String getDefaultedRequestParameter(HttpServletRequest r, String param, String dflt)
{
String result = r.getParameter(param);
return (result == null) ? dflt : result;
}
%>
<%
String mdfield = getDefaultedRequestParameter(request,"field", "FieldMissing");
String isNameValue = getDefaultedRequestParameter(request,"isName", "false");
String isRepeatingValue = getDefaultedRequestParameter(request,"isRepeating", "false");
boolean isName = isNameValue.equalsIgnoreCase("true");
boolean isRepeating = isRepeatingValue.equalsIgnoreCase("true");
%>
<dspace:layout titlekey="jsp.tools.lookup.title"
style="popup"
navbar="off"
locbar="off"
parenttitlekey="jsp.administer"
parentlink="/dspace-admin">
<h1><%= LocaleSupport.getLocalizedMessage(pageContext, "jsp.tools.lookup.field."+mdfield+".title") %></h1>
<form id="aspect_general_ChoiceLookupTransformer_div_lookup"
class="ds-interactive-div popup" action="" method="get">
<fieldset id="aspect_general_ChoiceLookupTransformer_list_choicesList"
class="ds-form-list choices-lookup">
<%-- Results @1@ to @2@ of @3@ for "@4@" --%>
<legend><fmt:message key="jsp.tools.lookup.results"/></legend>
<ol>
<li id="aspect_general_ChoiceLookupTransformer_item_select" class="ds-form-item choices-lookup"> 
<div class="ds-form-content">
<div>
<select onChange="javascript:DSpaceChoicesSelectOnChange();" id="aspect_general_ChoiceLookupTransformer_field_chooser" class="ds-select-field choices-lookup" name="chooser"
size="<%= String.valueOf(ConfigurationManager.getIntProperty("webui.lookup.select.size", 12)) %>">
<!--space filler because "unclosed" select annoys browsers-->
</select>
<img style="display:none;" alt="Loading..." id="lookup_indicator_id" class="choices-lookup"
src="<%= request.getContextPath() %>/image/authority/load-indicator.gif" />
</div>
<input type="hidden" name="paramField" value="<%= getDefaultedRequestParameter(request,"field", "") %>" />
<input type="hidden" name="paramValue" value="<%= getDefaultedRequestParameter(request,"value", "") %>" />
<input type="hidden" name="paramIsName" value="<%= isNameValue %>" />
<input type="hidden" name="paramIsRepeating" value="<%= isRepeatingValue %>" />
<input type="hidden" name="paramValueInput" value="<%= getDefaultedRequestParameter(request,"valueInput", "") %>" />
<input type="hidden" name="paramAuthorityInput" value="<%= getDefaultedRequestParameter(request,"authorityInput", "") %>" />
<input type="hidden" name="paramStart" value="<%= getDefaultedRequestParameter(request,"start", "0") %>" />
<input type="hidden" name="paramLimit" value="<%= getDefaultedRequestParameter(request,"limit", "0") %>" />
<input type="hidden" name="paramFormID" value="<%= getDefaultedRequestParameter(request,"formID", "") %>" />
<input type="hidden" name="paramIsClosed" value="<%= getDefaultedRequestParameter(request,"isClosed", "false") %>" />
<input type="hidden" name="paramConfIndicatorID" value="<%= getDefaultedRequestParameter(request,"confIndicatorID", "") %>" />
<input type="hidden" name="paramCollection" value="<%= getDefaultedRequestParameter(request,"collection", "-1") %>" />
<%-- XXX get this from dspace config if available..?? --%>
<input type="hidden" name="paramNonAuthority" value="<%= LocaleSupport.getLocalizedMessage(pageContext, "jsp.tools.lookup.field."+mdfield+".nonauthority") %>" />
<input name="paramFail" type="hidden" value="<%= LocaleSupport.getLocalizedMessage(pageContext, "jsp.tools.lookup.fail") %>" />
<input name="contextPath" type="hidden" value="<%= request.getContextPath() %>" />
</div>
</li>
<li id="aspect_general_ChoiceLookupTransformer_item_textFields" class="ds-form-item choices-lookup"> 
<div class="ds-form-content">
<% if (isName) { %>
<%-- XXX get this from dspace config if available..?? --%>
<% String help1 = LocaleSupport.getLocalizedMessage(pageContext, "jsp.tools.lookup.field."+mdfield+".help.last"); %>
<% String help2 = LocaleSupport.getLocalizedMessage(pageContext, "jsp.tools.lookup.field."+mdfield+".help.first"); %>
<label class="ds-composite-component">
<input class="ds-text-field choices-lookup" name="text1" type="text" value=""
title="<%= help1 %>" />
<br/><%= help1 %>
</label>
<label class="ds-composite-component last">
<input class="ds-text-field choices-lookup" name="text2" type="text" value=""
title="<%= help2 %>" />
<br/><%= help2 %>
</label>
<% } else { %>
<%-- XXX get this from dspace config if available..?? --%>
<% String help = LocaleSupport.getLocalizedMessage(pageContext, "jsp.tools.lookup.field."+mdfield+".help"); %>
<label class="ds-composite-component">
<input class="ds-text-field choices-lookup" name="text1" type="text" value=""
title="<%= help %>" />
<br/><%= help %>
</label>
<% } %>
<div class="spacer"> </div>
</div>
</li>
<li class="ds-form-item last choices-lookup"> 
<div class="ds-form-content">
<input name="accept" onClick="javascript:DSpaceChoicesAcceptOnClick();" type="button" class="ds-button-field choices-lookup"
value="<%= LocaleSupport.getLocalizedMessage(pageContext, isRepeating ? "jsp.tools.lookup.add":"jsp.tools.lookup.accept") %>"/>
<input name="more" onClick="javascript:DSpaceChoicesMoreOnClick();" type="button" class="ds-button-field choices-lookup" disabled="disabled"
value="<%= LocaleSupport.getLocalizedMessage(pageContext, "jsp.tools.lookup.more") %>"/>
<input name="cancel" onClick="javascript:DSpaceChoicesCancelOnClick();" type="button" class="ds-button-field choices-lookup"
value="<%= LocaleSupport.getLocalizedMessage(pageContext, "jsp.tools.lookup.cancel") %>"/>
</div>
</li>
</ol>
</fieldset>
</form>
<script type="text/javascript">
var form = document.getElementById('aspect_general_ChoiceLookupTransformer_div_lookup');
DSpaceChoicesSetup(form);
</script>
</dspace:layout>

54
dspace-ui-shared/pom.xml Normal file
View File

@@ -0,0 +1,54 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.dspace</groupId>
<artifactId>dspace-ui-shared</artifactId>
<packaging>war</packaging>
<name>DSpace UI :: Shared JS code</name>
<description>Some JS artifacts shared betwee DSpace JSPUI and XMLUI</description>
<url>http://projects.dspace.org/dspace-ui-shared</url>
<!--
A Parent POM that Maven inherits DSpace Defaults
POM atrributes from.
-->
<parent>
<groupId>org.dspace</groupId>
<artifactId>dspace-parent</artifactId>
<version>1.6.0-SNAPSHOT</version>
</parent>
<repositories>
<repository>
<id>maven.dspace.org-snapshot</id>
<name>DSpace Maven Snapshot Repository</name>
<url>http://maven.dspace.org/snapshot</url>
<releases>
<enabled>false</enabled>
<checksumPolicy>fail</checksumPolicy>
</releases>
<snapshots>
<enabled>true</enabled>
<updatePolicy>never</updatePolicy>
<checksumPolicy>fail</checksumPolicy>
</snapshots>
</repository>
</repositories>
<!--
The Subversion repository location is used by Continuum to update against
when changes have occured, this spawns a new build cycle and releases snapshots
into the snapshot repository below.
-->
<scm>
<connection>scm:svn:http://scm.dspace.org/svn/repo/dspace/trunk/dspace</connection>
<developerConnection>scm:svn:https://scm.dspace.org/svn/repo/dspace/trunk/dspace</developerConnection>
<url>http://scm.dspace.org/svn/repo/dspace/trunk/dspace</url>
</scm>
<!--
Runtime and Compile Time dependencies for DSpace.
-->
<dependencies>
</dependencies>
</project>

View File

@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
<!--
- web.xml
-
- Version: $Revision: 4254 $
-
- Date: $Date: 2009-09-11 11:59:19 -0400 (Fri, 11 Sep 2009) $
-
- Copyright (c) 2002-2006, Hewlett-Packard Company and Massachusetts
- Institute of Technology. All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are
- met:
-
- - Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
- - Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- - Neither the name of the Hewlett-Packard Company nor the name of the
- Massachusetts Institute of Technology nor the names of their
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
- USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
- DAMAGE.
-->
<!--
- The is the servlet deployment descriptor for Tomcat 4.0 for the DSpace
- Web user interface
-
- '@@dspace.dir@@' will be replaced with the directory where DSpace is installed
-->
<web-app>
<display-name>DSpace Web UI</display-name>
</web-app>

View File

@@ -0,0 +1,575 @@
/*
* choice-support.js
*
* Version: $Revision: 3705 $
*
* Date: $Date: 2009-04-11 13:02:24 -0400 (Sat, 11 Apr 2009) $
*
* Copyright (c) 2002-2009, The DSpace Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the DSpace Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
// Client-side scripting to support DSpace Choice Control
// IMPORTANT NOTE:
// This code depends on a *MODIFIED* version of the
// script.aculo.us controls v1.8.2, fixed to avoid a bug that
// affects autocomplete in Firefox 3. This code is included in DSpace.
// Entry points:
// 1. DSpaceAutocomplete -- add autocomplete (suggest) to an input field
//
// 2. DSpaceChoiceLookup -- create popup window with authority choices
//
// @Author: Larry Stone <lcs@hulmail.harvard.edu>
// $Revision $
// -------------------- support for Autocomplete (Suggest)
// Autocomplete utility:
// Arguments:
// formID -- ID attribute of form tag
// args properties:
// metadataField -- metadata field e.g. dc_contributor_author
// inputName -- input field name for text input, or base of "Name" pair
// authorityName -- input field name in which to set authority
// containerID -- ID attribute of DIV to hold the menu objects
// indicatorID -- ID attribute of element to use as a "loading" indicator
// confidenceIndicatorID -- ID of element on which to set confidence
// confidenceName - NAME of confidence input (not ID)
// contextPath -- URL path prefix (i.e. webapp contextPath) for DSpace.
// collection -- db ID of dspace collection to serve as context
// isClosed -- true if authority value is required, false = non-auth allowed
// XXX Can't really enforce "isClosed=true" with autocomplete, user can type anything
//
// NOTE: Successful autocomplete always sets confidence to 'accepted' since
// authority value (if any) *was* chosen interactively by a human.
function DSpaceSetupAutocomplete(formID, args)
{
if (args.authorityName == null)
args.authorityName = dspace_makeFieldInput(args.inputName,'_authority');
var form = document.getElementById(formID);
var inputID = form.elements[args.inputName].id;
var authorityID = null;
if (form.elements[args.authorityName] != null)
authorityID = form.elements[args.authorityName].id;
// AJAX menu source, can add &query=TEXT
var choiceURL = args.contextPath+"/choices/"+args.metadataField;
var collID = args.collection == null ? -1 : args.collection;
// field in whcih to store authority value
var options =
{
// class name of spans that contain value in li elements
select: "value",
// make up query args for AJAX callback
parameters: 'collection='+collID+'&format=ul',
callback:
function(inField, querystring) {
return querystring+"&query="+inField.value;
},
// called after target field is updated
afterUpdateElement:
function(ignoreField, li)
{
// NOTE: lookup element late because it might not be in DOM
// at the time we evaluate the function..
var authInput = document.getElementById(authorityID);
var authValue = li == null ? "" : li.getAttribute("authority");
if (authInput != null)
{
authInput.value = authValue;
// update confidence input's value too if available.
if (args.confidenceName != null)
{
var confInput = authInput.form.elements[args.confidenceName];
if (confInput != null)
confInput.value = 'accepted';
}
}
// make indicator blank if no authority value
DSpaceUpdateConfidence(document, args.confidenceIndicatorID,
authValue == null || authValue == '' ? 'blank' :'accepted');
}
};
if (args.indicatorID != null)
options.indicator = args.indicatorID;
// be sure to turn off autocomplete, it absorbs arrow-key events!
form.elements[args.inputName].setAttribute("autocomplete", "off");
new Ajax.Autocompleter(inputID, args.containerID, choiceURL, options);
}
// -------------------- support for Lookup Popup
// Create popup window with authority choices for value of an input field.
// This is intended to be called by onClick of a "Lookup" or "Add" button.
function DSpaceChoiceLookup(url, field, formID, valueInput, authInput,
confIndicatorID, collectionID, isName, isRepeating)
{
// fill in URL
url += '?field='+field+'&formID='+formID+'&valueInput='+valueInput+
'&authorityInput='+authInput+'&collection='+collectionID+
'&isName='+isName+'&isRepeating='+isRepeating+'&confIndicatorID='+confIndicatorID;
// primary input field - for positioning popup.
var inputFieldName = isName ? dspace_makeFieldInput(valueInput,'_last') : valueInput;
var inputField = document.getElementById(formID).elements[inputFieldName];
// scriptactulous magic to figure out true offset:
var cOffset = 0;
if (inputField != null)
cOffset = $(inputField).cumulativeOffset();
var width = 600; // XXX guesses! these should be params, or configured..
var height = 470;
var left; var top;
if (window.screenX == null) {
left = window.screenLeft + cOffset.left - (width/2);
top = window.screenTop + cOffset.top - (height/2);
} else {
left = window.screenX + cOffset.left - (width/2);
top = window.screenY + cOffset.top - (height/2);
}
if (left < 0) left = 0;
if (top < 0) top = 0;
var pw = window.open(url, 'ignoreme',
'width='+width+',height='+height+',left='+left+',top='+top+
',toolbar=no,menubar=no,location=no,status=no,resizable');
if (window.focus) pw.focus();
return false;
}
// Run this as the Lookup page is loaded to initialize DOM objects, load choices
function DSpaceChoicesSetup(form)
{
// find the "LEGEND" in fieldset, which acts as page title,
// and save it as a bogus form element, e.g. elements['statline']
var fieldset = document.getElementById('aspect_general_ChoiceLookupTransformer_list_choicesList');
for (i = 0; i < fieldset.childNodes.length; ++i)
{
if (fieldset.childNodes[i].nodeName == 'LEGEND')
{
form.statline = fieldset.childNodes[i];
form.statline_template = fieldset.childNodes[i].innerHTML;
fieldset.childNodes[i].innerHTML = "Loading...";
break;
}
}
DSpaceChoicesLoad(form);
}
// populate the "select" with options from ajax request
// stash some parameters as properties of the "select" so we can add to
// the last start index to query for next set of results.
function DSpaceChoicesLoad(form)
{
var field = form.elements['paramField'].value;
var value = form.elements['paramValue'].value;
var start = form.elements['paramStart'].value;
var limit = form.elements['paramLimit'].value;
var formID = form.elements['paramFormID'].value;
var collID = form.elements['paramCollection'].value;
var isName = form.elements['paramIsName'].value == 'true';
var isRepeating = form.elements['paramIsRepeating'].value == 'true';
var isClosed = form.elements['paramIsClosed'].value == 'true';
var contextPath = form.elements['contextPath'].value;
var fail = form.elements['paramFail'].value;
var nonAuthority = "";
if (form.elements['paramNonAuthority'] != null)
nonAuthority = form.elements['paramNonAuthority'].value;
// get value from form inputs in opener if not explicitly supplied
if (value.length == 0)
{
var of = window.opener.document.getElementById(formID);
var valueInput = form.elements['paramValueInput'].value;
if (isName)
value = makePersonName(of.elements[dspace_makeFieldInput(valueInput,'_last')].value,
of.elements[dspace_makeFieldInput(valueInput,'_first')].value);
else
value = of.elements[valueInput].value;
}
// start spinner
var indicator = document.getElementById('lookup_indicator_id');
if (indicator != null)
indicator.style.display = "inline";
new Ajax.Request(contextPath+"/choices/"+field,
{
method: "get",
parameters: {query: value, format: 'select', collection: collID,
start: start, limit: limit},
// triggered by any exception, even in success
onException: function(req, e) {
window.alert(fail+" Exception="+e);
if (indicator != null) indicator.style.display = "none";
},
// when http load of choices fails
onFailure: function() {
window.alert(fail+" HTTP error resonse");
if (indicator != null) indicator.style.display = "none";
},
// format is <select><option authority="key" value="val">label</option>...
onSuccess: function(transport) {
var ul = transport.responseXML.firstChild;
var err = ul.getAttributeNode('error');
if (err != null && err.value == 'true')
window.alert(fail+" Server indicates error in response.");
var opts = ul.getElementsByTagName('option');
// update range message and update 'more' button
var oldStart = 1 * ul.getAttributeNode('start').value;
var nextStart = oldStart + opts.length;
var lastTotal = ul.getAttributeNode('total').value;
var resultMore = ul.getAttributeNode('more');
form.elements['more'].disabled = !(resultMore != null && resultMore.value == 'true');
form.elements['paramStart'].value = nextStart;
// clear select first
var select = form.elements['chooser'];
for (var i = select.length-1; i >= 0; --i)
select.remove(i);
// load select and look for default selection
var selectedByValue = -1; // select by value match
var selectedByChoices = -1; // Choice says its selected
for (var i = 0; i < opts.length; ++i)
{
var opt = opts.item(i);
var olabel = "";
for (var j = 0; j < opt.childNodes.length; ++j)
{
var node = opt.childNodes[j];
if (node.nodeName == "#text")
olabel += node.data;
}
var ovalue = opt.getAttributeNode('value').value;
var option = new Option(olabel, ovalue);
option.authority = opt.getAttributeNode('authority').value;
select.add(option, null);
if (value == ovalue)
selectedByValue = select.options.length - 1;
if (opt.getAttributeNode('selected') != null)
selectedByChoices = select.options.length - 1;
}
// add non-authority option if needed.
if (!isClosed)
{
select.add(new Option(dspace_formatMessage(nonAuthority, value), value), null);
}
var defaultSelected = -1;
if (selectedByChoices >= 0)
defaultSelected = selectedByChoices;
else if (selectedByValue >= 0)
defaultSelected = selectedByValue;
else if (select.options.length == 1)
defaultSelected = 0;
// load default-selected value
if (defaultSelected >= 0)
{
select.options[defaultSelected].defaultSelected = true;
var so = select.options[defaultSelected];
if (isName)
{
form.elements['text1'].value = lastNameOf(so.value);
form.elements['text2'].value = firstNameOf(so.value);
}
else
form.elements['text1'].value = so.value;
}
// turn off spinner
if (indicator != null)
indicator.style.display = "none";
// "results" status line
var statLast = nextStart + (isClosed ? 2 : 1);
form.statline.innerHTML =
dspace_formatMessage(form.statline_template,
oldStart+1, statLast, Math.max(lastTotal,statLast), value);
}
});
}
// handler for change event on choice selector - load new values
function DSpaceChoicesSelectOnChange ()
{
// "this" is the window,
var form = document.getElementById('aspect_general_ChoiceLookupTransformer_div_lookup');
var select = form.elements['chooser'];
var so = select.options[select.selectedIndex];
var isName = form.elements['paramIsName'].value == 'true';
if (isName)
{
form.elements['text1'].value = lastNameOf(so.value);
form.elements['text2'].value = firstNameOf(so.value);
}
else
form.elements['text1'].value = so.value;
}
// handler for lookup popup's accept (or add) button
// stuff values back to calling page, force an add if necessary, and close.
function DSpaceChoicesAcceptOnClick ()
{
var select = this.form.elements['chooser'];
var isName = this.form.elements['paramIsName'].value == 'true';
var isRepeating = this.form.elements['paramIsRepeating'].value == 'true';
var valueInput = this.form.elements['paramValueInput'].value;
var authorityInput = this.form.elements['paramAuthorityInput'].value;
var formID = this.form.elements['paramFormID'].value;
var confIndicatorID = this.form.elements['paramConfIndicatorID'] == null?null:this.form.elements['paramConfIndicatorID'].value;
// default the authority input if not supplied.
if (authorityInput.length == 0)
authorityInput = dspace_makeFieldInput(valueInput,'_authority');
// always stuff text fields back into caller's value input(s)
if (valueInput.length > 0)
{
var of = window.opener.document.getElementById(formID);
if (isName)
{
of.elements[dspace_makeFieldInput(valueInput,'_last')].value = this.form.elements['text1'].value;
of.elements[dspace_makeFieldInput(valueInput,'_first')].value = this.form.elements['text2'].value;
}
else
of.elements[valueInput].value = this.form.elements['text1'].value;
if (authorityInput.length > 0 && of.elements[authorityInput] != null)
{
// conf input is auth input, substitute '_confidence' for '_authority'
// if conf fieldname is FIELD_confidence_NUMBER, then '_authority_' => '_confidence_'
var confInput = "";
var ci = authorityInput.lastIndexOf("_authority_");
if (ci < 0)
confInput = authorityInput.substring(0, authorityInput.length-10)+'_confidence';
else
confInput = authorityInput.substring(0, ci)+"_confidence_"+authorityInput.substring(ci+11);
// DEBUG:
// window.alert('Setting fields auth="'+authorityInput+'", conf="'+confInput+'"');
var authValue = null;
if (select.selectedIndex >= 0 && select.options[select.selectedIndex].authority != null)
{
authValue = select.options[select.selectedIndex].authority;
of.elements[authorityInput].value = authValue;
}
if (of.elements[confInput] != null)
of.elements[confInput].value = 'accepted';
// make indicator blank if no authority value
DSpaceUpdateConfidence(window.opener.document, confIndicatorID,
authValue == null || authValue == '' ? 'blank' :'accepted');
}
// force the submit button -- if there is an "add"
if (isRepeating)
{
var add = of.elements["submit_"+valueInput+"_add"];
if (add != null)
add.click();
else
alert('Sanity check: Cannot find button named "submit_'+valueInput+'_add"');
}
}
window.close();
return false;
}
// handler for lookup popup's more button
function DSpaceChoicesMoreOnClick ()
{
DSpaceChoicesLoad(this.form);
}
// handler for lookup popup's cancel button
function DSpaceChoicesCancelOnClick ()
{
window.close();
return false;
}
// -------------------- Utilities
// DSpace person-name conventions, see DCPersonName
function makePersonName(lastName, firstName)
{
return (firstName == null || firstName.length == 0) ? lastName :
lastName+", "+firstName;
}
// DSpace person-name conventions, see DCPersonName
function firstNameOf(personName)
{
var comma = personName.indexOf(",");
return (comma < 0) ? "" : stringTrim(personName.substring(comma+1));
}
// DSpace person-name conventions, see DCPersonName
function lastNameOf(personName)
{
var comma = personName.indexOf(",");
return stringTrim((comma < 0) ? personName : personName.substring(0, comma));
}
// replicate java String.trim()
function stringTrim(str)
{
var start = 0;
var end = str.length;
for (; str.charAt(start) == ' '&& start < end; ++start) ;
for (; end > start && str.charAt(end-1) == ' '; --end) ;
return str.slice(start, end);
}
// format utility - replace @1@, @2@ etc with args 1, 2, 3..
// NOTE params MUST be monotonically increasing
// NOTE we can't use "{1}" like the i18n catalog because it elides them!!
// ...UNLESS maybe it were to be fixed not to when no params...
function dspace_formatMessage()
{
var template = dspace_formatMessage.arguments[0];
var i;
for (i = 1; i < arguments.length; ++i)
{
var pattern = '@'+i+'@';
if (template.search(pattern) >= 0)
template = template.replace(pattern, dspace_formatMessage.arguments[i]);
}
return template;
}
// utility to make sub-field name of input field, e.g. _last, _first, _auth..
// if name ends with _1, _2 etc, put sub-name BEFORE the number
function dspace_makeFieldInput(name, sub)
{
var i = name.search("_[0-9]+$");
if (i < 0)
return name+sub;
else
return name.substr(0, i)+sub+name.substr(i);
}
// update the class value of confidence-indicating element
function DSpaceUpdateConfidence(doc, confIndicatorID, newValue)
{
// sanity checks - need valid ID and a real DOM object
if (confIndicatorID == null || confIndicatorID == "")
return;
var confElt = doc.getElementById(confIndicatorID);
if (confElt == null)
return;
// add or update CSS class with new confidence value, e.g. "cf-accepted".
if (confElt.className == null)
confElt.className = "cf-"+newValue;
else
{
var classes = confElt.className.split(" ");
var newClasses = "";
var found = false;
for (var i = 0; i < classes.length; ++i)
{
if (classes[i].match('^cf-[a-zA-Z0-9]+$'))
{
newClasses += "cf-"+newValue+" ";
found = true;
}
else
newClasses += classes[i]+" ";
}
if (!found)
newClasses += "cf-"+newValue+" ";
confElt.className = newClasses;
}
}
// respond to "onchanged" event on authority input field
// set confidence to 'accepted' if authority was changed by user.
function DSpaceAuthorityOnChange(self, confValueID, confIndicatorID)
{
var confidence = 'accepted';
if (confValueID != null && confValueID != '')
{
var confValueField = document.getElementById(confValueID);
if (confValueField != null)
confValueField.value = confidence;
}
DSpaceUpdateConfidence(document, confIndicatorID, confidence)
return false;
}
// respond to click on the authority-value lock button in Edit Item Metadata:
// "button" is bound to the image input for the lock button, "this"
function DSpaceToggleAuthorityLock(button, authInputID)
{
// sanity checks - need valid ID and a real DOM object
if (authInputID == null || authInputID == '')
return false;
var authInput = document.getElementById(authInputID);
if (authInput == null)
return false;
// look for is-locked or is-unlocked in class list:
var classes = button.className.split(' ');
var newClass = '';
var newLocked = false;
var found = false;
for (var i = 0; i < classes.length; ++i)
{
if (classes[i] == 'is-locked')
{
newLocked = false;
found = true;
}
else if (classes[i] == 'is-unlocked')
{
newLocked = true;
found = true;
}
else
newClass += classes[i]+' ';
}
if (!found)
return false;
// toggle the image, and set readability
button.className = newClass + (newLocked ? 'is-locked' : 'is-unlocked') + ' ';
authInput.readOnly = newLocked;
return false;
}

View File

@@ -0,0 +1,136 @@
// script.aculo.us builder.js v1.8.2, Tue Nov 18 18:30:58 +0100 2008
// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
//
// script.aculo.us is freely distributable under the terms of an MIT-style license.
// For details, see the script.aculo.us web site: http://script.aculo.us/
var Builder = {
NODEMAP: {
AREA: 'map',
CAPTION: 'table',
COL: 'table',
COLGROUP: 'table',
LEGEND: 'fieldset',
OPTGROUP: 'select',
OPTION: 'select',
PARAM: 'object',
TBODY: 'table',
TD: 'table',
TFOOT: 'table',
TH: 'table',
THEAD: 'table',
TR: 'table'
},
// note: For Firefox < 1.5, OPTION and OPTGROUP tags are currently broken,
// due to a Firefox bug
node: function(elementName) {
elementName = elementName.toUpperCase();
// try innerHTML approach
var parentTag = this.NODEMAP[elementName] || 'div';
var parentElement = document.createElement(parentTag);
try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
parentElement.innerHTML = "<" + elementName + "></" + elementName + ">";
} catch(e) {}
var element = parentElement.firstChild || null;
// see if browser added wrapping tags
if(element && (element.tagName.toUpperCase() != elementName))
element = element.getElementsByTagName(elementName)[0];
// fallback to createElement approach
if(!element) element = document.createElement(elementName);
// abort if nothing could be created
if(!element) return;
// attributes (or text)
if(arguments[1])
if(this._isStringOrNumber(arguments[1]) ||
(arguments[1] instanceof Array) ||
arguments[1].tagName) {
this._children(element, arguments[1]);
} else {
var attrs = this._attributes(arguments[1]);
if(attrs.length) {
try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
parentElement.innerHTML = "<" +elementName + " " +
attrs + "></" + elementName + ">";
} catch(e) {}
element = parentElement.firstChild || null;
// workaround firefox 1.0.X bug
if(!element) {
element = document.createElement(elementName);
for(attr in arguments[1])
element[attr == 'class' ? 'className' : attr] = arguments[1][attr];
}
if(element.tagName.toUpperCase() != elementName)
element = parentElement.getElementsByTagName(elementName)[0];
}
}
// text, or array of children
if(arguments[2])
this._children(element, arguments[2]);
return $(element);
},
_text: function(text) {
return document.createTextNode(text);
},
ATTR_MAP: {
'className': 'class',
'htmlFor': 'for'
},
_attributes: function(attributes) {
var attrs = [];
for(attribute in attributes)
attrs.push((attribute in this.ATTR_MAP ? this.ATTR_MAP[attribute] : attribute) +
'="' + attributes[attribute].toString().escapeHTML().gsub(/"/,'&quot;') + '"');
return attrs.join(" ");
},
_children: function(element, children) {
if(children.tagName) {
element.appendChild(children);
return;
}
if(typeof children=='object') { // array can hold nodes and text
children.flatten().each( function(e) {
if(typeof e=='object')
element.appendChild(e);
else
if(Builder._isStringOrNumber(e))
element.appendChild(Builder._text(e));
});
} else
if(Builder._isStringOrNumber(children))
element.appendChild(Builder._text(children));
},
_isStringOrNumber: function(param) {
return(typeof param=='string' || typeof param=='number');
},
build: function(html) {
var element = this.node('div');
$(element).update(html.strip());
return element.down();
},
dump: function(scope) {
if(typeof scope != 'object' && typeof scope != 'function') scope = window; //global scope
var tags = ("A ABBR ACRONYM ADDRESS APPLET AREA B BASE BASEFONT BDO BIG BLOCKQUOTE BODY " +
"BR BUTTON CAPTION CENTER CITE CODE COL COLGROUP DD DEL DFN DIR DIV DL DT EM FIELDSET " +
"FONT FORM FRAME FRAMESET H1 H2 H3 H4 H5 H6 HEAD HR HTML I IFRAME IMG INPUT INS ISINDEX "+
"KBD LABEL LEGEND LI LINK MAP MENU META NOFRAMES NOSCRIPT OBJECT OL OPTGROUP OPTION P "+
"PARAM PRE Q S SAMP SCRIPT SELECT SMALL SPAN STRIKE STRONG STYLE SUB SUP TABLE TBODY TD "+
"TEXTAREA TFOOT TH THEAD TITLE TR TT U UL VAR").split(/\s+/);
tags.each( function(tag){
scope[tag] = function() {
return Builder.node.apply(Builder, [tag].concat($A(arguments)));
};
});
}
};

View File

@@ -0,0 +1,980 @@
// script.aculo.us controls.js v1.8.2, Tue Nov 18 18:30:58 +0100 2008
// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// (c) 2005-2008 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
// (c) 2005-2008 Jon Tirsen (http://www.tirsen.com)
// Contributors:
// Richard Livsey
// Rahul Bhargava
// Rob Wills
//
// script.aculo.us is freely distributable under the terms of an MIT-style license.
// For details, see the script.aculo.us web site: http://script.aculo.us/
// Autocompleter.Base handles all the autocompletion functionality
// that's independent of the data source for autocompletion. This
// includes drawing the autocompletion menu, observing keyboard
// and mouse events, and similar.
//
// Specific autocompleters need to provide, at the very least,
// a getUpdatedChoices function that will be invoked every time
// the text inside the monitored textbox changes. This method
// should get the text for which to provide autocompletion by
// invoking this.getToken(), NOT by directly accessing
// this.element.value. This is to allow incremental tokenized
// autocompletion. Specific auto-completion logic (AJAX, etc)
// belongs in getUpdatedChoices.
//
// Tokenized incremental autocompletion is enabled automatically
// when an autocompleter is instantiated with the 'tokens' option
// in the options parameter, e.g.:
// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' });
// will incrementally autocomplete with a comma as the token.
// Additionally, ',' in the above example can be replaced with
// a token array, e.g. { tokens: [',', '\n'] } which
// enables autocompletion on multiple tokens. This is most
// useful when one of the tokens is \n (a newline), as it
// allows smart autocompletion after linebreaks.
if(typeof Effect == 'undefined')
throw("controls.js requires including script.aculo.us' effects.js library");
var Autocompleter = { };
Autocompleter.Base = Class.create({
baseInitialize: function(element, update, options) {
element = $(element);
this.element = element;
this.update = $(update);
this.hasFocus = false;
this.changed = false;
this.active = false;
this.index = 0;
this.entryCount = 0;
this.oldElementValue = this.element.value;
if(this.setOptions)
this.setOptions(options);
else
this.options = options || { };
this.options.paramName = this.options.paramName || this.element.name;
this.options.tokens = this.options.tokens || [];
this.options.frequency = this.options.frequency || 0.4;
this.options.minChars = this.options.minChars || 1;
this.options.onShow = this.options.onShow ||
function(element, update){
if(!update.style.position || update.style.position=='absolute') {
update.style.position = 'absolute';
Position.clone(element, update, {
setHeight: false,
offsetTop: element.offsetHeight
});
}
Effect.Appear(update,{duration:0.15});
};
this.options.onHide = this.options.onHide ||
function(element, update){ new Effect.Fade(update,{duration:0.15}) };
if(typeof(this.options.tokens) == 'string')
this.options.tokens = new Array(this.options.tokens);
// Force carriage returns as token delimiters anyway
if (!this.options.tokens.include('\n'))
this.options.tokens.push('\n');
this.observer = null;
this.element.setAttribute('autocomplete','off');
Element.hide(this.update);
Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this));
Event.observe(this.element, 'keydown', this.onKeyPress.bindAsEventListener(this));
},
show: function() {
if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update);
if(!this.iefix &&
(Prototype.Browser.IE) &&
(Element.getStyle(this.update, 'position')=='absolute')) {
new Insertion.After(this.update,
'<iframe id="' + this.update.id + '_iefix" '+
'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' +
'src="javascript:false;" frameborder="0" scrolling="no"></iframe>');
this.iefix = $(this.update.id+'_iefix');
}
if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50);
},
fixIEOverlapping: function() {
Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)});
this.iefix.style.zIndex = 1;
this.update.style.zIndex = 2;
Element.show(this.iefix);
},
hide: function() {
this.stopIndicator();
if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update);
if(this.iefix) Element.hide(this.iefix);
},
startIndicator: function() {
if(this.options.indicator) Element.show(this.options.indicator);
},
stopIndicator: function() {
if(this.options.indicator) Element.hide(this.options.indicator);
},
onKeyPress: function(event) {
if(this.active)
switch(event.keyCode) {
case Event.KEY_TAB:
case Event.KEY_RETURN:
this.selectEntry();
Event.stop(event);
case Event.KEY_ESC:
this.hide();
this.active = false;
Event.stop(event);
return;
case Event.KEY_LEFT:
case Event.KEY_RIGHT:
return;
case Event.KEY_UP:
this.markPrevious();
this.render();
Event.stop(event);
return;
case Event.KEY_DOWN:
this.markNext();
this.render();
Event.stop(event);
return;
}
else
if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN ||
(Prototype.Browser.WebKit > 0 && event.keyCode == 0)) return;
this.changed = true;
this.hasFocus = true;
if(this.observer) clearTimeout(this.observer);
this.observer =
setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000);
},
activate: function() {
this.changed = false;
this.hasFocus = true;
this.getUpdatedChoices();
},
onHover: function(event) {
var element = Event.findElement(event, 'LI');
if(this.index != element.autocompleteIndex)
{
this.index = element.autocompleteIndex;
this.render();
}
Event.stop(event);
},
onClick: function(event) {
var element = Event.findElement(event, 'LI');
this.index = element.autocompleteIndex;
this.selectEntry();
this.hide();
},
onBlur: function(event) {
// needed to make click events working
setTimeout(this.hide.bind(this), 250);
this.hasFocus = false;
this.active = false;
},
render: function() {
if(this.entryCount > 0) {
for (var i = 0; i < this.entryCount; i++)
this.index==i ?
Element.addClassName(this.getEntry(i),"selected") :
Element.removeClassName(this.getEntry(i),"selected");
if(this.hasFocus) {
this.show();
this.active = true;
}
} else {
this.active = false;
this.hide();
}
},
markPrevious: function() {
if(this.index > 0) this.index--;
else {
this.index = this.entryCount-1;
this.update.scrollTop = this.update.scrollHeight;
}
selection = this.getEntry(this.index);
selection_top = selection.offsetTop;
if(selection_top < this.update.scrollTop){
this.update.scrollTop = this.update.scrollTop-selection.offsetHeight;
}
},
markNext: function() {
if(this.index < this.entryCount-1) this.index++;
else {
this.index = 0;
this.update.scrollTop = 0;
}
selection = this.getEntry(this.index);
selection_bottom = selection.offsetTop+selection.offsetHeight;
if(selection_bottom > this.update.scrollTop+this.update.offsetHeight){
this.update.scrollTop = this.update.scrollTop+selection.offsetHeight;
}
},
getEntry: function(index) {
return this.update.firstChild.childNodes[index];
},
getCurrentEntry: function() {
return this.getEntry(this.index);
},
selectEntry: function() {
this.active = false;
this.updateElement(this.getCurrentEntry());
},
updateElement: function(selectedElement) {
if (this.options.updateElement) {
this.options.updateElement(selectedElement);
return;
}
var value = '';
if (this.options.select) {
var nodes = $(selectedElement).select('.' + this.options.select) || [];
if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select);
} else
value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
var bounds = this.getTokenBounds();
if (bounds[0] != -1) {
var newValue = this.element.value.substr(0, bounds[0]);
var whitespace = this.element.value.substr(bounds[0]).match(/^\s+/);
if (whitespace)
newValue += whitespace[0];
this.element.value = newValue + value + this.element.value.substr(bounds[1]);
} else {
this.element.value = value;
}
this.oldElementValue = this.element.value;
this.element.focus();
if (this.options.afterUpdateElement)
this.options.afterUpdateElement(this.element, selectedElement);
},
updateChoices: function(choices) {
if(!this.changed && this.hasFocus) {
this.update.innerHTML = choices;
Element.cleanWhitespace(this.update);
Element.cleanWhitespace(this.update.down());
if(this.update.firstChild && this.update.down().childNodes) {
this.entryCount =
this.update.down().childNodes.length;
for (var i = 0; i < this.entryCount; i++) {
var entry = this.getEntry(i);
entry.autocompleteIndex = i;
this.addObservers(entry);
}
} else {
this.entryCount = 0;
}
this.stopIndicator();
this.update.scrollTop = 0;
this.index = 0;
if(this.entryCount==1 && this.options.autoSelect) {
this.selectEntry();
this.hide();
} else {
this.render();
}
}
},
addObservers: function(element) {
Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this));
Event.observe(element, "click", this.onClick.bindAsEventListener(this));
},
onObserverEvent: function() {
this.changed = false;
this.tokenBounds = null;
if(this.getToken().length>=this.options.minChars) {
this.getUpdatedChoices();
} else {
this.active = false;
this.hide();
}
this.oldElementValue = this.element.value;
},
getToken: function() {
var bounds = this.getTokenBounds();
return this.element.value.substring(bounds[0], bounds[1]).strip();
},
getTokenBounds: function() {
if (null != this.tokenBounds) return this.tokenBounds;
var value = this.element.value;
if (value.strip().empty()) return [-1, 0];
var diff = arguments.callee.getFirstDifferencePos(value, this.oldElementValue);
var offset = (diff == this.oldElementValue.length ? 1 : 0);
var prevTokenPos = -1, nextTokenPos = value.length;
var tp;
for (var index = 0, l = this.options.tokens.length; index < l; ++index) {
tp = value.lastIndexOf(this.options.tokens[index], diff + offset - 1);
if (tp > prevTokenPos) prevTokenPos = tp;
tp = value.indexOf(this.options.tokens[index], diff + offset);
if (-1 != tp && tp < nextTokenPos) nextTokenPos = tp;
}
return (this.tokenBounds = [prevTokenPos + 1, nextTokenPos]);
}
});
Autocompleter.Base.prototype.getTokenBounds.getFirstDifferencePos = function(newS, oldS) {
var boundary = Math.min(newS.length, oldS.length);
for (var index = 0; index < boundary; ++index)
if (newS[index] != oldS[index])
return index;
return boundary;
};
Ajax.Autocompleter = Class.create(Autocompleter.Base, {
initialize: function(element, update, url, options) {
this.baseInitialize(element, update, options);
this.options.asynchronous = true;
this.options.onComplete = this.onComplete.bind(this);
this.options.defaultParams = this.options.parameters || null;
this.url = url;
},
getUpdatedChoices: function() {
this.startIndicator();
var entry = encodeURIComponent(this.options.paramName) + '=' +
encodeURIComponent(this.getToken());
this.options.parameters = this.options.callback ?
this.options.callback(this.element, entry) : entry;
if(this.options.defaultParams)
this.options.parameters += '&' + this.options.defaultParams;
new Ajax.Request(this.url, this.options);
},
onComplete: function(request) {
this.updateChoices(request.responseText);
}
});
// The local array autocompleter. Used when you'd prefer to
// inject an array of autocompletion options into the page, rather
// than sending out Ajax queries, which can be quite slow sometimes.
//
// The constructor takes four parameters. The first two are, as usual,
// the id of the monitored textbox, and id of the autocompletion menu.
// The third is the array you want to autocomplete from, and the fourth
// is the options block.
//
// Extra local autocompletion options:
// - choices - How many autocompletion choices to offer
//
// - partialSearch - If false, the autocompleter will match entered
// text only at the beginning of strings in the
// autocomplete array. Defaults to true, which will
// match text at the beginning of any *word* in the
// strings in the autocomplete array. If you want to
// search anywhere in the string, additionally set
// the option fullSearch to true (default: off).
//
// - fullSsearch - Search anywhere in autocomplete array strings.
//
// - partialChars - How many characters to enter before triggering
// a partial match (unlike minChars, which defines
// how many characters are required to do any match
// at all). Defaults to 2.
//
// - ignoreCase - Whether to ignore case when autocompleting.
// Defaults to true.
//
// It's possible to pass in a custom function as the 'selector'
// option, if you prefer to write your own autocompletion logic.
// In that case, the other options above will not apply unless
// you support them.
Autocompleter.Local = Class.create(Autocompleter.Base, {
initialize: function(element, update, array, options) {
this.baseInitialize(element, update, options);
this.options.array = array;
},
getUpdatedChoices: function() {
this.updateChoices(this.options.selector(this));
},
setOptions: function(options) {
this.options = Object.extend({
choices: 10,
partialSearch: true,
partialChars: 2,
ignoreCase: true,
fullSearch: false,
selector: function(instance) {
var ret = []; // Beginning matches
var partial = []; // Inside matches
var entry = instance.getToken();
var count = 0;
for (var i = 0; i < instance.options.array.length &&
ret.length < instance.options.choices ; i++) {
var elem = instance.options.array[i];
var foundPos = instance.options.ignoreCase ?
elem.toLowerCase().indexOf(entry.toLowerCase()) :
elem.indexOf(entry);
while (foundPos != -1) {
if (foundPos == 0 && elem.length != entry.length) {
ret.push("<li><strong>" + elem.substr(0, entry.length) + "</strong>" +
elem.substr(entry.length) + "</li>");
break;
} else if (entry.length >= instance.options.partialChars &&
instance.options.partialSearch && foundPos != -1) {
if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) {
partial.push("<li>" + elem.substr(0, foundPos) + "<strong>" +
elem.substr(foundPos, entry.length) + "</strong>" + elem.substr(
foundPos + entry.length) + "</li>");
break;
}
}
foundPos = instance.options.ignoreCase ?
elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) :
elem.indexOf(entry, foundPos + 1);
}
}
if (partial.length)
ret = ret.concat(partial.slice(0, instance.options.choices - ret.length));
return "<ul>" + ret.join('') + "</ul>";
}
}, options || { });
}
});
// AJAX in-place editor and collection editor
// Full rewrite by Christophe Porteneuve <tdd@tddsworld.com> (April 2007).
// Use this if you notice weird scrolling problems on some browsers,
// the DOM might be a bit confused when this gets called so do this
// waits 1 ms (with setTimeout) until it does the activation
Field.scrollFreeActivate = function(field) {
setTimeout(function() {
Field.activate(field);
}, 1);
};
Ajax.InPlaceEditor = Class.create({
initialize: function(element, url, options) {
this.url = url;
this.element = element = $(element);
this.prepareOptions();
this._controls = { };
arguments.callee.dealWithDeprecatedOptions(options); // DEPRECATION LAYER!!!
Object.extend(this.options, options || { });
if (!this.options.formId && this.element.id) {
this.options.formId = this.element.id + '-inplaceeditor';
if ($(this.options.formId))
this.options.formId = '';
}
if (this.options.externalControl)
this.options.externalControl = $(this.options.externalControl);
if (!this.options.externalControl)
this.options.externalControlOnly = false;
this._originalBackground = this.element.getStyle('background-color') || 'transparent';
this.element.title = this.options.clickToEditText;
this._boundCancelHandler = this.handleFormCancellation.bind(this);
this._boundComplete = (this.options.onComplete || Prototype.emptyFunction).bind(this);
this._boundFailureHandler = this.handleAJAXFailure.bind(this);
this._boundSubmitHandler = this.handleFormSubmission.bind(this);
this._boundWrapperHandler = this.wrapUp.bind(this);
this.registerListeners();
},
checkForEscapeOrReturn: function(e) {
if (!this._editing || e.ctrlKey || e.altKey || e.shiftKey) return;
if (Event.KEY_ESC == e.keyCode)
this.handleFormCancellation(e);
else if (Event.KEY_RETURN == e.keyCode)
this.handleFormSubmission(e);
},
createControl: function(mode, handler, extraClasses) {
var control = this.options[mode + 'Control'];
var text = this.options[mode + 'Text'];
if ('button' == control) {
var btn = document.createElement('input');
btn.type = 'submit';
btn.value = text;
btn.className = 'editor_' + mode + '_button';
if ('cancel' == mode)
btn.onclick = this._boundCancelHandler;
this._form.appendChild(btn);
this._controls[mode] = btn;
} else if ('link' == control) {
var link = document.createElement('a');
link.href = '#';
link.appendChild(document.createTextNode(text));
link.onclick = 'cancel' == mode ? this._boundCancelHandler : this._boundSubmitHandler;
link.className = 'editor_' + mode + '_link';
if (extraClasses)
link.className += ' ' + extraClasses;
this._form.appendChild(link);
this._controls[mode] = link;
}
},
createEditField: function() {
var text = (this.options.loadTextURL ? this.options.loadingText : this.getText());
var fld;
if (1 >= this.options.rows && !/\r|\n/.test(this.getText())) {
fld = document.createElement('input');
fld.type = 'text';
var size = this.options.size || this.options.cols || 0;
if (0 < size) fld.size = size;
} else {
fld = document.createElement('textarea');
fld.rows = (1 >= this.options.rows ? this.options.autoRows : this.options.rows);
fld.cols = this.options.cols || 40;
}
fld.name = this.options.paramName;
fld.value = text; // No HTML breaks conversion anymore
fld.className = 'editor_field';
if (this.options.submitOnBlur)
fld.onblur = this._boundSubmitHandler;
this._controls.editor = fld;
if (this.options.loadTextURL)
this.loadExternalText();
this._form.appendChild(this._controls.editor);
},
createForm: function() {
var ipe = this;
function addText(mode, condition) {
var text = ipe.options['text' + mode + 'Controls'];
if (!text || condition === false) return;
ipe._form.appendChild(document.createTextNode(text));
};
this._form = $(document.createElement('form'));
this._form.id = this.options.formId;
this._form.addClassName(this.options.formClassName);
this._form.onsubmit = this._boundSubmitHandler;
this.createEditField();
if ('textarea' == this._controls.editor.tagName.toLowerCase())
this._form.appendChild(document.createElement('br'));
if (this.options.onFormCustomization)
this.options.onFormCustomization(this, this._form);
addText('Before', this.options.okControl || this.options.cancelControl);
this.createControl('ok', this._boundSubmitHandler);
addText('Between', this.options.okControl && this.options.cancelControl);
this.createControl('cancel', this._boundCancelHandler, 'editor_cancel');
addText('After', this.options.okControl || this.options.cancelControl);
},
destroy: function() {
if (this._oldInnerHTML)
this.element.innerHTML = this._oldInnerHTML;
this.leaveEditMode();
this.unregisterListeners();
},
enterEditMode: function(e) {
if (this._saving || this._editing) return;
this._editing = true;
this.triggerCallback('onEnterEditMode');
if (this.options.externalControl)
this.options.externalControl.hide();
this.element.hide();
this.createForm();
this.element.parentNode.insertBefore(this._form, this.element);
if (!this.options.loadTextURL)
this.postProcessEditField();
if (e) Event.stop(e);
},
enterHover: function(e) {
if (this.options.hoverClassName)
this.element.addClassName(this.options.hoverClassName);
if (this._saving) return;
this.triggerCallback('onEnterHover');
},
getText: function() {
return this.element.innerHTML.unescapeHTML();
},
handleAJAXFailure: function(transport) {
this.triggerCallback('onFailure', transport);
if (this._oldInnerHTML) {
this.element.innerHTML = this._oldInnerHTML;
this._oldInnerHTML = null;
}
},
handleFormCancellation: function(e) {
this.wrapUp();
if (e) Event.stop(e);
},
handleFormSubmission: function(e) {
var form = this._form;
var value = $F(this._controls.editor);
this.prepareSubmission();
var params = this.options.callback(form, value) || '';
if (Object.isString(params))
params = params.toQueryParams();
params.editorId = this.element.id;
if (this.options.htmlResponse) {
var options = Object.extend({ evalScripts: true }, this.options.ajaxOptions);
Object.extend(options, {
parameters: params,
onComplete: this._boundWrapperHandler,
onFailure: this._boundFailureHandler
});
new Ajax.Updater({ success: this.element }, this.url, options);
} else {
var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
Object.extend(options, {
parameters: params,
onComplete: this._boundWrapperHandler,
onFailure: this._boundFailureHandler
});
new Ajax.Request(this.url, options);
}
if (e) Event.stop(e);
},
leaveEditMode: function() {
this.element.removeClassName(this.options.savingClassName);
this.removeForm();
this.leaveHover();
this.element.style.backgroundColor = this._originalBackground;
this.element.show();
if (this.options.externalControl)
this.options.externalControl.show();
this._saving = false;
this._editing = false;
this._oldInnerHTML = null;
this.triggerCallback('onLeaveEditMode');
},
leaveHover: function(e) {
if (this.options.hoverClassName)
this.element.removeClassName(this.options.hoverClassName);
if (this._saving) return;
this.triggerCallback('onLeaveHover');
},
loadExternalText: function() {
this._form.addClassName(this.options.loadingClassName);
this._controls.editor.disabled = true;
var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
Object.extend(options, {
parameters: 'editorId=' + encodeURIComponent(this.element.id),
onComplete: Prototype.emptyFunction,
onSuccess: function(transport) {
this._form.removeClassName(this.options.loadingClassName);
var text = transport.responseText;
if (this.options.stripLoadedTextTags)
text = text.stripTags();
this._controls.editor.value = text;
this._controls.editor.disabled = false;
this.postProcessEditField();
}.bind(this),
onFailure: this._boundFailureHandler
});
new Ajax.Request(this.options.loadTextURL, options);
},
postProcessEditField: function() {
var fpc = this.options.fieldPostCreation;
if (fpc)
$(this._controls.editor)['focus' == fpc ? 'focus' : 'activate']();
},
prepareOptions: function() {
this.options = Object.clone(Ajax.InPlaceEditor.DefaultOptions);
Object.extend(this.options, Ajax.InPlaceEditor.DefaultCallbacks);
[this._extraDefaultOptions].flatten().compact().each(function(defs) {
Object.extend(this.options, defs);
}.bind(this));
},
prepareSubmission: function() {
this._saving = true;
this.removeForm();
this.leaveHover();
this.showSaving();
},
registerListeners: function() {
this._listeners = { };
var listener;
$H(Ajax.InPlaceEditor.Listeners).each(function(pair) {
listener = this[pair.value].bind(this);
this._listeners[pair.key] = listener;
if (!this.options.externalControlOnly)
this.element.observe(pair.key, listener);
if (this.options.externalControl)
this.options.externalControl.observe(pair.key, listener);
}.bind(this));
},
removeForm: function() {
if (!this._form) return;
this._form.remove();
this._form = null;
this._controls = { };
},
showSaving: function() {
this._oldInnerHTML = this.element.innerHTML;
this.element.innerHTML = this.options.savingText;
this.element.addClassName(this.options.savingClassName);
this.element.style.backgroundColor = this._originalBackground;
this.element.show();
},
triggerCallback: function(cbName, arg) {
if ('function' == typeof this.options[cbName]) {
this.options[cbName](this, arg);
}
},
unregisterListeners: function() {
$H(this._listeners).each(function(pair) {
if (!this.options.externalControlOnly)
this.element.stopObserving(pair.key, pair.value);
if (this.options.externalControl)
this.options.externalControl.stopObserving(pair.key, pair.value);
}.bind(this));
},
wrapUp: function(transport) {
this.leaveEditMode();
// Can't use triggerCallback due to backward compatibility: requires
// binding + direct element
this._boundComplete(transport, this.element);
}
});
Object.extend(Ajax.InPlaceEditor.prototype, {
dispose: Ajax.InPlaceEditor.prototype.destroy
});
Ajax.InPlaceCollectionEditor = Class.create(Ajax.InPlaceEditor, {
initialize: function($super, element, url, options) {
this._extraDefaultOptions = Ajax.InPlaceCollectionEditor.DefaultOptions;
$super(element, url, options);
},
createEditField: function() {
var list = document.createElement('select');
list.name = this.options.paramName;
list.size = 1;
this._controls.editor = list;
this._collection = this.options.collection || [];
if (this.options.loadCollectionURL)
this.loadCollection();
else
this.checkForExternalText();
this._form.appendChild(this._controls.editor);
},
loadCollection: function() {
this._form.addClassName(this.options.loadingClassName);
this.showLoadingText(this.options.loadingCollectionText);
var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
Object.extend(options, {
parameters: 'editorId=' + encodeURIComponent(this.element.id),
onComplete: Prototype.emptyFunction,
onSuccess: function(transport) {
var js = transport.responseText.strip();
if (!/^\[.*\]$/.test(js)) // TODO: improve sanity check
throw('Server returned an invalid collection representation.');
this._collection = eval(js);
this.checkForExternalText();
}.bind(this),
onFailure: this.onFailure
});
new Ajax.Request(this.options.loadCollectionURL, options);
},
showLoadingText: function(text) {
this._controls.editor.disabled = true;
var tempOption = this._controls.editor.firstChild;
if (!tempOption) {
tempOption = document.createElement('option');
tempOption.value = '';
this._controls.editor.appendChild(tempOption);
tempOption.selected = true;
}
tempOption.update((text || '').stripScripts().stripTags());
},
checkForExternalText: function() {
this._text = this.getText();
if (this.options.loadTextURL)
this.loadExternalText();
else
this.buildOptionList();
},
loadExternalText: function() {
this.showLoadingText(this.options.loadingText);
var options = Object.extend({ method: 'get' }, this.options.ajaxOptions);
Object.extend(options, {
parameters: 'editorId=' + encodeURIComponent(this.element.id),
onComplete: Prototype.emptyFunction,
onSuccess: function(transport) {
this._text = transport.responseText.strip();
this.buildOptionList();
}.bind(this),
onFailure: this.onFailure
});
new Ajax.Request(this.options.loadTextURL, options);
},
buildOptionList: function() {
this._form.removeClassName(this.options.loadingClassName);
this._collection = this._collection.map(function(entry) {
return 2 === entry.length ? entry : [entry, entry].flatten();
});
var marker = ('value' in this.options) ? this.options.value : this._text;
var textFound = this._collection.any(function(entry) {
return entry[0] == marker;
}.bind(this));
this._controls.editor.update('');
var option;
this._collection.each(function(entry, index) {
option = document.createElement('option');
option.value = entry[0];
option.selected = textFound ? entry[0] == marker : 0 == index;
option.appendChild(document.createTextNode(entry[1]));
this._controls.editor.appendChild(option);
}.bind(this));
this._controls.editor.disabled = false;
Field.scrollFreeActivate(this._controls.editor);
}
});
//**** DEPRECATION LAYER FOR InPlace[Collection]Editor! ****
//**** This only exists for a while, in order to let ****
//**** users adapt to the new API. Read up on the new ****
//**** API and convert your code to it ASAP! ****
Ajax.InPlaceEditor.prototype.initialize.dealWithDeprecatedOptions = function(options) {
if (!options) return;
function fallback(name, expr) {
if (name in options || expr === undefined) return;
options[name] = expr;
};
fallback('cancelControl', (options.cancelLink ? 'link' : (options.cancelButton ? 'button' :
options.cancelLink == options.cancelButton == false ? false : undefined)));
fallback('okControl', (options.okLink ? 'link' : (options.okButton ? 'button' :
options.okLink == options.okButton == false ? false : undefined)));
fallback('highlightColor', options.highlightcolor);
fallback('highlightEndColor', options.highlightendcolor);
};
Object.extend(Ajax.InPlaceEditor, {
DefaultOptions: {
ajaxOptions: { },
autoRows: 3, // Use when multi-line w/ rows == 1
cancelControl: 'link', // 'link'|'button'|false
cancelText: 'cancel',
clickToEditText: 'Click to edit',
externalControl: null, // id|elt
externalControlOnly: false,
fieldPostCreation: 'activate', // 'activate'|'focus'|false
formClassName: 'inplaceeditor-form',
formId: null, // id|elt
highlightColor: '#ffff99',
highlightEndColor: '#ffffff',
hoverClassName: '',
htmlResponse: true,
loadingClassName: 'inplaceeditor-loading',
loadingText: 'Loading...',
okControl: 'button', // 'link'|'button'|false
okText: 'ok',
paramName: 'value',
rows: 1, // If 1 and multi-line, uses autoRows
savingClassName: 'inplaceeditor-saving',
savingText: 'Saving...',
size: 0,
stripLoadedTextTags: false,
submitOnBlur: false,
textAfterControls: '',
textBeforeControls: '',
textBetweenControls: ''
},
DefaultCallbacks: {
callback: function(form) {
return Form.serialize(form);
},
onComplete: function(transport, element) {
// For backward compatibility, this one is bound to the IPE, and passes
// the element directly. It was too often customized, so we don't break it.
new Effect.Highlight(element, {
startcolor: this.options.highlightColor, keepBackgroundImage: true });
},
onEnterEditMode: null,
onEnterHover: function(ipe) {
ipe.element.style.backgroundColor = ipe.options.highlightColor;
if (ipe._effect)
ipe._effect.cancel();
},
onFailure: function(transport, ipe) {
alert('Error communication with the server: ' + transport.responseText.stripTags());
},
onFormCustomization: null, // Takes the IPE and its generated form, after editor, before controls.
onLeaveEditMode: null,
onLeaveHover: function(ipe) {
ipe._effect = new Effect.Highlight(ipe.element, {
startcolor: ipe.options.highlightColor, endcolor: ipe.options.highlightEndColor,
restorecolor: ipe._originalBackground, keepBackgroundImage: true
});
}
},
Listeners: {
click: 'enterEditMode',
keydown: 'checkForEscapeOrReturn',
mouseover: 'enterHover',
mouseout: 'leaveHover'
}
});
Ajax.InPlaceCollectionEditor.DefaultOptions = {
loadingCollectionText: 'Loading options...'
};
// Delayed observer, like Form.Element.Observer,
// but waits for delay after last key input
// Ideal for live-search fields
Form.Element.DelayedObserver = Class.create({
initialize: function(element, delay, callback) {
this.delay = delay || 0.5;
this.element = $(element);
this.callback = callback;
this.timer = null;
this.lastValue = $F(this.element);
Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this));
},
delayedListener: function(event) {
if(this.lastValue == $F(this.element)) return;
if(this.timer) clearTimeout(this.timer);
this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000);
this.lastValue = $F(this.element);
},
onTimerEvent: function() {
this.timer = null;
this.callback(this.element, $F(this.element));
}
});

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -5,8 +5,7 @@
*
* Date: $Date$
*
* Copyright (c) 2002, Hewlett-Packard Company and Massachusetts
* Institute of Technology. All rights reserved.
* Copyright (c) 2002-2009, The DSpace Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -19,8 +18,7 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Hewlett-Packard Company nor the name of the
* Massachusetts Institute of Technology nor the names of their
* - Neither the name of the DSpace Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
@@ -36,7 +34,8 @@
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/package org.dspace.app.xmlui.aspect.administrative;
*/
package org.dspace.app.xmlui.aspect.administrative;
import java.io.IOException;
import java.io.InputStream;
@@ -59,6 +58,7 @@ import org.dspace.content.FormatIdentifier;
import org.dspace.content.Item;
import org.dspace.content.MetadataField;
import org.dspace.content.MetadataSchema;
import org.dspace.content.authority.Choices;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.handle.HandleManager;
@@ -213,6 +213,8 @@ public class FlowItemUtils
{
String name = request.getParameter("name_"+index);
String value = request.getParameter("value_"+index);
String authority = request.getParameter("value_"+index+"_authority");
String confidence = request.getParameter("value_"+index+"_confidence");
String lang = request.getParameter("language_"+index);
String remove = request.getParameter("remove_"+index);
@@ -223,8 +225,15 @@ public class FlowItemUtils
// get the field's name broken up
String[] parts = parseName(name);
// Add the metadata back in.
item.addMetadata(parts[0], parts[1], parts[2], lang, value);
// probe for a confidence value
int iconf = Choices.CF_UNSET;
if (confidence != null && confidence.length() > 0)
iconf = Choices.getConfidenceValue(confidence);
// upgrade to a minimum of NOVALUE if there IS an authority key
if (authority != null && authority.length() > 0 && iconf == Choices.CF_UNSET)
iconf = Choices.CF_NOVALUE;
item.addMetadata(parts[0], parts[1], parts[2], lang,
value, authority, iconf);
}
item.update();

View File

@@ -210,9 +210,9 @@ public class WithdrawnItems extends AbstractDSpaceTransformer implements
else
{
// Add the metadata to the validity
for (String singleEntry : browseInfo.getStringResults())
for (String[] singleEntry : browseInfo.getStringResults())
{
validity.add(singleEntry);
validity.add(singleEntry[0]+"#"+singleEntry[1]);
}
}
}
@@ -310,16 +310,24 @@ public class WithdrawnItems extends AbstractDSpaceTransformer implements
message("xmlui.ArtifactBrowser.ConfigurableBrowse." + type + ".column_heading"));
// Iterate each result
for (String singleEntry : browseInfo.getStringResults())
for (String[] singleEntry : browseInfo.getStringResults())
{
// Create a Map of the query parameters for the link
Map<String, String> queryParams = new HashMap<String, String>();
queryParams.put(BrowseParams.TYPE, URLEncode(type));
queryParams.put(BrowseParams.FILTER_VALUE, URLEncode(singleEntry));
if (singleEntry[1] != null)
{
queryParams.put(BrowseParams.FILTER_VALUE[1], URLEncode(
singleEntry[1]));
}
else
{
queryParams.put(BrowseParams.FILTER_VALUE[0], URLEncode(
singleEntry[0]));
}
// Create an entry in the table, and a linked entry
Cell cell = singleTable.addRow().addCell();
cell.addXref(super.generateURL(WITHDRAWN_URL_BASE, queryParams), singleEntry);
cell.addXref(super.generateURL(WITHDRAWN_URL_BASE, queryParams), singleEntry[0]);
}
}
}
@@ -623,7 +631,16 @@ public class WithdrawnItems extends AbstractDSpaceTransformer implements
params.scope.setResultsPerPage(RequestUtils.getIntParameter(request,
BrowseParams.RESULTS_PER_PAGE));
params.scope.setStartsWith(request.getParameter(BrowseParams.STARTS_WITH));
params.scope.setFilterValue(request.getParameter(BrowseParams.FILTER_VALUE));
String filterValue = request.getParameter(BrowseParams.FILTER_VALUE[0]);
if (filterValue == null)
{
filterValue = request.getParameter(BrowseParams.FILTER_VALUE[1]);
}
else
{
params.scope.setAuthorityValue(filterValue);
}
params.scope.setFilterValue(filterValue);
params.scope.setJumpToValue(request.getParameter(BrowseParams.JUMPTO_VALUE));
params.scope.setJumpToValueLang(request.getParameter(BrowseParams.JUMPTO_VALUE_LANG));
params.scope.setFilterValueLang(request.getParameter(BrowseParams.FILTER_VALUE_LANG));
@@ -863,7 +880,7 @@ class BrowseParams
final static String STARTS_WITH = "starts_with";
final static String FILTER_VALUE = "value";
final static String[] FILTER_VALUE = new String[]{"value","authority"};
final static String FILTER_VALUE_LANG = "value_lang";
@@ -877,7 +894,9 @@ class BrowseParams
if (scope.getFilterValue() != null)
{
paramMap.put(BrowseParams.FILTER_VALUE, AbstractDSpaceTransformer.URLEncode(
paramMap.put(scope.getAuthorityValue() != null?
BrowseParams.FILTER_VALUE[1]:BrowseParams.FILTER_VALUE[0],
AbstractDSpaceTransformer.URLEncode(
scope.getFilterValue()));
}

View File

@@ -5,8 +5,7 @@
*
* Date: $Date$
*
* Copyright (c) 2002, Hewlett-Packard Company and Massachusetts
* Institute of Technology. All rights reserved.
* Copyright (c) 2002-2009, The DSpace Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -19,8 +18,7 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Hewlett-Packard Company nor the name of the
* Massachusetts Institute of Technology nor the names of their
* - Neither the name of the DSpace Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
@@ -49,6 +47,7 @@ import org.dspace.app.xmlui.cocoon.AbstractDSpaceTransformer;
import org.dspace.app.xmlui.wing.Message;
import org.dspace.app.xmlui.wing.WingException;
import org.dspace.app.xmlui.wing.element.Body;
import org.dspace.app.xmlui.wing.element.Button;
import org.dspace.app.xmlui.wing.element.Cell;
import org.dspace.app.xmlui.wing.element.CheckBox;
import org.dspace.app.xmlui.wing.element.Composite;
@@ -56,16 +55,22 @@ import org.dspace.app.xmlui.wing.element.Division;
import org.dspace.app.xmlui.wing.element.List;
import org.dspace.app.xmlui.wing.element.PageMeta;
import org.dspace.app.xmlui.wing.element.Para;
import org.dspace.app.xmlui.wing.element.Params;
import org.dspace.app.xmlui.wing.element.Row;
import org.dspace.app.xmlui.wing.element.Select;
import org.dspace.app.xmlui.wing.element.Table;
import org.dspace.app.xmlui.wing.element.Text;
import org.dspace.app.xmlui.wing.element.TextArea;
import org.dspace.app.xmlui.wing.element.Value;
import org.dspace.content.Collection;
import org.dspace.content.DCValue;
import org.dspace.content.Item;
import org.dspace.content.MetadataField;
import org.dspace.content.MetadataSchema;
import org.dspace.content.authority.MetadataAuthorityManager;
import org.dspace.content.authority.ChoiceAuthorityManager;
import org.dspace.content.authority.Choice;
import org.dspace.content.authority.Choices;
/**
* Display a list of all metadata available for this item and allow the user to
@@ -104,12 +109,15 @@ public class EditItemMetadataForm extends AbstractDSpaceTransformer {
private static final Message T_column2 = message("xmlui.administrative.item.EditItemMetadataForm.column2");
private static final Message T_column3 = message("xmlui.administrative.item.EditItemMetadataForm.column3");
private static final Message T_column4 = message("xmlui.administrative.item.EditItemMetadataForm.column4");
private static final Message T_unlock = message("xmlui.authority.confidence.unlock.help");
public void addPageMeta(PageMeta pageMeta) throws WingException
public void addPageMeta(PageMeta pageMeta) throws WingException, SQLException
{
Item item = Item.find(context, parameters.getParameterAsInteger("itemID",-1));
Collection owner = item.getOwningCollection();
int collectionID = (owner == null) ? -1 : owner.getID();
pageMeta.addMetadata("choice", "collection").addContent(String.valueOf(collectionID));
pageMeta.addMetadata("title").addContent(T_title);
pageMeta.addTrailLink(contextPath + "/", T_dspace_home);
@@ -158,6 +166,8 @@ public class EditItemMetadataForm extends AbstractDSpaceTransformer {
main.setHead(T_option_head);
}
Collection owner = item.getOwningCollection();
int collectionID = (owner == null) ? -1 : owner.getID();
// LIST: options
@@ -227,6 +237,7 @@ public class EditItemMetadataForm extends AbstractDSpaceTransformer {
header.addCell().addContent(T_column3);
header.addCell().addContent(T_column4);
ChoiceAuthorityManager cmgr = ChoiceAuthorityManager.getManager();
for(DCValue value : values)
{
String name = value.schema + "_" + value.element;
@@ -243,10 +254,46 @@ public class EditItemMetadataForm extends AbstractDSpaceTransformer {
cell.addContent(name.replaceAll("_", ". "));
cell.addHidden("name_"+index).setValue(name);
TextArea mdValue = row.addCell().addTextArea("value_"+index);
// value entry cell:
Cell mdCell = row.addCell();
String fieldKey = MetadataAuthorityManager.makeFieldKey(value.schema, value.element, value.qualifier);
// put up just a selector when preferred choice presentation is select:
if (cmgr.isChoicesConfigured(fieldKey) &&
Params.PRESENTATION_SELECT.equals(cmgr.getPresentation(fieldKey)))
{
Select mdSelect = mdCell.addSelect("value_"+index);
mdSelect.setSize(1);
Choices cs = cmgr.getMatches(fieldKey, value.value, collectionID, 0, 0, null);
if (cs.defaultSelected < 0)
mdSelect.addOption(true, value.value, value.value);
for (int i = 0; i < cs.values.length; ++i)
{
mdSelect.addOption(i == cs.defaultSelected, cs.values[i].value, cs.values[i].label);
}
}
else
{
TextArea mdValue = mdCell.addTextArea("value_"+index);
mdValue.setSize(4,35);
mdValue.setValue(value.value);
boolean isAuth = MetadataAuthorityManager.getManager().isAuthorityControlled(fieldKey);
if (isAuth)
{
mdValue.setAuthorityControlled();
mdValue.setAuthorityRequired(MetadataAuthorityManager.getManager().isAuthorityRequired(fieldKey));
Value authValue = mdValue.setAuthorityValue((value.authority == null)?"":value.authority, Choices.getConfidenceText(value.confidence));
// add the "unlock" button to auth field
Button unlock = authValue.addButton("authority_unlock_"+index,"ds-authority-lock");
unlock.setHelp(T_unlock);
}
if (ChoiceAuthorityManager.getManager().isChoicesConfigured(fieldKey))
{
mdValue.setChoices(fieldKey);
mdValue.setChoicesPresentation(Params.PRESENTATION_LOOKUP);
mdValue.setChoicesClosed(ChoiceAuthorityManager.getManager().isClosed(fieldKey));
}
}
Text mdLang = row.addCell().addText("language_"+index);
mdLang.setSize(6);
mdLang.setValue(value.language);

View File

@@ -5,8 +5,7 @@
*
* Date: $Date$
*
* Copyright (c) 2002-2005, Hewlett-Packard Company and Massachusetts
* Institute of Technology. All rights reserved.
* Copyright (c) 2002-2009, The DSpace Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -19,8 +18,7 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Hewlett-Packard Company nor the name of the
* Massachusetts Institute of Technology nor the names of their
* - Neither the name of the DSpace Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
@@ -85,6 +83,7 @@ import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.DCDate;
import org.dspace.content.DSpaceObject;
import org.dspace.content.authority.ChoiceAuthorityManager;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.Context;
import org.dspace.core.LogManager;
@@ -217,9 +216,9 @@ public class ConfigurableBrowse extends AbstractDSpaceTransformer implements
else
{
// Add the metadata to the validity
for (String singleEntry : browseInfo.getStringResults())
for (String[] singleEntry : browseInfo.getStringResults())
{
validity.add(singleEntry);
validity.add(singleEntry[0]+"#"+singleEntry[1]);
}
}
@@ -313,16 +312,26 @@ public class ConfigurableBrowse extends AbstractDSpaceTransformer implements
message("xmlui.ArtifactBrowser.ConfigurableBrowse." + type + ".column_heading"));
// Iterate each result
for (String singleEntry : browseInfo.getStringResults())
for (String[] singleEntry : browseInfo.getStringResults())
{
// Create a Map of the query parameters for the link
Map<String, String> queryParams = new HashMap<String, String>();
queryParams.put(BrowseParams.TYPE, URLEncode(type));
queryParams.put(BrowseParams.FILTER_VALUE, URLEncode(singleEntry));
if (singleEntry[1] != null)
{
queryParams.put(BrowseParams.FILTER_VALUE[1], URLEncode(
singleEntry[1]));
}
else
{
queryParams.put(BrowseParams.FILTER_VALUE[0], URLEncode(
singleEntry[0]));
}
// Create an entry in the table, and a linked entry
Cell cell = singleTable.addRow().addCell();
cell.addXref(super.generateURL(BROWSE_URL_BASE, queryParams), singleEntry);
cell.addXref(super.generateURL(BROWSE_URL_BASE, queryParams),
singleEntry[0]);
}
}
}
@@ -667,7 +676,14 @@ public class ConfigurableBrowse extends AbstractDSpaceTransformer implements
params.scope.setResultsPerPage(RequestUtils.getIntParameter(request,
BrowseParams.RESULTS_PER_PAGE));
params.scope.setStartsWith(URLDecode(request.getParameter(BrowseParams.STARTS_WITH)));
params.scope.setFilterValue(URLDecode(request.getParameter(BrowseParams.FILTER_VALUE)));
String filterValue = request.getParameter(BrowseParams.FILTER_VALUE[0]);
if (filterValue == null)
{
filterValue = request.getParameter(BrowseParams.FILTER_VALUE[1]);
params.scope.setAuthorityValue(filterValue);
}
params.scope.setFilterValue(filterValue);
params.scope.setJumpToValue(URLDecode(request.getParameter(BrowseParams.JUMPTO_VALUE)));
params.scope.setJumpToValueLang(URLDecode(request.getParameter(BrowseParams.JUMPTO_VALUE_LANG)));
params.scope.setFilterValueLang(URLDecode(request.getParameter(BrowseParams.FILTER_VALUE_LANG)));
@@ -805,7 +821,18 @@ public class ConfigurableBrowse extends AbstractDSpaceTransformer implements
// For a second level browse (ie. items for author),
// get the value we are focussing on (ie. author).
// (empty string if none).
String value = (info.hasValue() ? "\"" + info.getValue() + "\"" : "");
String value = "";
if (info.hasValue())
{
if (bix.isAuthorityIndex())
{
ChoiceAuthorityManager cm = ChoiceAuthorityManager.getManager();
String fk = cm.makeFieldKey(bix.getMetadata(0));
value = "\""+cm.getLabel(fk, info.getValue(), null)+"\"";
}
else
value = "\"" + info.getValue() + "\"";
}
// Get the name of any scoping element (collection / community)
String scopeName = "";
@@ -907,7 +934,7 @@ class BrowseParams
final static String STARTS_WITH = "starts_with";
final static String FILTER_VALUE = "value";
final static String[] FILTER_VALUE = new String[]{"value","authority"};
final static String FILTER_VALUE_LANG = "value_lang";
@@ -924,7 +951,9 @@ class BrowseParams
if (scope.getFilterValue() != null)
{
paramMap.put(BrowseParams.FILTER_VALUE, AbstractDSpaceTransformer.URLEncode(
paramMap.put(scope.getAuthorityValue() != null?
BrowseParams.FILTER_VALUE[1]:BrowseParams.FILTER_VALUE[0],
AbstractDSpaceTransformer.URLEncode(
scope.getFilterValue()));
}
@@ -984,4 +1013,3 @@ class BrowseParams
}
}
};

View File

@@ -0,0 +1,338 @@
/*
* ChoiceLookupTransformer.java
*
* Version: $Revision: 3705 $
*
* Date: $Date: 2009-04-11 13:02:24 -0400 (Sat, 11 Apr 2009) $
*
* Copyright (c) 2002-2009, The DSpace Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the DSpace Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
package org.dspace.app.xmlui.aspect.general;
import java.io.IOException;
import java.io.Serializable;
import java.sql.SQLException;
import javax.servlet.http.HttpServletResponse;
import org.dspace.content.authority.ChoiceAuthorityManager;
import org.dspace.content.DCPersonName;
import org.dspace.core.ConfigurationManager;
import org.apache.cocoon.caching.CacheableProcessingComponent;
import org.apache.cocoon.environment.ObjectModelHelper;
import org.apache.cocoon.environment.Request;
import org.apache.cocoon.environment.http.HttpEnvironment;
import org.apache.cocoon.util.HashUtil;
import org.apache.excalibur.source.SourceValidity;
import org.apache.excalibur.source.impl.validity.NOPValidity;
import org.dspace.app.xmlui.cocoon.AbstractDSpaceTransformer;
import org.dspace.app.xmlui.utils.UIException;
import org.dspace.app.xmlui.wing.Message;
import org.dspace.app.xmlui.wing.WingConstants;
import org.dspace.app.xmlui.wing.WingException;
import org.dspace.app.xmlui.wing.element.Body;
import org.dspace.app.xmlui.wing.element.Composite;
import org.dspace.app.xmlui.wing.element.Division;
import org.dspace.app.xmlui.wing.element.PageMeta;
import org.dspace.app.xmlui.wing.element.Hidden;
import org.dspace.app.xmlui.wing.element.List;
import org.dspace.app.xmlui.wing.element.Item;
import org.dspace.app.xmlui.wing.element.Select;
import org.dspace.app.xmlui.wing.element.Text;
import org.dspace.app.xmlui.wing.element.Button;
import org.dspace.authorize.AuthorizeException;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.apache.log4j.Logger;
/**
* Create the "lookup" popup window for Choice Control. It loads a selector
* via AJAX request, and transfers values (both text and authority/confidence)
* back to the indicated form fields in the window that launched it.
* Some necessary logic is in JavaScript, see choice-control.js.
*
* Expected Parameters:
* field - name of metadata field in "_" notation, eg: dc_contributor_author
* value - maybe-partial value of field
* formID - the @id of <form> tag in calling window containing the inputs we are to set.
* valueInput - @name of input field in DOM for value.
* authorityInput - @name of input field in DOM for authority value
* isRepeating - true if metadata value can be repeated
* isName - true if this is a name value (i.e. last/first boxes)
* start - starting index, default 0
* limit - maximum values to return, default 0 (none)
*
* Configuration Properties:
* xmlui.lookup.select.size = 12 (default, entries to show in SELECT widget.)
*
* For each FIELD, e.g. dc.contributor.author, these message properties
* will OVERRIDE the corresponding i18n message catalog entries:
* xmlui.lookup.field.FIELD.title = title of lookup page
* (e.g. xmlui.lookup.field.dc_contributor_author.title = Author..)
* xmlui.lookup.field.FIELD.nonauthority = template for "non-authority" label in options
* xmlui.lookup.field.FIELD.help = help message for single input
* (NOTE this is still required even for name inputs)
* xmlui.lookup.field.FIELD.help.last = help message for last name of Name-oriented input
* xmlui.lookup.field.FIELD.help.first = help message for first name of Name-oriented input
*
* @author Larry Stone
*/
public class ChoiceLookupTransformer extends AbstractDSpaceTransformer
{
/** log4j logger */
private static Logger log = Logger.getLogger(ChoiceLookupTransformer.class);
private static final String CONFIG_PREFIX = "xmlui.lookup.field.";
/** Language Strings */
private static final String MESSAGE_PREFIX = "xmlui.ChoiceLookupTransformer.";
private static final Message T_title = message(MESSAGE_PREFIX+"title");
private static final Message T_add = message(MESSAGE_PREFIX+"add");
private static final Message T_accept = message(MESSAGE_PREFIX+"accept");
private static final Message T_more = message(MESSAGE_PREFIX+"more");
private static final Message T_cancel = message(MESSAGE_PREFIX+"cancel");
private static final Message T_results = message(MESSAGE_PREFIX+"results");
private static final Message T_fail = message(MESSAGE_PREFIX+"fail");
public void addBody(Body body) throws SAXException, WingException,
UIException, SQLException, IOException, AuthorizeException
{
String field = null;
String value = null;
String formID = null;
String confIndicatorID = null;
boolean isName = false;
boolean isRepeating = false;
String valueInput = null;
String authorityInput = null;
int start = 0;
int limit = 0;
String collection = null;
// HTTP parameters:
try
{
field = parameters.getParameter("field");
value = parameters.getParameter("value");
formID = parameters.getParameter("formID");
confIndicatorID = parameters.getParameter("confIndicatorID");
isName = parameters.getParameterAsBoolean("isName", false);
isRepeating = parameters.getParameterAsBoolean("isRepeating", false);
valueInput = parameters.getParameter("valueInput");
authorityInput = parameters.getParameter("authorityInput");
String sStart = parameters.getParameter("start");
if (sStart != null)
start = atoi(sStart);
String sLimit = parameters.getParameter("limit");
if (sLimit != null)
limit = atoi(sLimit);
collection = parameters.getParameter("collection");
if (collection == null)
collection = "-1";
}
catch (org.apache.avalon.framework.parameters.ParameterException e)
{
throw new UIException("Missing a required parameter",e);
}
Division idiv = body.addInteractiveDivision("lookup", "", "get", "popup");
if (isFieldMessage(field, "title"))
idiv.setHead(getFieldMessage(field, "title"));
else
idiv.setHead(getFieldLabel(field, "title"));
List fl = idiv.addList("choicesList", "form", "choices-lookup");
fl.setHead(T_results);
// the <select> tag, and param values
Item selectItem = fl.addItem("select", "choices-lookup");
Select s = selectItem.addSelect("chooser", "choices-lookup");
s.setSize(ConfigurationManager.getIntProperty("xmlui.lookup.select.size", 12));
// parameters for javascript
Hidden h = selectItem.addHidden("paramField");
h.setValue(field);
h = selectItem.addHidden("paramValue");
h.setValue(value);
h = selectItem.addHidden("paramIsName");
h.setValue(String.valueOf(isName));
h = selectItem.addHidden("paramIsRepeating");
h.setValue(String.valueOf(isRepeating));
h = selectItem.addHidden("paramValueInput");
h.setValue(valueInput);
h = selectItem.addHidden("paramAuthorityInput");
h.setValue(authorityInput);
h = selectItem.addHidden("paramStart");
h.setValue(String.valueOf(start));
h = selectItem.addHidden("paramLimit");
h.setValue(String.valueOf(limit));
h = selectItem.addHidden("paramFormID");
h.setValue(formID);
h = selectItem.addHidden("paramConfIndicatorID");
h.setValue(confIndicatorID);
h = selectItem.addHidden("paramFail");
h.setValue(T_fail);
boolean isClosed = ChoiceAuthorityManager.getManager().isClosed(field);
h = selectItem.addHidden("paramIsClosed");
h.setValue(String.valueOf(isClosed));
h = selectItem.addHidden("paramCollection");
h.setValue(String.valueOf(collection));
if (!isClosed)
{
h = selectItem.addHidden("paramNonAuthority");
if (isFieldMessage(field, "nonauthority"))
h.setValue(getFieldMessage(field, "nonauthority"));
else
h.setValue(getFieldLabel(field, "nonauthority"));
}
h = selectItem.addHidden("contextPath");
h.setValue(contextPath);
// NOTE: the "spinner" indicator image gets added in the XSLT.
// the text input(s)
Item ti = fl.addItem("textFields", "choices-lookup");
Composite textItem = ti.addComposite("textFieldsComp", "choices-lookup");
Text t1 = textItem.addText("text1", "choices-lookup");
if (isName)
{
Text t2 = textItem.addText("text2", "choices-lookup");
DCPersonName dp = new DCPersonName(value);
t1.setValue(dp.getLastName());
t2.setValue(dp.getFirstNames());
if (isFieldMessage(field, "help.last"))
{
Message m = getFieldMessage(field, "help.last");
t1.setLabel(m);
t1.setHelp(m);
}
else
{
String m = getFieldLabel(field, "help.last");
t1.setLabel(m);
t1.setHelp(m);
}
if (isFieldMessage(field, "help.first"))
{
Message m = getFieldMessage(field, "help.first");
t2.setLabel(m);
t2.setHelp(m);
}
else
{
String m = getFieldLabel(field, "help.first");
t2.setLabel(m);
t2.setHelp(m);
}
}
else
{
t1.setValue(value);
if (isFieldMessage(field, "help"))
{
Message m = getFieldMessage(field, "help");
t1.setLabel(m);
t1.setHelp(m);
}
else
{
String m = getFieldLabel(field, "help");
t1.setLabel(m);
t1.setHelp(m);
}
}
// confirmation buttons
Item buttItem = fl.addItem("confirmation", "choices-lookup");
Button accept = buttItem.addButton("accept", "choices-lookup");
accept.setValue(isRepeating ? T_add : T_accept);
Button more = buttItem.addButton("more", "choices-lookup");
more.setDisabled();
more.setValue(T_more);
Button cancel = buttItem.addButton("cancel", "choices-lookup");
cancel.setValue(T_cancel);
}
public void addPageMeta(PageMeta pageMeta) throws SAXException,
WingException, UIException, SQLException, IOException,
AuthorizeException
{
// Set the page title
pageMeta.addMetadata("title").addContent(T_title);
// This invokes magic popup transformation in XSL - "framing.popup"
pageMeta.addMetadata("framing","popup").addContent("true");
}
/**
* Protocol to get custom and/or i18n strings:
* For label NAME,
* .. if config key xmlui.choices.FIELD.NAME is defined, and starts
* with "xmlui.", then it's a message key.
* .. if NO config key is defined, look for message
* xmlui.ChoiceLookupTransformer.field.FIELD.NAME
* .. otherwise take literal value from configuration
*/
// return true if configured (or lack thereof) value points to Message
private boolean isFieldMessage(String field, String name)
{
String cv = getFieldLabel(field, name);
return (cv == null || cv.startsWith("xmlui."));
}
// get field-specific label value
private String getFieldLabel(String field, String name)
{
return ConfigurationManager.getProperty(CONFIG_PREFIX+field+"."+name);
}
// get field-specific label value
private Message getFieldMessage(String field, String name)
{
String cv = getFieldLabel(field, name);
if (cv == null)
return message(MESSAGE_PREFIX+"field."+field+"."+name);
else
return message(cv);
}
private int atoi(String s)
{
try
{
return Integer.parseInt(s);
}
catch (Exception e) {}
return 0;
}
}

View File

@@ -51,6 +51,7 @@ import org.apache.log4j.Logger;
import org.dspace.app.util.DCInput;
import org.dspace.app.util.DCInputSet;
import org.dspace.app.util.DCInputsReader;
import org.dspace.app.util.DCInputsReaderException;
import org.dspace.app.xmlui.utils.UIException;
import org.dspace.app.xmlui.aspect.submission.AbstractSubmissionStep;
import org.dspace.app.xmlui.aspect.submission.FlowUtils;
@@ -61,7 +62,10 @@ import org.dspace.app.xmlui.wing.element.CheckBox;
import org.dspace.app.xmlui.wing.element.Composite;
import org.dspace.app.xmlui.wing.element.Division;
import org.dspace.app.xmlui.wing.element.Field;
import org.dspace.app.xmlui.wing.element.Instance;
import org.dspace.app.xmlui.wing.element.List;
import org.dspace.app.xmlui.wing.element.PageMeta;
import org.dspace.app.xmlui.wing.element.Params;
import org.dspace.app.xmlui.wing.element.Radio;
import org.dspace.app.xmlui.wing.element.Select;
import org.dspace.app.xmlui.wing.element.Text;
@@ -74,7 +78,10 @@ import org.dspace.content.DCPersonName;
import org.dspace.content.DCSeriesNumber;
import org.dspace.content.DCValue;
import org.dspace.content.Item;
import org.dspace.content.authority.MetadataAuthorityManager;
import org.dspace.content.authority.ChoiceAuthorityManager;
import org.dspace.content.authority.Choice;
import org.dspace.content.authority.Choices;
import org.xml.sax.SAXException;
@@ -128,7 +135,7 @@ public class DescribeStep extends AbstractSubmissionStep
* Ensure that the inputs reader has been initialized, this method may be
* called multiple times with no ill-effect.
*/
private static void initializeInputsReader() throws ServletException
private static void initializeInputsReader() throws DCInputsReaderException
{
if (INPUTS_READER == null)
INPUTS_READER = new DCInputsReader();
@@ -155,12 +162,22 @@ public class DescribeStep extends AbstractSubmissionStep
this.requireStep = true;
//Ensure that the InputsReader is initialized.
try
{
initializeInputsReader();
}
catch (DCInputsReaderException e)
{
throw new ServletException(e);
}
}
public void addPageMeta(PageMeta pageMeta) throws SAXException, WingException,
UIException, SQLException, IOException, AuthorizeException
{
int collectionID = submission.getCollection().getID();
pageMeta.addMetadata("choice", "collection").addContent(String.valueOf(collectionID));
String jumpTo = submissionInfo.getJumpToField();
if (jumpTo != null)
pageMeta.addMetadata("page","jumpTo").addContent(jumpTo);
@@ -181,7 +198,7 @@ public class DescribeStep extends AbstractSubmissionStep
inputSet = getInputsReader().getInputs(submission.getCollection().getHandle());
inputs = inputSet.getPageRows(getPage()-1, submission.hasMultipleTitles(), submission.isPublishedBefore());
}
catch (ServletException se)
catch (DCInputsReaderException se)
{
throw new UIException(se);
}
@@ -212,9 +229,18 @@ public class DescribeStep extends AbstractSubmissionStep
DCValue[] dcValues = item.getMetadata(schema, element, qualifier, Item.ANY);
String fieldName = FlowUtils.getFieldName(dcInput);
String inputType = dcInput.getInputType();
if (inputType.equals("name"))
// if this field is configured as choice control and its
// presentation format is SELECT, render it as select field:
String fieldKey = MetadataAuthorityManager.makeFieldKey(schema, element, qualifier);
ChoiceAuthorityManager cmgr = ChoiceAuthorityManager.getManager();
if (cmgr.isChoicesConfigured(fieldKey) &&
Params.PRESENTATION_SELECT.equals(cmgr.getPresentation(fieldKey)))
{
renderChoiceSelectField(form, fieldName, collection, dcInput, dcValues, readonly);
}
else if (inputType.equals("name"))
{
renderNameField(form, fieldName, dcInput, dcValues, readonly);
}
@@ -311,11 +337,12 @@ public class DescribeStep extends AbstractSubmissionStep
{
inputSet = getInputsReader().getInputs(submission.getCollection().getHandle());
}
catch (ServletException se)
catch (DCInputsReaderException se)
{
throw new UIException(se);
}
MetadataAuthorityManager mam = MetadataAuthorityManager.getManager();
DCInput[] inputs = inputSet.getPageRows(getPage()-1, submission.hasMultipleTitles(), submission.isPublishedBefore());
for (DCInput input : inputs)
@@ -369,7 +396,18 @@ public class DescribeStep extends AbstractSubmissionStep
//Only display this field if we have a value to display
if (displayValue!=null && displayValue.length()>0)
{
describeSection.addLabel(input.getLabel());
if (mam.isAuthorityControlled(value.schema, value.element, value.qualifier))
{
String confidence = (value.authority != null && value.authority.length() > 0) ?
Choices.getConfidenceText(value.confidence).toLowerCase() :
"blank";
org.dspace.app.xmlui.wing.element.Item authItem =
describeSection.addItem("submit-review-field-with-authority", "ds-authority-confidence cf-"+confidence);
authItem.addContent(displayValue);
}
else
describeSection.addItem(displayValue);
}
} // For each DCValue
@@ -414,6 +452,19 @@ public class DescribeStep extends AbstractSubmissionStep
fullName.enableAddOperation();
if ((dcInput.isRepeatable() || dcValues.length > 1) && !readonly)
fullName.enableDeleteOperation();
String fieldKey = MetadataAuthorityManager.makeFieldKey(dcInput.getSchema(), dcInput.getElement(), dcInput.getQualifier());
boolean isAuthorityControlled = MetadataAuthorityManager.getManager().isAuthorityControlled(fieldKey);
if (isAuthorityControlled)
{
fullName.setAuthorityControlled();
fullName.setAuthorityRequired(MetadataAuthorityManager.getManager().isAuthorityRequired(fieldKey));
}
if (ChoiceAuthorityManager.getManager().isChoicesConfigured(fieldKey))
{
fullName.setChoices(fieldKey);
fullName.setChoicesPresentation(ChoiceAuthorityManager.getManager().getPresentation(fieldKey));
fullName.setChoicesClosed(ChoiceAuthorityManager.getManager().isClosed(fieldKey));
}
// Setup the first and last name
lastName.setLabel(T_last_name_help);
@@ -435,7 +486,15 @@ public class DescribeStep extends AbstractSubmissionStep
lastName.addInstance().setValue(dpn.getLastName());
firstName.addInstance().setValue(dpn.getFirstNames());
fullName.addInstance().setValue(dcValue.value);
Instance fi = fullName.addInstance();
fi.setValue(dcValue.value);
if (isAuthorityControlled)
{
if (dcValue.authority == null || dcValue.authority.equals(""))
fi.setAuthorityValue("", "blank");
else
fi.setAuthorityValue(dcValue.authority, Choices.getConfidenceText(dcValue.confidence));
}
}
}
else if (dcValues.length == 1)
@@ -444,6 +503,13 @@ public class DescribeStep extends AbstractSubmissionStep
lastName.setValue(dpn.getLastName());
firstName.setValue(dpn.getFirstNames());
if (isAuthorityControlled)
{
if (dcValues[0].authority == null || dcValues[0].authority.equals(""))
lastName.setAuthorityValue("", "blank");
else
lastName.setAuthorityValue(dcValues[0].authority, Choices.getConfidenceText(dcValues[0].confidence));
}
}
}
@@ -694,6 +760,19 @@ public class DescribeStep extends AbstractSubmissionStep
// Setup the text area
textArea.setLabel(dcInput.getLabel());
textArea.setHelp(cleanHints(dcInput.getHints()));
String fieldKey = MetadataAuthorityManager.makeFieldKey(dcInput.getSchema(), dcInput.getElement(), dcInput.getQualifier());
boolean isAuth = MetadataAuthorityManager.getManager().isAuthorityControlled(fieldKey);
if (isAuth)
{
textArea.setAuthorityControlled();
textArea.setAuthorityRequired(MetadataAuthorityManager.getManager().isAuthorityRequired(fieldKey));
}
if (ChoiceAuthorityManager.getManager().isChoicesConfigured(fieldKey))
{
textArea.setChoices(fieldKey);
textArea.setChoicesPresentation(ChoiceAuthorityManager.getManager().getPresentation(fieldKey));
textArea.setChoicesClosed(ChoiceAuthorityManager.getManager().isClosed(fieldKey));
}
if (dcInput.isRequired())
textArea.setRequired();
if (isFieldInError(fieldName))
@@ -713,12 +792,87 @@ public class DescribeStep extends AbstractSubmissionStep
{
for (DCValue dcValue : dcValues)
{
textArea.addInstance().setValue(dcValue.value);
Instance ti = textArea.addInstance();
ti.setValue(dcValue.value);
if (isAuth)
{
if (dcValue.authority == null || dcValue.authority.equals(""))
ti.setAuthorityValue("", "blank");
else
ti.setAuthorityValue(dcValue.authority, Choices.getConfidenceText(dcValue.confidence));
}
}
}
else if (dcValues.length == 1)
{
textArea.setValue(dcValues[0].value);
if (isAuth)
{
if (dcValues[0].authority == null || dcValues[0].authority.equals(""))
textArea.setAuthorityValue("", "blank");
else
textArea.setAuthorityValue(dcValues[0].authority, Choices.getConfidenceText(dcValues[0].confidence));
}
}
}
/**
* Render a dropdown field for a choice-controlled input of the
* 'select' presentation to the DRI document. The dropdown field
* consists of an HTML select box.
*
* @param form
* The form list to add the field too
* @param fieldName
* The field's name.
* @param dcInput
* The field's input deffinition
* @param dcValues
* The field's pre-existing values.
*/
private void renderChoiceSelectField(List form, String fieldName, Collection coll, DCInput dcInput, DCValue[] dcValues, boolean readonly) throws WingException
{
String fieldKey = MetadataAuthorityManager.makeFieldKey(dcInput.getSchema(), dcInput.getElement(), dcInput.getQualifier());
if (MetadataAuthorityManager.getManager().isAuthorityControlled(fieldKey))
throw new WingException("Field "+fieldKey+" has choice presentation of type \""+Params.PRESENTATION_SELECT+"\", it may NOT be authority-controlled.");
// Plain old select list.
Select select = form.addItem().addSelect(fieldName,"submit-select");
//Setup the select field
select.setLabel(dcInput.getLabel());
select.setHelp(cleanHints(dcInput.getHints()));
if (dcInput.isRequired())
select.setRequired();
if (isFieldInError(fieldName))
select.addError(T_required_field);
if (dcInput.isRepeatable() || dcValues.length > 1)
{
// Use the multiple functionality from the HTML
// widget instead of DRI's version.
select.setMultiple();
select.setSize(6);
}
else
select.setSize(1);
if (readonly)
{
select.setDisabled();
}
Choices cs = ChoiceAuthorityManager.getManager().getMatches(fieldKey, "", coll.getID(), 0, 0, null);
if (dcValues.length == 0)
select.addOption(true, "", "");
for (Choice c : cs.values)
{
select.addOption(c.value, c.label);
}
// Setup the field's pre-selected values
for (DCValue dcValue : dcValues)
{
select.setOptionSelected(dcValue.value);
}
}
@@ -879,6 +1033,20 @@ public class DescribeStep extends AbstractSubmissionStep
// Setup the select field
text.setLabel(dcInput.getLabel());
text.setHelp(cleanHints(dcInput.getHints()));
String fieldKey = MetadataAuthorityManager.makeFieldKey(dcInput.getSchema(), dcInput.getElement(), dcInput.getQualifier());
boolean isAuth = MetadataAuthorityManager.getManager().isAuthorityControlled(fieldKey);
if (isAuth)
{
text.setAuthorityControlled();
text.setAuthorityRequired(MetadataAuthorityManager.getManager().isAuthorityRequired(fieldKey));
}
if (ChoiceAuthorityManager.getManager().isChoicesConfigured(fieldKey))
{
text.setChoices(fieldKey);
text.setChoicesPresentation(ChoiceAuthorityManager.getManager().getPresentation(fieldKey));
text.setChoicesClosed(ChoiceAuthorityManager.getManager().isClosed(fieldKey));
}
if (dcInput.isRequired())
text.setRequired();
if (isFieldInError(fieldName))
@@ -898,12 +1066,27 @@ public class DescribeStep extends AbstractSubmissionStep
{
for (DCValue dcValue : dcValues)
{
text.addInstance().setValue(dcValue.value);
Instance ti = text.addInstance();
ti.setValue(dcValue.value);
if (isAuth)
{
if (dcValue.authority == null || dcValue.authority.equals(""))
ti.setAuthorityValue("", "blank");
else
ti.setAuthorityValue(dcValue.authority, Choices.getConfidenceText(dcValue.confidence));
}
}
}
else if (dcValues.length == 1)
{
text.setValue(dcValues[0].value);
if (isAuth)
{
if (dcValues[0].authority == null || dcValues[0].authority.equals(""))
text.setAuthorityValue("", "blank");
else
text.setAuthorityValue(dcValues[0].authority, Choices.getConfidenceText(dcValues[0].confidence));
}
}
}

View File

@@ -0,0 +1,126 @@
/*
* AJAXMenuGenerator.java
*
* Version: $Revision: 3705 $
*
* Date: $Date: 2009-04-11 13:02:24 -0400 (Sat, 11 Apr 2009) $
*
* Copyright (c) 2002-2009, The DSpace Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the DSpace Foundation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
package org.dspace.app.xmlui.cocoon;
import java.io.IOException;
import java.sql.SQLException;
import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.ResourceNotFoundException;
import org.apache.cocoon.environment.ObjectModelHelper;
import org.apache.cocoon.environment.Request;
import org.apache.cocoon.generation.AbstractGenerator;
import org.dspace.app.xmlui.objectmanager.AbstractAdapter;
import org.dspace.app.xmlui.objectmanager.ContainerAdapter;
import org.dspace.app.xmlui.objectmanager.ItemAdapter;
import org.dspace.app.xmlui.objectmanager.RepositoryAdapter;
import org.dspace.app.xmlui.utils.ContextUtil;
import org.dspace.app.xmlui.wing.WingException;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
import org.dspace.content.authority.Choices;
import org.dspace.content.authority.Choice;
import org.dspace.content.authority.ChoiceAuthorityManager;
import org.dspace.content.authority.ChoicesXMLGenerator;
import org.dspace.content.crosswalk.CrosswalkException;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.Context;
import org.dspace.handle.HandleManager;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.ext.LexicalHandler;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.AttributesImpl;
import org.apache.log4j.Logger;
/**
* Generate XML description of Choice values to be used by
* AJAX UI client.
*
* @author Larry Stone
*/
public class AJAXMenuGenerator extends AbstractGenerator
{
private static Logger log = Logger.getLogger(AJAXMenuGenerator.class);
/**
* Generate the AJAX response Document.
*
* Looks for request paraemters:
* field - MD field key, i.e. form key, REQUIRED.
* start - index to start from, default 0.
* limit - max number of lines, default 1000.
* format - opt. result XML/XHTML format: "select", "ul", "xml"(default)
* locale - explicit locale, pass to choice plugin
*/
public void generate()
throws IOException, SAXException, ProcessingException
{
int start = 0;
int limit = 1000;
int collection = -1;
String format = parameters.getParameter("format",null);
String field = parameters.getParameter("field",null);
String sstart = parameters.getParameter("start",null);
if (sstart != null && sstart.length() > 0)
start = Integer.parseInt(sstart);
String slimit = parameters.getParameter("limit",null);
if (slimit != null && slimit.length() > 0)
limit = Integer.parseInt(slimit);
String scoll = parameters.getParameter("collection",null);
if (scoll != null && scoll.length() > 0)
collection = Integer.parseInt(scoll);
String query = parameters.getParameter("query",null);
// localization
String locale = parameters.getParameter("locale",null);
log.debug("AJAX menu generator: field="+field+", query="+query+", start="+sstart+", limit="+slimit+", format="+format+", field="+field+", query="+query+", start="+sstart+", limit="+slimit+", format="+format+", locale = "+locale);
Choices result =
ChoiceAuthorityManager.getManager().getMatches(field, query, collection, start, limit, locale);
log.debug("Result count = "+result.values.length+", default="+result.defaultSelected);
ChoicesXMLGenerator.generate(result, format, contentHandler);
}
}

View File

@@ -46,6 +46,7 @@ import org.dspace.content.Bitstream;
import org.dspace.content.Bundle;
import org.dspace.content.DCValue;
import org.dspace.content.Item;
import org.dspace.content.authority.Choices;
import org.dspace.content.crosswalk.CrosswalkException;
import org.dspace.content.crosswalk.DisseminationCrosswalk;
import org.dspace.core.ConfigurationManager;
@@ -282,7 +283,11 @@ public class ItemAdapter extends AbstractAdapter
attributes.put("qualifier", dcv.qualifier);
if (dcv.language != null)
attributes.put("language", dcv.language);
if (dcv.authority != null || dcv.confidence != Choices.CF_UNSET)
{
attributes.put("authority", dcv.authority);
attributes.put("confidence", Choices.getConfidenceText(dcv.confidence));
}
startElement(DIM,"field",attributes);
sendCharacters(dcv.value);
endElement(DIM,"field");

View File

@@ -112,6 +112,7 @@ to administer DSpace.
<map:transformer name="ControlPanel" src="org.dspace.app.xmlui.aspect.administrative.ControlPanel" />
<map:transformer name="WithdrawnItems" src="org.dspace.app.xmlui.aspect.administrative.WithdrawnItems" />
<map:transformer name="ItemExport" src="org.dspace.app.xmlui.aspect.administrative.ItemExport"/>
<map:transformer name="ChoiceLookup" src="org.dspace.app.xmlui.aspect.general.ChoiceLookupTransformer"/>
</map:transformers>
<map:matchers default="wildcard">
@@ -885,6 +886,34 @@ to administer DSpace.
</map:select>
</map:match>
<!-- choice value lookup popup -->
<map:match pattern="admin/lookup">
<map:transform type="ChoiceLookup">
<map:parameter name="field" value="{request-param:field}"/>
<map:parameter name="formID" value="{request-param:formID}"/>
<map:parameter name="value" value="{request-param:value}"/>
<map:parameter name="valueInput" value="{request-param:valueInput}"/>
<map:parameter name="authorityInput" value="{request-param:authorityInput}"/>
<map:parameter name="isName" value="{request-param:isName}"/>
<map:parameter name="isRepeating" value="{request-param:isRepeating}"/>
<map:parameter name="confIndicatorID" value="{request-param:confIndicatorID}"/>
<map:parameter name="start" value="{request-param:start}"/>
<map:parameter name="limit" value="{request-param:limit}"/>
<map:parameter name="collection" value="{request-param:collection}"/>
</map:transform>
</map:match>
<map:match pattern="admin/**">
<map:transform type="IncludePageMeta">
<!-- javascript libraries and utils for the choice and authority-control -->
<map:parameter name="javascript.static#1" value="static/js/scriptaculous/prototype.js"/>
<map:parameter name="javascript.static#2" value="static/js/scriptaculous/effects.js"/>
<map:parameter name="javascript.static#3" value="static/js/scriptaculous/builder.js"/>
<map:parameter name="javascript.static#4" value="static/js/scriptaculous/controls.js"/>
<map:parameter name="javascript.static#5" value="static/js/choice-support.js"/>
</map:transform>
</map:match>
<map:serialize type="xml"/>
</map:pipeline>
</map:pipelines>

View File

@@ -73,6 +73,7 @@
<map:matchers default="wildcard">
<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="regexp" src="org.apache.cocoon.matching.RegexpURIMatcher"/>
</map:matchers>
<map:actions>
@@ -297,6 +298,17 @@
</map:match> <!-- flow match-->
<!-- javascript libraries and utils for choice/authority-control -->
<map:match type="regexp" pattern="(^submit)|(^handle/.*/submit)|(^handle/.*/workflow)">
<map:transform type="IncludePageMeta">
<map:parameter name="javascript.static#1" value="static/js/scriptaculous/prototype.js"/>
<map:parameter name="javascript.static#2" value="static/js/scriptaculous/effects.js"/>
<map:parameter name="javascript.static#3" value="static/js/scriptaculous/builder.js"/>
<map:parameter name="javascript.static#4" value="static/js/scriptaculous/controls.js"/>
<map:parameter name="javascript.static#5" value="static/js/choice-support.js"/>
</map:transform>
</map:match>
<map:serialize type="xml"/>
</map:when>

View File

@@ -128,6 +128,12 @@
<artifactId>dspace-xmlui-api</artifactId>
</dependency>
<!-- Shared JS code for Choice/Authority control -->
<dependency>
<groupId>org.dspace</groupId>
<artifactId>dspace-ui-shared</artifactId>
<type>war</type>
</dependency>
</dependencies>
</project>

Some files were not shown because too many files have changed in this diff Show More