Index: perl_lib/EPrints/MetaField/Namevalue.pm
===================================================================
--- perl_lib/EPrints/MetaField/Namevalue.pm	(revision 0)
+++ perl_lib/EPrints/MetaField/Namevalue.pm	(revision 224)
@@ -0,0 +1,462 @@
+######################################################################
+#
+# EPrints::MetaField::Namevalue;
+#
+######################################################################
+#
+#
+# Copyright 2000-2008 University of Southampton. All Rights Reserved.
+# 
+#  This file is part of GNU EPrints 3.
+#  
+#  Copyright (c) 2000-2008 University of Southampton, UK. SO17 1BJ.
+#  
+#  EPrints 3 is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#  
+#  EPrints 3 is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#  
+#  You should have received a copy of the GNU General Public License
+#  along with EPrints 3; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+######################################################################
+
+=pod
+
+=head1 NAME
+
+B<EPrints::MetaField::Namevalue> - Name-value pair storage
+
+=head1 DESCRIPTION
+
+Handles name-value pairs
+
+=over 4
+
+=cut
+
+package EPrints::MetaField::Namevalue;
+
+use strict;
+use warnings;
+
+use Unicode::String qw( latin1 utf8 );
+
+BEGIN
+{
+	our( @ISA );
+
+	@ISA = qw( EPrints::MetaField::Text );
+}
+
+use EPrints::MetaField::Text;
+
+my $VARCHAR_SIZE = 255;
+
+# database order
+my @PARTS = qw( name value );
+
+sub get_sql_names
+{
+	my( $self ) = @_;
+
+	return map { $self->get_name() . "_" . $_ } @PARTS;
+}
+
+sub value_from_sql_row
+{
+	my( $self, $session, $row ) = @_;
+
+	my %value;
+	@value{@PARTS} = splice(@$row,0,2);
+
+	return \%value;
+}
+
+sub sql_row_from_value
+{
+	my( $self, $session, $value ) = @_;
+
+	return @$value{@PARTS};
+}
+
+sub get_sql_type
+{
+	my( $self, $session, $notnull ) = @_;
+
+	my @parts = $self->get_sql_names;
+
+	for(@parts)
+	{
+		$_ = $session->get_database->get_column_type(
+			$_,
+			EPrints::Database::SQL_VARCHAR,
+			$notnull,
+			$VARCHAR_SIZE
+		);
+	}
+
+	return join ", ", @parts;
+}
+
+# index the name part only...ignore the value
+sub get_sql_index
+{
+	my( $self ) = @_;
+
+	return () unless( $self->get_property( "sql_index" ) );
+
+	return ($self->get_name()."_name");
+}
+	
+sub render_single_value
+{
+	my( $self, $session, $value ) = @_;
+
+	my $order = $self->{render_order};
+	
+	# If the render opt "order" is set to "gf" then we order
+	# the name with given name first. 
+
+	return $session->render_name( 
+			$value, 
+			defined $order && $order eq "gf" );
+}
+
+sub get_input_bits
+{
+	my( $self, $session ) = @_;
+
+	my @namebits;
+	# TODO: Review this to ensure its right
+	push @namebits, "name";
+	push @namebits, "value";
+
+	return @namebits;
+}
+
+sub get_basic_input_elements
+{
+	my( $self, $session, $value, $basename, $staff, $obj ) = @_;
+
+	my $parts = [];
+	foreach( $self->get_input_bits( $session ) )
+	{
+		my $size = $self->{input_name_cols}->{$_};
+		my $f = $session->make_element( "div" );
+		push @{$parts}, {el=>$f};
+		my $input_field = $session->render_noenter_input_field(
+			class => "ep_form_text",
+			name => $basename."_".$_,
+			id => $basename."_".$_,
+			value => $value->{$_},
+			size => $size,
+			maxlength => $self->{maxlength} );
+		$f->appendChild( $input_field );
+		$f->appendChild( $session->make_element( "div", id=>$basename."_".$_."_billboard" ));
+	}
+
+	return [ $parts ];
+}
+
+sub get_basic_input_ids
+{
+	my( $self, $session, $basename, $staff, $obj ) = @_;
+
+	my @ids = ();
+	foreach( $self->get_input_bits( $session ) )
+	{
+		push @ids, $basename."_".$_;
+	}
+
+	return @ids;
+}
+
+sub get_input_col_titles
+{
+	my( $self, $session, $staff ) = @_;
+
+	my @r = ();
+	foreach my $bit ( $self->get_input_bits( $session ) )
+	{
+		push @r, $session->html_phrase(	"lib/metafield/namevalue:".$bit );
+	}
+	return \@r;
+}
+
+sub form_value_basic
+{
+	my( $self, $session, $basename ) = @_;
+	
+	my $data = {};
+	foreach( @PARTS )
+	{
+		$data->{$_} = 
+			$session->param( $basename."_".$_ );
+	}
+
+	unless( EPrints::Utils::is_set( $data ) )
+	{
+		return( undef );
+	}
+
+	return $data;
+}
+
+sub get_value_label
+{
+	my( $self, $session, $value ) = @_;
+
+	return $self->render_single_value( $session, $value );
+}
+
+sub ordervalue_basic
+{
+	my( $self , $value ) = @_;
+
+	unless( ref($value) =~ m/^HASH/ ) { 
+		EPrints::abort( "EPrints::MetaField::NameValue::ordervalue_basic called on something other than a hash." );
+	}
+
+	my @a;
+	foreach( @PARTS )
+	{
+		if( defined $value->{$_} )
+		{
+			push @a, $value->{$_};
+		}
+		else
+		{
+			push @a, "";
+		}
+	}
+	return join( "\t" , @a );
+}
+
+
+
+sub split_search_value
+{
+	my( $self, $session, $value ) = @_;
+
+	# should use archive whitespaces
+	# remove spaces around commas to make them single names
+	$value =~ s/\s*:\s*/,/g; 
+
+	# things in double quotes are treated as a single name
+	# eg. "Harris Smith" or "Smith, J K"
+	my @bits = ();
+	while( $value =~ s/"([^"]+)"// )
+	{
+		push @bits, $1;
+	}
+
+	# if there is anything left, split it on whitespace
+	if( $value !~ m/^:+$/ )
+	{
+		push @bits, split /\s+/ , $value;
+	}
+
+	return @bits;
+}
+
+sub render_search_value
+{
+        my( $self, $session, $value ) = @_;
+
+	my @bits = $self->split_search_value( $session, $value );
+        return $session->make_text( '"'.join( '", "', @bits).'"' );
+}
+
+sub get_search_conditions
+{
+	my( $self, $session, $dataset, $search_value, $match, $merge,
+		$search_mode ) = @_;
+
+	my $v2 = EPrints::Index::apply_mapping( 
+			$session,
+			$search_value );
+
+	my $indexmode = "index";
+
+#	if( $session->get_repository->get_conf( "match_start_of_name" ) )
+#	{
+#		$indexmode = "index_start";
+#	}
+
+	# name searches are case sensitive
+	$v2 = "\L$v2";
+
+	# TODO: nasty hack to get this to work, need to re-evaluate
+	return EPrints::Search::Condition->new( 
+		$indexmode,
+		$dataset,
+		$self, 
+		$v2 );
+}
+
+# INHERRITS get_search_conditions_not_ex, but it's not called.
+
+sub get_search_group { return 'name'; } 
+
+sub get_property_defaults
+{
+	my( $self ) = @_;
+	my %defaults = $self->SUPER::get_property_defaults;
+	$defaults{input_name_cols} = $EPrints::MetaField::FROM_CONFIG;
+	$defaults{render_order} = "fg";
+	return %defaults;
+}
+
+sub get_unsorted_values
+{
+	my( $self, $session, $dataset, %opts ) = @_;
+
+	my $list = $session->get_database->get_values( $self, $dataset );
+
+	return $list;
+
+	#my $out = [];
+	#foreach my $name ( @{$list} )
+	#{
+		#push @{$out}, $name->{family}.', '.$name->{given};
+	#}
+	#return $out;
+}
+
+sub get_index_codes_basic
+{
+	my( $self, $session, $value ) = @_;
+
+	return( [], [], [] ) unless( EPrints::Utils::is_set( $value ) );
+
+	my $f = &EPrints::Index::apply_mapping( $session, $value->{name} );
+	my $g = &EPrints::Index::apply_mapping( $session, $value->{value} );
+
+
+	# Add a space before all capitals to break
+	# up initials. Will screw up names with capital
+	# letters in the middle of words. But that's
+	# pretty rare.
+#	my $len_g = $g->length;
+#        my $new_g = utf8( "" );
+#        for(my $i = 0; $i<$len_g; ++$i )
+#        {
+#                my $s = $g->substr( $i, 1 );
+#                if( $s eq "\U$s" )
+#                {
+#			$new_g .= ' ';
+#                }
+#		$new_g .= $s;
+#	}
+#
+	my $code = '';
+	my @r = ();
+#	foreach( EPrints::Index::split_words( $session, $f ) )
+#	{
+#		next if( $_ eq "" );
+#		push @r, "\L$_";
+#		$code.= "[\L$_]";
+#	}
+	#$code.="[\L$f]";
+	#$code.= "-";
+
+	$code.="[$g]";
+#	foreach( EPrints::Index::split_words( $session, $new_g ) )
+#	{
+#		next if( $_ eq "" );
+##		push @r, "value:\L$_";
+ 		push @r, "$g";
+		#$code.= "[\L$_]";
+#	}
+
+	return( \@r, [$code], [] );
+}	
+
+sub get_values
+{
+	my( $self, $session, $dataset, %opts ) = @_;
+
+	my $langid = $opts{langid};
+	$langid = $session->get_langid unless( defined $langid );
+
+	my $unsorted_values = $self->get_unsorted_values( 
+		$session,
+		$dataset,	
+		%opts );
+
+	my %orderkeys = ();
+	my @values;
+	foreach my $value ( @{$unsorted_values} )
+	{
+		my $v2 = $value;
+		$v2 = {} unless( defined $value );
+		push @values, $v2;
+
+		# uses function _basic because value will NEVER be multiple
+		my $orderkey = $self->ordervalue_basic(
+			$value, 
+			$session, 
+			$langid );
+		$orderkeys{$self->get_id_from_value($session, $v2)} = $orderkey;
+	}
+
+	my @outvalues = sort {$orderkeys{$self->get_id_from_value($session, $a)} cmp $orderkeys{$self->get_id_from_value($session, $b)}} @values;
+	return \@outvalues;
+}
+
+sub get_id_from_value
+{
+	my( $self, $session, $name ) = @_;
+
+	no warnings;
+
+	return $name->{name}.':'.$name->{value};
+}
+
+sub to_xml_basic
+{
+	my( $self, $session, $value ) = @_;
+
+	my $r = $session->make_doc_fragment;	
+
+	foreach my $part ( @PARTS )
+	{
+		my $nv = $value->{$part};
+		next unless defined $nv;
+		next unless $nv ne "";
+		my $tag = $session->make_element( $part );
+		$tag->appendChild( $session->make_text( $nv ) );
+		$r->appendChild( $tag );
+	}
+	
+	return $r;
+}
+
+sub render_xml_schema_type
+{
+	my( $self, $session ) = @_;
+
+	my $type = $session->make_element( "xs:complexType", name => $self->get_xml_schema_type );
+
+	my $all = $session->make_element( "xs:all", minOccurs => "0" );
+	$type->appendChild( $all );
+	foreach my $part ( @PARTS )
+	{
+		my $element = $session->make_element( "xs:element", name => $part, type => "xs:string" );
+		$all->appendChild( $element );
+	}
+
+	return $type;
+}
+
+
+
+######################################################################
+1;
Index: perl_lib/EPrints/MetaField/Externalitemref.pm
===================================================================
--- perl_lib/EPrints/MetaField/Externalitemref.pm	(revision 0)
+++ perl_lib/EPrints/MetaField/Externalitemref.pm	(revision 224)
@@ -0,0 +1,140 @@
+######################################################################
+#
+# EPrints::MetaField::Externalitemref;
+#
+######################################################################
+#
+#
+# Copyright 2000-2008 University of Southampton. All Rights Reserved.
+# 
+#  This file is part of GNU EPrints 3.
+#  
+#  Copyright (c) 2000-2008 University of Southampton, UK. SO17 1BJ.
+#  
+#  EPrints 3 is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#  
+#  EPrints 3 is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#  
+#  You should have received a copy of the GNU General Public License
+#  along with EPrints 3; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+######################################################################
+
+=pod
+
+=head1 NAME
+
+B<EPrints::MetaField::Externalitemref> - Reference to an object with an "int" type of ID field.
+
+=head1 DESCRIPTION
+
+This item is similar to the Itemref metafield but is designed to link to non-dataset tables
+
+=over 4
+
+=cut
+
+package EPrints::MetaField::Externalitemref;
+
+use strict;
+use warnings;
+
+BEGIN
+{
+	our( @ISA );
+
+	@ISA = qw( EPrints::MetaField::Int );
+}
+
+use EPrints::MetaField::Int;
+
+sub get_property_defaults
+{
+	my( $self ) = @_;
+	my %defaults = $self->SUPER::get_property_defaults;
+	$defaults{externaltable} = $EPrints::MetaField::REQUIRED;
+	$defaults{externalkey} = $EPrints::MetaField::REQUIRED;
+	$defaults{externalname} = $EPrints::MetaField::REQUIRED;
+	$defaults{external_lookup_url} = $EPrints::MetaField::UNDEF;
+	$defaults{external_lookup_params} = ''; # blank this out
+	$defaults{text_index} = 0;
+	return %defaults;
+}
+
+sub get_basic_input_elements
+{
+	my( $self, $session, $value, $basename, $staff ) = @_;
+
+	my $ex = $self->SUPER::get_basic_input_elements( $session, $value, $basename, $staff );
+
+	my $desc = $self->render_single_value( $session, $value );
+
+	push @{$ex->[0]}, {el=>$desc, style=>"padding: 0 0.5em 0 0.5em;"};
+
+	return $ex;
+}
+
+sub render_single_value
+{
+	my( $self, $session, $value ) = @_;
+
+	if( !defined $value )
+	{
+		return $session->make_doc_fragment;
+	}
+
+	my $database = $session->{database};
+
+	my $sql = "SELECT ". $database->quote_identifier( $self->get_property('externalname') ) .
+		  " FROM " . $database->quote_identifier( $self->get_property('externaltable') ) .
+		  " WHERE " . $database->quote_identifier( $self->get_property('externalkey') ) . 
+		  " = " .  $database->quote_value($value) . 
+		  " LIMIT 1";
+
+	my $sth = $database->prepare( $sql );
+	my $result = $database->execute( $sth, $sql );
+	my $name = $sth->fetch;	
+
+	if( defined $name )
+	{
+		# TODO: Link?
+		my $frag = $session->make_doc_fragment;
+		$frag->appendChild( $session->make_text( @{$name}[0] ) );
+		return $frag;
+	}
+
+	return $session->html_phrase( 
+		"lib/metafield/itemref:not_found",
+			id=>$session->make_text($value),
+			objtype=>$session->make_text($self->get_property('externaltable')));
+}
+
+sub get_input_elements
+{   
+	my( $self, $session, $value, $staff, $obj, $basename ) = @_;
+
+	my $input = $self->SUPER::get_input_elements( $session, $value, $staff, $obj, $basename );
+
+	my $buttons = $session->make_doc_fragment;
+	$buttons->appendChild( 
+		$session->render_internal_buttons( 
+			$self->{name}."_null" => $session->phrase(
+				"lib/metafield/itemref:lookup" )));
+
+	push @{ $input->[0] }, {el=>$buttons};
+
+	return $input;
+}
+
+
+
+
+######################################################################
+1;
Index: perl_lib/EPrints/DataSet.pm
===================================================================
--- perl_lib/EPrints/DataSet.pm	(revision 217)
+++ perl_lib/EPrints/DataSet.pm	(revision 224)
@@ -240,6 +240,16 @@
 		index => 1,
 		datestamp => "datestamp",
 	},
+	author => {
+		sqlname => "author",	
+		class => "EPrints::DataObj::Author",
+		import => 1,
+		index => 1,
+	},
+	author_instance => {
+		sqlname => "author_instance",
+		class => "EPrints::DataObj::Author_Instance",
+	},
 };
 
 
@@ -938,7 +948,7 @@
 
 sub get_sql_dataset_ids
 {
-	return( qw/ import metafield cachemap message loginticket eprint user document saved_search subject history access request / );
+	return( qw/ import metafield cachemap message loginticket eprint user document saved_search subject history access request author author_instance / );
 }
 
 ######################################################################
Index: perl_lib/EPrints/DataObj/Author_Instance.pm
===================================================================
--- perl_lib/EPrints/DataObj/Author_Instance.pm	(revision 0)
+++ perl_lib/EPrints/DataObj/Author_Instance.pm	(revision 224)
@@ -0,0 +1,611 @@
+######################################################################
+#
+# EPrints::DataObj::Author_Instance
+#
+######################################################################
+#
+#
+# Copyright 2000-2008 University of Southampton. All Rights Reserved.
+# 
+#  This file is part of GNU EPrints 3.
+#  
+#  Copyright (c) 2000-2008 University of Southampton, UK. SO17 1BJ.
+#  
+#  EPrints 3 is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#  
+#  EPrints 3 is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#  
+#  You should have received a copy of the GNU General Public License
+#  along with EPrints 3; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+######################################################################
+
+=head1 NAME
+
+B<EPrints::DataObj::Author_Instance> - Class representing an actual Author_Instance
+
+=head1 DESCRIPTION
+
+This class represents a single author_instance record and the metadata 
+associated with it.
+
+EPrints::DataObj::Author_Instance is a subclass of EPrints::DataObj with the following
+metadata fields (plus those defined in ArchiveMetadataFieldsConfig):
+
+=head1 SYSTEM METADATA
+
+=over 4
+
+=item instanceid (int)
+
+The unique numerical ID of this author_instance. 
+
+=item authorid (itemref)
+
+The id of the author that this instance is linked to
+
+=item display_name (text)
+
+The name of this instance
+
+=item preferred (boolean)
+
+If this instance is the preferred instance for this author (exclusive field)
+
+=item created_date (time)
+
+The date this record first appeared in the repository.
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=cut
+
+######################################################################
+#
+# INSTANCE VARIABLES:
+#
+#  From EPrints::DataObj
+#
+######################################################################
+
+package EPrints::DataObj::Author_Instance;
+
+@ISA = ( 'EPrints::DataObj' );
+
+use strict;
+
+######################################################################
+=pod
+
+=item $metadata = EPrints::DataObj::Author_Instance->get_system_field_info
+
+Return an array describing the system metadata of the Author_Instance dataset.
+
+=cut
+######################################################################
+
+sub get_system_field_info
+{
+	my( $class ) = @_;
+
+	return ( 
+	{ name=>"instanceid", type=>"int", required=>1, import=>0, can_clone=>0 },
+
+	{ name=>"authorid", type=>"itemref", 
+		datasetid=>"author", required=>1 },
+
+	{ name=>"display_name", type=>"text", required=>0, },
+
+	{ name=> "preferred", type=>"boolean", },
+
+	{ name=> "created_date", type=>"time", },
+
+	);
+}
+
+
+######################################################################
+=pod
+
+=item $author_instance = EPrints::DataObj::Author_Instance->new( $session, $instance_id )
+
+Return the eprint with the given instance_id, or undef if it does not exist.
+
+=cut
+######################################################################
+
+sub new
+{
+	my( $class, $session, $author_id ) = @_;
+
+	EPrints::abort "session not defined in Author_Instance->new" unless defined $session;
+
+	my $dataset = $session->get_repository->get_dataset( "author_instance" );
+
+	return $session->get_database->get_single( $dataset , $author_id );
+}
+
+
+######################################################################
+=pod
+
+=item $eprint = EPrints::DataObj::Author_Instance->new_from_data( $session, $data, $dataset )
+
+Construct a new EPrints::DataObj::Author_Instance object based on the $data hash 
+reference of metadata.
+
+=cut
+######################################################################
+
+sub new_from_data
+{
+	my( $class, $session, $known, $dataset ) = @_;
+
+	return $class->SUPER::new_from_data(
+			$session,
+			$known,
+			$dataset );
+}
+
+	
+
+######################################################################
+# =pod
+# 
+# =item $eprint = EPrints::DataObj::Author_Instance::create( $session, $dataset, $data )
+# 
+# Create a new EPrint entry in the given dataset.
+# 
+# If data is defined, then this is used as the base for the new record.
+# Otherwise the repository specific defaults (if any) are used.
+# 
+# The fields "instanceid" and "dir" will be overridden even if they
+# are set.
+# 
+# If C<$data> is not defined calls L</set_eprint_defaults>.
+# 
+# =cut
+######################################################################
+
+sub create
+{
+	my( $session, $dataset, $data ) = @_;
+
+	return EPrints::DataObj::Author_Instance->create_from_data( 
+		$session, 
+		$data, 
+		$dataset );
+}
+
+######################################################################
+# =pod
+# 
+# =item $dataobj = EPrints::DataObj->create_from_data( $session, $data, $dataset )
+# 
+# Create a new object of this type in the database. 
+# 
+# $dataset is the dataset it will belong to. 
+# 
+# $data is the data structured as with new_from_data.
+# 
+# This will create sub objects also.
+# 
+# =cut
+######################################################################
+
+
+sub create_from_data
+{
+	my( $class, $session, $data, $dataset ) = @_;
+
+	$data->{instanceid} = $session->get_database->counter_next( "instanceid" );
+
+	my $new_instance = $class->SUPER::create_from_data( $session, $data, $dataset );
+
+	$session->get_database->counter_minimum( "instanceid", $new_instance->get_id );
+
+	return $new_instance;
+}
+
+######################################################################
+=pod
+
+=item $defaults = EPrints::DataObj::Author_Instance->get_defaults( $session, $data )
+
+Return default values for this object based on the starting data.
+
+=cut
+######################################################################
+
+sub get_defaults
+{
+	my( $class, $session, $data ) = @_;
+
+	if( !defined $data->{created_date} )
+	{
+	    $data->{created_date} = EPrints::Time::get_iso_timestamp();
+	}
+	return $data;
+}
+
+######################################################################
+=pod
+
+=item $success = $author_instance->remove
+
+Erase this author instance
+
+=cut
+######################################################################
+
+sub remove
+{
+	my( $self ) = @_;
+
+	my $success = $self->{session}->get_database->remove(
+		$self->{dataset},
+		$self->get_value( "instanceid" ) );
+
+
+	return $success;
+}
+
+
+######################################################################
+=pod
+
+=item $success = $eprint->commit( [$force] );
+
+Commit any changes that might have been made to the database.
+
+If the item has not be changed then this function does nothing unless
+$force is true.
+
+Calls L</set_eprint_automatic_fields> just before the C<$eprint> is committed.
+
+=cut
+######################################################################
+
+sub commit
+{
+	my( $self, $force ) = @_;
+
+	if( $self->{changed}->{succeeds} )
+	{
+		my $old_succ = EPrints::DataObj::Author_Instance->new( $self->{session}, $self->{changed}->{succeeds} );
+		$old_succ->succeed_thread_modified if( defined $old_succ );
+
+		my $new_succ = EPrints::DataObj::Author_Instance->new( $self->{session}, $self->{data}->{succeeds} );
+		$new_succ->succeed_thread_modified if( defined $new_succ );
+	}
+
+	$self->{session}->get_repository->call( 
+		"set_author_instance_automatic_fields", 
+		$self );
+
+
+# 	if( !$self->is_set( "datestamp" ) )
+# 	{
+# 		$self->set_value( 
+# 			"datestamp" , 
+# 			EPrints::Time::get_iso_timestamp() );
+# 	}
+
+	if( !defined $self->{changed} || scalar( keys %{$self->{changed}} ) == 0 )
+	{
+		# don't do anything if there isn't anything to do
+		return( 1 ) unless $force;
+	}
+
+	# unset the preferred bit on any previous item if this one is set
+	if( $self->get_value( "preferred" ) ) {
+		my $database = $self->{session}->get_database;
+		my $update  = "UPDATE ". $database->quote_identifier('author_instance');
+ 		$update    .= " SET ". $database->quote_identifier('preferred') . " = ". $database->quote_value('FALSE');
+		$update    .= " WHERE ". $database->quote_identifier('authorid') ." = ". $self->get_value("authorid");
+		my $stmt = $self->{session}->get_database->prepare($update);
+		$self->{session}->get_database->execute($stmt, $update); # ignore the return result of this
+	}
+
+	$self->tidy;
+	my $success = $self->{session}->get_database->update(
+		$self->{dataset},
+		$self->{data} );
+
+	if( !$success )
+	{
+		my $db_error = $self->{session}->get_database->error;
+		$self->{session}->get_repository->log( 
+			"Error committing Author Instance ".
+			$self->get_value( "instanceid" ).": ".$db_error );
+		return $success;
+	}
+
+	$self->queue_changes;
+	return( $success );
+}
+
+######################################################################
+=pod
+
+=item $problems = $eprint->validate( [$for_archive] )
+
+Return a reference to an array of XHTML DOM objects describing
+validation problems with the entire eprint.
+
+A reference to an empty array indicates no problems.
+
+Calls L</validate_eprint> for the C<$eprint>.
+
+=cut
+######################################################################
+
+sub validate
+{
+	my( $self , $for_archive ) = @_;
+
+	return [] if $self->skip_validation;
+	
+
+	# get the workflow
+
+	my %opts = ( item=> $self, session=>$self->{session} );
+	$opts{STAFF_ONLY} = [$for_archive ? "TRUE" : "FALSE","BOOLEAN"];
+ 	my $workflow = EPrints::Workflow->new( $self->{session}, "default", %opts );
+
+	my @problems = ();
+
+	push @problems, $workflow->validate;
+
+	# Now give the site specific stuff one last chance to have a gander.
+	push @problems, $self->{session}->get_repository->call( 
+			"validate_eprint", 
+			$self,
+			$self->{session},
+			$for_archive );
+
+	return( \@problems );
+}
+
+######################################################################
+=pod
+
+=item $warnings = $eprint->get_warnings
+
+Return a reference to an array of XHTML DOM objects describing
+warnings about this eprint - that is things that are not quite 
+validation errors, but it'd be nice if they were fixed.
+
+Calls L</eprint_warnings> for the C<$eprint>.
+
+=cut
+######################################################################
+
+sub get_warnings
+{
+	my( $self , $for_archive ) = @_;
+
+	# Now give the site specific stuff one last chance to have a gander.
+	my @warnings = $self->{session}->get_repository->call( 
+			"eprint_warnings", 
+			$self,
+			$self->{session} );
+
+	return \@warnings;
+}
+
+
+######################################################################
+=pod
+
+=item $boolean = $eprint->skip_validation
+
+Returns true if this eprint should pass validation without being
+properly validated. This is to allow the use of dodgey data imported
+from legacy systems.
+
+=cut
+######################################################################
+
+sub skip_validation 
+{
+	my( $self ) = @_;
+
+	my $repos = $self->{session}->get_repository;
+	if( $repos->can_call( 'skip_validation' ) )
+	{
+		return $repos->call( 'skip_validation', $self );
+	}
+	else
+	{
+		return( 0 );
+	}
+}
+
+
+
+
+######################################################################
+=pod
+
+=item @formats =  $eprint->required_formats
+
+Return a list of the required formats for this 
+eprint. Only one of the required formats is required, not all.
+
+An empty list means no format is required.
+
+=cut
+######################################################################
+
+sub required_formats
+{
+	my( $self ) = @_;
+
+	my $fmts = $self->{session}->get_repository->get_conf( 
+				"required_formats" );
+	if( ref( $fmts ) ne "ARRAY" )
+	{
+		# function pointer then...
+		$fmts = $self->{session}->get_repository->call(
+			'required_formats',
+			$self );
+	}
+
+	return @{$fmts};
+}
+
+######################################################################
+=pod
+
+=item ( $description, $title, $links ) = $eprint->render
+
+Render the eprint. The 3 returned values are references to XHTML DOM
+objects. $description is the public viewable description of this eprint
+that appears as the body of the abstract page. $title is the title of
+the abstract page for this eprint. $links is any elements which should
+go in the <head> of this page.
+
+Calls L</eprint_render> to actually render the C<$eprint>, if it isn't deleted.
+
+=cut
+######################################################################
+
+sub render_preview
+{
+	my( $self ) = @_;
+
+	return $self->render( 1 );
+}
+
+
+sub render
+{
+	my( $self ) = @_;
+
+	my( $dom, $title ) = $self->{session}->get_repository->call( "author_instance_render", $self, $self->{session} );
+
+
+	if( !defined $title )
+	{
+	#	$title = $self->render_description;
+	}
+
+	return( $dom, $title );
+}
+
+
+sub render_box_list
+{
+	my( $session, $eprint, $list ) = @_;
+
+	my $processor = bless { session=>$session, eprint=>$eprint, instanceid=>$eprint->get_id }, "EPrints::ScreenProcessor";
+	my $some_plugin = $session->plugin( "Screen", processor=>$processor );
+
+	my $chunk = $session->make_doc_fragment;
+	foreach my $item ( $some_plugin->list_items( $list ) )
+	{
+		my $i = $session->get_next_id;
+
+		my %options;
+		$options{session} = $session;
+		$options{id} = "ep_summary_box_$i";
+		$options{title} = $item->{screen}->render_title;
+		$options{content} = $item->{screen}->render;
+		$options{collapsed} = $item->{screen}->render_collapsed;
+		# $options{content_style} = "height: 100px; overflow: auto";
+		$chunk->appendChild( EPrints::Box::render( %options ) );
+	}
+
+	return $chunk;
+}
+
+######################################################################
+=pod
+
+=item $url = $eprint->get_control_url
+
+Return the URL of the control page for this eprint.
+
+=cut
+######################################################################
+
+sub get_control_url
+{
+	my( $self ) = @_;
+
+	return $self->{session}->get_repository->get_conf( "http_cgiurl" ).
+		"/users/home?screen=Author_Instance::View&instanceid=".
+		$self->get_value( "instanceid" )
+}
+
+######################################################################
+=pod
+
+=item $url = $eprint->get_url
+
+Return the public URL of this eprints abstract page. 
+
+=cut
+######################################################################
+
+sub get_url
+{
+	my( $self , $staff ) = @_;
+
+	return( $self->url_stem );
+}
+
+
+######################################################################
+=pod
+
+=back
+
+=cut
+######################################################################
+
+1; # For use/require success
+
+__END__
+
+=head1 CALLBACKS
+
+Callbacks may optionally be defined in the ArchiveConfig.
+
+=over 4
+
+=item validate_field
+
+	validate_field( $field, $value, $session, [$for_archive] )
+
+=item validate_author_instance
+
+	validate_author_instance( $instance, $session, [$for_archive] )
+	
+=item set_author_instance_defaults
+
+	set_author_instance_defaults( $data, $session )
+
+=item set_author_instance_automatic_fields
+
+	set_author_instance_automatic_fields( $instance )
+
+=item author_instance_render
+
+	author_instance_render( $instance, $session )
+
+See L<ArchiveRenderConfig/author_instance_render>.
+
+=back
Index: perl_lib/EPrints/DataObj/MetaField.pm
===================================================================
--- perl_lib/EPrints/DataObj/MetaField.pm	(revision 217)
+++ perl_lib/EPrints/DataObj/MetaField.pm	(revision 224)
@@ -205,6 +205,7 @@
 			text
 			time
 			url
+			namevalue
 	);
 
 	my $base_path = $EPrints::SystemSettings::conf->{base_path};
@@ -519,7 +520,7 @@
 
 sub get_valid_datasets
 {
-	qw( document eprint user saved_search import );
+	qw( document eprint user saved_search import author author_instance );
 }
 
 sub get_config_path
Index: perl_lib/EPrints/DataObj/User.pm
===================================================================
--- perl_lib/EPrints/DataObj/User.pm	(revision 217)
+++ perl_lib/EPrints/DataObj/User.pm	(revision 224)
@@ -212,6 +212,9 @@
 		{ name=>"review_fields", type=>"fields", datasetid=>"eprint", 
 			multiple=>1, input_ordered=>1, required=>1, volatile=>1 },
 
+		{ name=>"authorinstance_fields", type=>"fields", datasetid=>"author_instance",
+			multiple=>1, input_ordered=>1, required=>1, volatile=>1 },
+
 		{ name=>"latitude", type=>"float", required=>0 },
 
 		{ name=>"longitude", type=>"float", required=>0 },
@@ -1127,6 +1130,19 @@
 		"user/history:editor",
 		"user/staff/edit:editor",
 		"create_user",
+		"author/edit",
+		"author/merge",
+		"author/remove:editor",
+		"author/view:editor",
+		"author/history:editor",
+		"author/staff/edit:editor",
+		"author_instance/staff/edit:editor",
+		"author_instance/edit",
+		"author_instance/items",
+		"author_instance/view",
+		"author_instance/merge",
+		"create_author",
+		"staff/author_search",
 		"subject/edit:editor",
 		"staff/user_search",
 		"staff/history_search",
Index: perl_lib/EPrints/DataObj/Author.pm
===================================================================
--- perl_lib/EPrints/DataObj/Author.pm	(revision 0)
+++ perl_lib/EPrints/DataObj/Author.pm	(revision 224)
@@ -0,0 +1,605 @@
+######################################################################
+#
+# EPrints::DataObj::Author
+#
+######################################################################
+#
+#
+# Copyright 2000-2008 University of Southampton. All Rights Reserved.
+# 
+#  This file is part of GNU EPrints 3.
+#  
+#  Copyright (c) 2000-2008 University of Southampton, UK. SO17 1BJ.
+#  
+#  EPrints 3 is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#  
+#  EPrints 3 is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#  
+#  You should have received a copy of the GNU General Public License
+#  along with EPrints 3; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+######################################################################
+
+
+=pod
+
+=head1 NAME
+
+B<EPrints::DataObj::Author> - Class representing a single author.
+
+=head1 DESCRIPTION
+
+This class represents a single eprint author record and the metadata 
+associated with it. 
+
+EPrints::DataObj::Author is a subclass of EPrints::DataObj with the following
+metadata fields (plus those defined in ArchiveMetadataFieldsConfig:
+
+=head1 SYSTEM METADATA
+
+=over 4
+
+=item authorid (int)
+
+The unique ID number of this author record. Unique within the current repository.
+
+=item authorname (name)
+
+The name of this author. Used to identify this particular author. Not necessarily
+unique.
+
+=item bio (text)
+
+This biography of this author.
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=cut
+
+package EPrints::DataObj::Author;
+
+@ISA = ( 'EPrints::DataObj' );
+
+use EPrints;
+use EPrints::Search;
+
+use strict;
+
+
+######################################################################
+=pod
+
+=item $field_info = EPrints::DataObj::Author->get_system_field_info
+
+Return an array describing the system metadata of the this 
+dataset.
+
+=cut
+######################################################################
+
+sub get_system_field_info
+{
+	my( $class ) = @_;
+
+	return 
+	( 
+		{ name=>"authorid", type=>"int", required=>1, import=>0, can_clone=>0, },
+		{ name=>"bio", type=>"longtext", required=>0, },
+		{ name=>"author", type=>"name", hide_honourific=>0, hide_lineage =>1, family_first=>1, text_index=>1, },
+	)
+};
+
+
+
+######################################################################
+=pod
+
+=item $author = EPrints::DataObj::Author->new( $session, $authorid )
+
+Load the author with the ID of $authorid from the database and return
+it as an EPrints::DataObj::Author object.
+
+=cut
+######################################################################
+
+sub new
+{
+	my( $class, $session, $authorid ) = @_;
+
+	return $session->get_database->get_single( 
+		$session->get_repository->get_dataset( "author" ),
+		$authorid );
+}
+
+
+######################################################################
+=pod
+
+=item $author = EPrints::DataObj::Author->new_from_data( $session, $data )
+
+Construct a new EPrints::DataObj::Author object based on the $data hash 
+reference of metadata.
+
+Used to create an object from the data retrieved from the database.
+
+=cut
+######################################################################
+
+sub new_from_data
+{
+	my( $class, $session, $known ) = @_;
+
+	return $class->SUPER::new_from_data(
+			$session,
+			$known,
+			$session->get_repository->get_dataset( "author" ) );
+}
+
+
+
+######################################################################
+# =pod
+# 
+# =item $author = EPrints::DataObj::Author::create( $session, $author_type )
+# 
+# Create a new author in the database with the specified author type.
+# 
+# =cut
+######################################################################
+
+sub create
+{
+	my( $session, $author_type ) = @_;
+
+
+	return EPrints::DataObj::Author->create_from_data( 
+		$session, 
+		{ authortype=>$author_type },
+		$session->get_repository->get_dataset( "author" ) );
+}
+
+######################################################################
+# =pod
+# 
+# =item $dataobj = EPrints::DataObj->create_from_data( $session, $data, $dataset )
+# 
+# Create a new object of this type in the database. 
+# 
+# $dataset is the dataset it will belong to. 
+# 
+# $data is the data structured as with new_from_data.
+# 
+# =cut
+######################################################################
+
+sub create_from_data
+{
+	my( $class, $session, $data, $dataset ) = @_;
+
+	my $new_author = $class->SUPER::create_from_data( $session, $data, $dataset );
+
+	$session->get_database->counter_minimum( "authorid", $new_author->get_id );
+
+	return $new_author;
+}
+
+######################################################################
+=pod
+
+=item $defaults = EPrints::DataObj::Author->get_defaults( $session, $data )
+
+Return default values for this object based on the starting data.
+
+=cut
+######################################################################
+
+sub get_defaults
+{
+	my( $class, $session, $data ) = @_;
+
+	my $date_joined = EPrints::Time::get_iso_timestamp();
+
+	my $defaults = { 
+		"authorid"=>$data->{authorid},
+	};
+
+	if( !defined $data->{authorid} )
+	{ 
+		$defaults->{authorid} = _create_authorid( $session );
+	}
+
+	$session->get_repository->call(
+		"set_author_defaults",
+		$defaults,
+		$session );
+
+	return $defaults;
+}
+
+
+
+######################################################################
+=pod
+
+=item $author = EPrints::DataObj::Author::author_with_email( $session, $email )
+
+Return the EPrints::author with the specified $email, or undef if they
+are not found.
+
+=cut
+######################################################################
+
+sub author_with_email
+{
+	my( $session, $email ) = @_;
+	
+	my $author_ds = $session->get_repository->get_dataset( "author" );
+
+	my $searchexp = new EPrints::Search(
+		session=>$session,
+		dataset=>$author_ds );
+
+	$searchexp->add_field(
+		$author_ds->get_field( "email" ),
+		$email );
+
+	my $searchid = $searchexp->perform_search;
+	my @records = $searchexp->get_records(0,1);
+	$searchexp->dispose();
+	
+	return $records[0];
+}
+
+
+######################################################################
+=pod
+
+=item $author = EPrints::DataObj::Author::author_with_authorname( $session, $authorname )
+
+Return the EPrints::author with the specified $authorname, or undef if 
+they are not found.
+
+=cut
+######################################################################
+
+sub author_with_authorname
+{
+	my( $session, $authorname ) = @_;
+	
+	my $author_ds = $session->get_repository->get_dataset( "author" );
+
+	my $searchexp = new EPrints::Search(
+		session=>$session,
+		dataset=>$author_ds );
+
+	$searchexp->add_field(
+		$author_ds->get_field( "authorname" ),
+		$authorname,
+		"EX" );
+
+	my $results = $searchexp->perform_search;
+	my @records = $results->get_records(0,1);
+	
+	return $records[0];
+}
+
+
+######################################################################
+=pod
+
+=item $problems = $thing->validate
+
+Validate the author - find out if all the required fields are filled
+out, and that what's been filled in is OK. Returns a reference to an
+array of problem descriptions.
+
+If there are no probelms then the array is empty.
+
+The problems are XHTML DOM objects describing the problem.
+
+=cut
+######################################################################
+
+sub validate
+{
+	my( $self ) = @_;
+
+	my @problems;
+
+	my $author_ds = $self->{session}->get_repository->get_dataset( "author" );
+
+	my %opts = ( item=> $self, session=>$self->{session} );
+ 	my $workflow = EPrints::Workflow->new( $self->{session}, "default", %opts );
+
+	push @problems, $workflow->validate;
+
+	push @problems, $self->{session}->get_repository->call(
+			"validate_author",
+			$self,
+			$self->{session} );
+
+	return( \@problems );
+}
+
+
+
+######################################################################
+=pod
+
+=item $author->commit( [$force] )
+
+Write this object to the database.
+
+If $force isn't true then it only actually modifies the database
+if one or more fields have been changed.
+
+=cut
+######################################################################
+
+sub commit
+{
+	my( $self, $force ) = @_;
+
+	$self->{session}->get_repository->call( 
+		"set_author_automatic_fields", 
+		$self );
+	
+	if( !defined $self->{changed} || scalar( keys %{$self->{changed}} ) == 0 )
+	{
+		# don't do anything if there isn't anything to do
+		return( 1 ) unless $force;
+	}
+
+	# if the primary email has changed, add it to the alternate list if it isn't there
+	if( defined $self->{changed}->{primary_email} && length($self->{changed}->{primary_email}) ) {
+		if( ! grep { $self->{changed}->{primary_email} eq $_ } $self->get_value('alternate_email') ) {
+			my $alt_email = $self->get_value('alternate_email');
+			push (@{$alt_email}, $self->{changed}->{primary_email});
+			$self->set_value('alternate_email', $alt_email);
+		}
+	}
+
+
+	my $author_ds = $self->{session}->get_repository->get_dataset( "author" );
+	$self->tidy;
+	my $success = $self->{session}->get_database->update(
+		$author_ds,
+		$self->{data} );
+	
+	$self->queue_changes;
+
+	return( $success );
+}
+
+
+
+######################################################################
+=pod
+
+=item $success = $author->remove
+
+Remove this author from the database. Also, remove their instances.
+
+=cut
+######################################################################
+
+sub remove
+{
+	my( $self ) = @_;
+	
+	my $success = 1;
+
+	foreach my $author_instance ( $self->get_author_instances )
+	{
+		$author_instance->remove;
+	}
+
+	# remove author record
+	my $author_ds = $self->{session}->get_repository->get_dataset( "author" );
+	$success = $success && $self->{session}->get_database->remove(
+		$author_ds,
+		$self->get_value( "authorid" ) );
+
+	return( $success );
+}
+
+######################################################################
+=pod
+
+=item @saved_searches = $eprint->get_saved_searches
+
+Return an array of all EPrint::DataObj::SavedSearch objects associated with this
+user.
+
+=cut
+######################################################################
+
+sub get_author_instances
+{
+	my( $self ) = @_;
+
+	my $ds = $self->{session}->get_repository->get_dataset( 
+		"author_instance" );
+
+	my $searchexp = EPrints::Search->new(
+		session=>$self->{session},
+		dataset=>$ds,
+		custom_order=>"instanceid" );
+
+	$searchexp->add_field(
+		$ds->get_field( "authorid" ),
+		$self->get_value( "authorid" ) );
+
+	my $searchid = $searchexp->perform_search;
+	my @results = $searchexp->get_records;
+	$searchexp->dispose;
+
+	return( @results );
+}
+
+######################################################################
+=pod
+
+=item $boolean = $author->has_owner( $possible_owner )
+
+True if the authors are the same record.
+
+=cut
+######################################################################
+
+sub has_owner
+{
+	my( $self, $possible_owner ) = @_;
+
+	if( $possible_owner->get_value( "authorid" ) == $self->get_value( "authorid" ) )
+	{
+		return 1;
+	}
+
+	return 0;
+}
+
+######################################################################
+# 
+# $authorid = EPrints::DataObj::Author::_create_authorid( $session )
+#
+# Get the next unused authorid value.
+#
+######################################################################
+
+sub _create_authorid
+{
+	my( $session ) = @_;
+	
+	my $new_id = $session->get_database->counter_next( "authorid" );
+
+	return( $new_id );
+}
+
+
+######################################################################
+=pod
+
+=item ( $page, $title ) = $author->render
+
+Render this author into HTML using the "author_render" method in
+ArchiveRenderConfig.pm. Returns both the rendered information and
+the title as XHTML DOM.
+
+=cut
+######################################################################
+
+sub render
+{
+	my( $self ) = @_;
+
+	my( $dom, $title ) = $self->{session}->get_repository->call( "author_render", $self, $self->{session} );
+
+
+	if( !defined $title )
+	{
+		$title = $self->render_description;
+	}
+
+	return( $dom, $title );
+}
+
+
+sub render_description
+{
+	my( $self, %params ) = @_;
+	return $self->render_value("bio");
+}
+
+
+# This should include all the info, not just that presented to the public.
+
+######################################################################
+=pod
+
+=item ( $page, $title ) = $author->render_full
+
+The same as $author->render, but renders all fields, not just those 
+intended for public viewing. This is the admin view of the author.
+
+=cut
+######################################################################
+
+sub render_full
+{
+	my( $self ) = @_;
+
+	my( $table, $title ) = $self->SUPER::render_full;
+
+	my $ds = $self->{session}->get_repository->get_dataset( "saved_search" );
+	foreach my $saved_search ( $self->get_saved_searches )
+	{
+		my $rowright = $self->{session}->make_doc_fragment;
+		foreach( "frequency","spec","mailempty" )
+		{
+			my $strong;
+			$strong = $self->{session}->make_element( "strong" );
+			$strong->appendChild( $ds->get_field( $_ )->render_name( $self->{session} ) );
+			$strong->appendChild( $self->{session}->make_text( ": " ) );
+			$rowright->appendChild( $strong );
+			$rowright->appendChild( $saved_search->render_value( $_ ) );
+			$rowright->appendChild( $self->{session}->make_element( "br" ) );
+		}
+		$table->appendChild( $self->{session}->render_row(
+			$self->{session}->html_phrase(
+				"page:saved_search" ),
+			$rowright ) );
+				
+	}
+
+	return( $table, $title );
+}
+
+
+######################################################################
+=pod
+
+=item $url = $author->get_url
+
+Return the URL which will display information about this author.
+
+If $staff is true then return the URL for an administrator to view
+and modify this record.
+
+=cut
+######################################################################
+
+sub get_url
+{
+	my( $self ) = @_;
+
+	return $self->{session}->get_repository->get_conf( "http_cgiurl" )."/users/home?screen=Author::View&authorid=".$self->get_value( "authorid" );
+}
+
+sub get_control_url
+{
+	my( $self ) = @_;
+
+	return $self->{session}->get_repository->get_conf( "http_cgiurl" )."/users/home?screen=Author::View&authorid=".$self->get_value( "authorid" );
+}
+
+1;
+
+######################################################################
+=pod
+
+=back
+
+=cut
+
Index: perl_lib/EPrints/Plugin/Screen/Author_Instance.pm
===================================================================
--- perl_lib/EPrints/Plugin/Screen/Author_Instance.pm	(revision 0)
+++ perl_lib/EPrints/Plugin/Screen/Author_Instance.pm	(revision 224)
@@ -0,0 +1,116 @@
+
+package EPrints::Plugin::Screen::Author_Instance;
+
+use EPrints::Plugin::Screen;
+
+@ISA = ( 'EPrints::Plugin::Screen' );
+
+use strict;
+
+sub properties_from
+{
+	my( $self ) = @_;
+
+	# sets instanceid and author_instance to the current author_instance, if any
+	$self->SUPER::properties_from;
+
+	my $instanceid = $self->{session}->param( "instanceid" );
+
+	if( defined $instanceid )
+	{
+		$self->{processor}->{instanceid} = $instanceid;
+		$self->{processor}->{author_instance} = new EPrints::DataObj::Author_Instance( 
+						$self->{session}, 
+						$instanceid );
+	}
+
+	if( !defined $self->{processor}->{author_instance} )
+	{
+		$self->{processor}->{screenid} = "Error";
+		$self->{processor}->add_message( "error", 
+			$self->html_phrase(
+				"no_such_author_instance",
+				id => $self->{session}->make_text( 
+						$self->{processor}->{instanceid} ) ) );
+		return;
+	}
+
+	$self->{processor}->{dataset} = 
+		$self->{processor}->{author_instance}->get_dataset;
+
+}
+
+sub redirect_to_me_url
+{
+	my( $self ) = @_;
+
+	return $self->SUPER::redirect_to_me_url."&instanceid=".$self->{processor}->{instanceid};
+}
+
+sub can_be_viewed
+{
+	my( $self ) = @_;
+
+	return $self->allow( "author/view" );
+}
+
+sub allow
+{
+	my( $self, $priv ) = @_;
+
+	return 0 unless defined $self->{processor}->{author_instance};
+
+	return 1 if( $self->{session}->allow_anybody( $priv ) );
+
+	return 0 if( !defined $self->{session}->current_user );
+
+	return $self->{session}->current_user->allow( $priv, $self->{processor}->{author_instance} );
+}
+
+
+sub workflow
+{
+	my( $self, $staff ) = @_;
+
+	my $cache_id = "workflow";
+	$cache_id.= "_staff" if( $staff ); 
+
+	if( !defined $self->{processor}->{$cache_id} )
+	{
+		my %opts = ( 
+			item => $self->{processor}->{author_instance},
+			session => $self->{session} );
+		$opts{STAFF_ONLY} = [$staff ? "TRUE" : "FALSE","BOOLEAN"];
+ 		$self->{processor}->{$cache_id} = EPrints::Workflow->new( 
+			$self->{session}, 
+			"default", 
+			%opts );
+	}
+
+	return $self->{processor}->{$cache_id};
+}
+
+sub uncache_workflow
+{
+	my( $self ) = @_;
+
+	delete $self->{processor}->{workflow};
+	delete $self->{processor}->{workflow_staff};
+}
+
+
+
+sub render_hidden_bits
+{
+	my( $self ) = @_;
+
+	my $chunk = $self->{session}->make_doc_fragment;
+
+	$chunk->appendChild( $self->{session}->render_hidden_field( "instanceid", $self->{processor}->{instanceid} ) );
+	$chunk->appendChild( $self->SUPER::render_hidden_bits );
+
+	return $chunk;
+}
+
+1;
+

Property changes on: perl_lib/EPrints/Plugin/Screen/Author_Instance.pm
___________________________________________________________________
Added: svn:mergeinfo

Index: perl_lib/EPrints/Plugin/Screen/NewAuthor_Instance.pm
===================================================================
--- perl_lib/EPrints/Plugin/Screen/NewAuthor_Instance.pm	(revision 0)
+++ perl_lib/EPrints/Plugin/Screen/NewAuthor_Instance.pm	(revision 224)
@@ -0,0 +1,141 @@
+
+package EPrints::Plugin::Screen::NewAuthor_Instance;
+
+use EPrints::Plugin::Screen;
+
+@ISA = ( 'EPrints::Plugin::Screen' );
+
+use strict;
+
+sub new
+{
+	my( $class, %params ) = @_;
+
+	my $self = $class->SUPER::new(%params);
+
+	$self->{actions} = [qw/ create cancel /];
+
+	$self->{appears} = [
+		{ 
+			place => "author_actions", 	
+			position => 1000, 
+		},
+		{
+			place => "author_instance_tools",
+			position => 1000,
+		},
+	];
+
+	return $self;
+}
+
+sub can_be_viewed
+{
+	my ( $self ) = @_;
+
+	return $self->allow( "create_author" );
+}
+
+sub allow_cancel
+{
+	my ( $self ) = @_;
+
+	return 1;
+}
+
+sub action_cancel
+{
+	my( $self ) = @_;
+
+	$self->{processor}->{screenid} = "Author_Instance::Items";
+}
+
+sub allow_create
+{
+	my ( $self ) = @_;
+
+	return $self->allow( "create_author" );
+}
+
+sub action_create
+{
+	my( $self ) = @_;
+
+	my $session = $self->{session};
+	my $ds = $session->get_repository->get_dataset( "author_instance" );
+
+	my $candidate_id = $session->param( "authorid" );
+
+	unless( EPrints::Utils::is_set( $candidate_id ) )
+	{
+		$self->{processor}->add_message( 
+			"warning",
+			$self->html_phrase( "no_id" ) );
+		return;
+	}
+
+	# Attempt to create a new author
+	# Author is the name of the field, but its a name field
+	# So we need a subhash of the individual elements for it!
+	$self->{processor}->{author_instance} = $ds->create_object( $self->{session}, {
+		authorid => $candidate_id,
+		} );
+
+	if( !defined $self->{processor}->{author_instance} )
+	{
+		my $db_error = session->get_database->error;
+		$session->get_repository->log( "Database Error: $db_error" );
+		$self->{processor}->add_message( 
+			"error",
+			$self->html_phrase( "db_error" ) );
+		return;
+	}
+
+	$self->{processor}->{dataset} = $ds; # SAM: is the right thing to do here?
+	$self->{processor}->{instanceid} = $self->{processor}->{author_instance}->get_id;
+	$self->{processor}->{screenid} = "Author_Instance::Staff::Edit";
+}
+
+sub render
+{
+	my( $self ) = @_;
+
+	my $session = $self->{session};
+
+	my $page = $session->make_element( "div", class=>"ep_block" );
+
+	$page->appendChild( $self->html_phrase( "blurb" ) );
+
+	my %buttons = (
+		cancel => $self->phrase( "action:cancel:title" ),
+		create => $self->phrase( "action:create:title" ),
+		_order => [ "create", "cancel" ]
+	);
+
+	my $form = $session->render_form( "GET" );
+	$form->appendChild( 
+		$session->render_hidden_field ( "screen", "NewAuthor_Instance" ) );		
+	my $ds = $session->get_repository->get_dataset( "author_instance" );
+	my $div = $session->make_element( "div", style=>"margin-bottom: 1em" );
+	# TODO: Work out how to do this better!
+	$div->appendChild( $session->make_text( "Author ID" ) );
+	$div->appendChild( $session->make_text( ": " ) );
+	$div->appendChild( 
+		$session->make_element( 
+			"input",
+			"maxlength"=>"255",
+			"name"=>"authorid",
+			"id"=>"authorid",
+			"class"=>"ep_form_text",
+			"size"=>"20",
+			"value"=>$session->param("authorid"), ));
+	$form->appendChild( $div );
+
+	$form->appendChild( $session->render_action_buttons( %buttons ) );
+	
+	$page->appendChild( $form );
+
+	return( $page );
+}	
+
+1;

Property changes on: perl_lib/EPrints/Plugin/Screen/NewAuthor_Instance.pm
___________________________________________________________________
Added: svn:mergeinfo

Index: perl_lib/EPrints/Plugin/Screen/Author.pm
===================================================================
--- perl_lib/EPrints/Plugin/Screen/Author.pm	(revision 0)
+++ perl_lib/EPrints/Plugin/Screen/Author.pm	(revision 224)
@@ -0,0 +1,115 @@
+
+package EPrints::Plugin::Screen::Author;
+
+use EPrints::Plugin::Screen;
+
+@ISA = ( 'EPrints::Plugin::Screen' );
+
+use strict;
+
+sub properties_from
+{
+	my( $self ) = @_;
+
+	# sets authorid and author to the current author, if any
+	$self->SUPER::properties_from;
+
+	my $authorid = $self->{session}->param( "authorid" );
+	if( defined $authorid )
+	{
+		$self->{processor}->{authorid} = $authorid;
+		$self->{processor}->{author} = new EPrints::DataObj::Author(
+						$self->{session},
+						$authorid );
+	}
+
+	if( !defined $self->{processor}->{author} )
+	{
+		$self->{processor}->{screenid} = "Error";
+		$self->{processor}->add_message( "error",
+			$self->html_phrase(
+				"no_such_author",
+				id => $self->{session}->make_text(
+						$self->{processor}->{authorid} ) ) );
+		return;
+	}
+
+	$self->{processor}->{dataset} =
+		$self->{processor}->{author}->get_dataset;
+
+}
+
+sub redirect_to_me_url
+{
+	my( $self ) = @_;
+
+	return $self->SUPER::redirect_to_me_url."&authorid=".$self->{processor}->{authorid};
+}
+
+sub can_be_viewed
+{
+	my( $self ) = @_;
+
+	return $self->allow( "author/view" );
+}
+
+sub allow
+{
+	my( $self, $priv ) = @_;
+
+	return 0 unless defined $self->{processor}->{author};
+
+	return 1 if( $self->{session}->allow_anybody( $priv ) );
+
+	return 0 if( !defined $self->{session}->current_user );
+
+	return $self->{session}->current_user->allow( $priv, $self->{processor}->{author} );
+}
+
+
+sub workflow
+{
+	my( $self, $staff ) = @_;
+
+	my $cache_id = "workflow";
+	$cache_id.= "_staff" if( $staff );
+
+	if( !defined $self->{processor}->{$cache_id} )
+	{
+		my %opts = (
+			item => $self->{processor}->{author},
+			session => $self->{session} );
+		$opts{STAFF_ONLY} = [$staff ? "TRUE" : "FALSE","BOOLEAN"];
+ 		$self->{processor}->{$cache_id} = EPrints::Workflow->new(
+			$self->{session},
+			"default",
+			%opts );
+	}
+
+	return $self->{processor}->{$cache_id};
+}
+
+sub uncache_workflow
+{
+	my( $self ) = @_;
+
+	delete $self->{processor}->{workflow};
+	delete $self->{processor}->{workflow_staff};
+}
+
+
+
+sub render_hidden_bits
+{
+	my( $self ) = @_;
+
+	my $chunk = $self->{session}->make_doc_fragment;
+
+	$chunk->appendChild( $self->{session}->render_hidden_field( "authorid", $self->{processor}->{authorid} ) );
+	$chunk->appendChild( $self->SUPER::render_hidden_bits );
+
+	return $chunk;
+}
+
+1;
+
Index: perl_lib/EPrints/Plugin/Screen/Author_Instance/Edit.pm
===================================================================
--- perl_lib/EPrints/Plugin/Screen/Author_Instance/Edit.pm	(revision 0)
+++ perl_lib/EPrints/Plugin/Screen/Author_Instance/Edit.pm	(revision 224)
@@ -0,0 +1,178 @@
+
+package EPrints::Plugin::Screen::Author_Instance::Edit;
+
+use EPrints::Plugin::Screen::Author_Instance;
+
+@ISA = ( 'EPrints::Plugin::Screen::Author_Instance' );
+
+use strict;
+
+sub new
+{
+	my( $class, %params ) = @_;
+
+	my $self = $class->SUPER::new(%params);
+
+	$self->{actions} = [qw/ stop save next prev /];
+
+	$self->{staff} = 0;
+
+	return $self;
+}
+
+sub can_be_viewed
+{
+	my( $self ) = @_;
+
+	return $self->allow( "author_instance/edit" );
+}
+
+sub from
+{
+	my( $self ) = @_;
+
+	if( defined $self->{processor}->{internal} )
+	{
+		my $from_ok = $self->workflow->update_from_form( $self->{processor},undef,1 );
+		$self->uncache_workflow;
+		return unless $from_ok;
+	}
+
+	$self->EPrints::Plugin::Screen::from;
+}
+
+sub allow_stop
+{
+	my( $self ) = @_;
+
+	return $self->can_be_viewed;
+}
+
+sub action_stop
+{
+	my( $self ) = @_;
+
+	$self->{processor}->{screenid} = "Author_Instance::View";
+}
+
+
+sub allow_save
+{
+	my( $self ) = @_;
+
+	return $self->can_be_viewed;
+}
+
+sub action_save
+{
+	my( $self ) = @_;
+
+	$self->workflow->update_from_form( $self->{processor} );
+	$self->uncache_workflow;
+
+	$self->{processor}->{screenid} = "Author_Instance::View";
+}
+
+
+sub allow_prev
+{
+	my( $self ) = @_;
+
+	return $self->can_be_viewed;
+}
+
+sub action_prev
+{
+	my( $self ) = @_;
+
+	$self->workflow->update_from_form( $self->{processor} );
+	$self->uncache_workflow;
+	$self->workflow->prev;
+}
+
+
+sub allow_next
+{
+	my( $self ) = @_;
+
+	return $self->can_be_viewed;
+}
+
+sub action_next
+{
+	my( $self ) = @_;
+
+	my $from_ok = $self->workflow->update_from_form( $self->{processor} );
+	$self->uncache_workflow;
+	return unless $from_ok;
+
+	if( !defined $self->workflow->get_next_stage_id )
+	{
+		$self->{processor}->{screenid} = $self->screen_after_flow;
+		return;
+	}
+
+	$self->workflow->next;
+}
+
+
+
+sub screen_after_flow
+{
+	my( $self ) = @_;
+
+	return "Author_Instance::View";
+}
+
+
+sub render
+{
+	my( $self ) = @_;
+
+#	$self->{processor}->before_messages(
+#		$self->render_blister( $self->workflow->get_stage_id, 1 ) );
+
+	my $form = $self->render_form;
+	my $session = $self->{session};
+	$form->appendChild( $self->render_buttons );
+	$form->appendChild( $self->workflow->render );
+	$form->appendChild( $self->render_buttons );
+
+	return $form;
+}
+
+
+sub redirect_to_me_url
+{
+	my( $self ) = @_;
+
+	return $self->SUPER::redirect_to_me_url.$self->workflow->get_state_params;
+}
+
+sub render_buttons
+{
+	my( $self ) = @_;
+
+	my %buttons = ( _order=>[], _class=>"ep_form_button_bar" );
+
+	if( defined $self->workflow->get_prev_stage_id )
+	{
+		push @{$buttons{_order}}, "prev";
+		$buttons{prev} = $self->phrase( "prev" );
+	}
+
+	push @{$buttons{_order}}, "stop", "save";
+	$buttons{stop} = $self->phrase( "stop" );
+	$buttons{save} = $self->phrase( "save" );
+
+	if( defined $self->workflow->get_next_stage_id )
+	{
+		push @{$buttons{_order}}, "next";
+		$buttons{next} = $self->phrase( "next" );
+	}
+	return $self->{session}->render_action_buttons( %buttons );
+}
+
+1;
+
+
Index: perl_lib/EPrints/Plugin/Screen/Author_Instance/MergeDetails.pm
===================================================================
--- perl_lib/EPrints/Plugin/Screen/Author_Instance/MergeDetails.pm	(revision 0)
+++ perl_lib/EPrints/Plugin/Screen/Author_Instance/MergeDetails.pm	(revision 224)
@@ -0,0 +1,304 @@
+
+package EPrints::Plugin::Screen::Author_Instance::MergeDetails;
+
+use EPrints::Plugin::Screen::Author_Instance;
+
+@ISA = ( 'EPrints::Plugin::Screen::Author_Instance' );
+
+use strict;
+
+sub properties_from
+{
+	my( $self ) = @_;
+
+	# sets instanceid and author_instance to the current author_instance, if any
+	$self->SUPER::properties_from;
+
+	my $dupeid = $self->{session}->param( "duplicateid" );
+	if( defined $dupeid )
+	{
+		$self->{processor}->{dupeid} = $dupeid;
+		$self->{processor}->{dupe} = new EPrints::DataObj::Author_Instance(
+						$self->{session},
+						$dupeid );
+	}
+
+	if( !defined $self->{processor}->{dupe} )
+	{
+		$self->{processor}->{screenid} = "Error";
+		$self->{processor}->add_message( "error",
+			$self->html_phrase(
+				"no_such_author_instance_dupe",
+				id => $self->{session}->make_text(
+						$self->{processor}->{dupeid} ) ) );
+		return;
+	}
+}
+
+sub new
+{
+	my( $class, %params ) = @_;
+
+	my $self = $class->SUPER::new(%params);
+
+	$self->{actions} = [qw/ stop merge /];
+
+	return $self;
+}
+
+sub can_be_viewed
+{
+	my( $self ) = @_;
+
+	return $self->allow( "author_instance/merge" );
+}
+
+sub from
+{
+	my( $self ) = @_;
+
+	if( defined $self->{processor}->{internal} )
+	{
+		my $from_ok = $self->workflow->update_from_form( $self->{processor},undef,1 );
+		$self->uncache_workflow;
+		return unless $from_ok;
+	}
+
+	$self->EPrints::Plugin::Screen::from;
+}
+
+sub allow_stop
+{
+	my( $self ) = @_;
+
+	return $self->can_be_viewed;
+}
+
+sub action_stop
+{
+	my( $self ) = @_;
+
+	$self->{processor}->{screenid} = "Author_Instance::View";
+}
+
+
+sub allow_merge
+{
+	my( $self ) = @_;
+
+	return $self->can_be_viewed;
+}
+
+sub action_merge
+{
+	my( $self ) = @_;
+	my $session = $self->{session};
+
+	# This is so god forsakenly wrong...
+	my $dataset = $session->get_repository->get_dataset( 'author_instance' );
+	my $instanceid = $session->param("instanceid");
+	my $dataobj = $dataset->get_object( $session, $instanceid );
+
+	# Grab the duplicate...
+	my $dupeid = $session->param("duplicateid");
+	my $dupeobj = $dataset->get_object( $session, $dupeid );
+
+	foreach my $field ( $dataset->get_fields )
+	{
+		if( $field->get_property( "multiple" ) )
+		{
+			# Throw this all together, very important that this is a reference otherwise something else gets angry later down the line
+			my @merged_values = ( @{$dataobj->get_value( $field->{name} )}, @{$dupeobj->get_value( $field->{name} )} );
+			$dataobj->set_value( $field->{name}, \@merged_values );
+		}
+		else
+		{
+			my $value = $field->form_value_single( $self->{session}, $field->{name}, $dataobj );
+			$dataobj->set_value( $field->{name}, $value );
+		}
+	}
+
+	$dataobj->commit; # commit the new one
+	$dupeobj->remove; # remove the old one
+
+	# and we're done!
+	$self->{processor}->{screenid} = "Author_Instance::View";
+
+	# Should we perhaps do this in the dataobj's themselves?
+}
+
+
+sub screen_after_flow
+{
+	my( $self ) = @_;
+
+	return "Author_Instance::View";
+}
+
+
+sub render
+{
+	my( $self ) = @_;
+
+# 	$self->{processor}->before_messages(
+# 		$self->render_blister( $self->workflow->get_stage_id, 1 ) );
+
+	my $form = $self->render_form;
+	my $session = $self->{session};
+	$form->appendChild( $self->render_buttons );
+
+	my $frag = $session->make_element( 'div', 'align'=>'center' );
+
+	my $p1 = $session->make_element( 'p' );
+	$p1->appendChild( $session->html_phrase( "Plugin/Screen/Author_Instance/MergeDetails:author_instance_merge_desc" ) );
+
+	$frag->appendChild( $p1 );
+
+	my $dataset = $session->get_repository->get_dataset( 'author_instance' );
+	my $instanceid = $session->param("instanceid");
+
+	my $p2 = $session->make_element( 'p' );
+	my $obj = $dataset->get_object( $session, $instanceid );
+	$p2->appendChild( $session->html_phrase( "Plugin/Screen/Author_Instance/MergeDetails:primary_author_instance" ) );
+ 	$p2->appendChild($obj->render_citation_link);
+	$frag->appendChild( $p2 );
+
+	my $p3 = $session->make_element( 'p' );
+	my $duplicateid = $session->param("duplicateid");
+	my $dupeobj = $dataset->get_object( $session, $duplicateid );
+	$p3->appendChild( $session->html_phrase( "Plugin/Screen/Author_Instance/MergeDetails:duplicate_author_instance" ) );
+ 	$p3->appendChild($dupeobj->render_citation_link);
+	$frag->appendChild( $p3 );
+
+	my $p4 = $session->make_element( 'p' );
+	my $base_data = $obj->get_data;
+	use Data::Dumper;
+
+	my $table = $session->make_element( "table", class=>"ep_form_input_grid" );
+	foreach my $field ( $dataset->get_fields )
+	{
+		my $reftype = ref( $base_data->{$field->get_name} );
+		my $field = $dataset->get_field( $field->get_name );
+		my $value = $obj->get_value( $field->get_name );
+		my $basename = $field->get_name;
+		my $staff = 0;
+
+		next if $field->get_name eq $dataset->get_key_field->get_name;
+
+		unless( $field->get_property( "multiple" ) )
+		{
+# 			$p4->appendChild( $field->render_single_value( $session, $obj->get_value( $field->get_name ) ) );
+# 			$p4->appendChild( $session->make_element( 'br' ) );
+			my $tr = $session->make_element( "tr" );
+			# override the style sheet
+			my %common_td_style = ( style=>"vertical-align: top;" );
+			my $td_fieldname = $session->make_element( "td", %common_td_style );
+			$td_fieldname->appendChild( $session->make_text( $field->get_name ) );
+			$tr->appendChild( $td_fieldname );
+			# Single fields
+			my $td_left = $session->make_element( "td", %common_td_style );
+			# Render as value
+			$td_left->appendChild( $field->render_single_value( $session, $obj->get_value( $field->get_name ) ) );
+
+			# Render as fields
+# 			my $left_elements = $field->get_input_elements_single( $session, $obj->get_value( $field->get_name ), 'left_'.$field->get_name, 0, $obj );
+# 			foreach my $element ( @{$left_elements} )
+# 			{
+# 				my $cols = [ ];
+# 				foreach my $subelement ( @{$element} )
+# 				{
+# 					#$td_left->appendChild( $session->make_text( Dumper( $field->get_input_col_titles( $session ) ) ) );
+# 					$td_left->appendChild( $subelement->{el} );
+# 					$td_left->appendChild( $session->make_element( 'br' ) );
+# 				}
+# 			}
+
+			my $td_right = $session->make_element( "td", %common_td_style );
+ 			$td_right->appendChild( $field->render_single_value( $session, $dupeobj->get_value( $field->get_name ) ) );
+# 			my $right_elements = $field->get_input_elements_single( $session, $dupeobj->get_value( $field->get_name ), 'right_'.$field->get_name, 0, $dupeobj );
+# 			foreach my $element ( @{$right_elements} )
+# 			{
+# 				my $cols = [ ];
+# 				foreach my $subelement ( @{$element} )
+# 				{
+# 					#$td_right->appendChild( $session->make_text( Dumper( $field->get_input_col_titles( $session ) ) ) );
+# 					$td_right->appendChild( $subelement->{el} );
+# 					$td_right->appendChild( $session->make_element( 'br' ) );
+# 				}
+# 			}
+
+			my $td_merged = $session->make_element( "td", %common_td_style );
+			my $merged_elements = $field->get_input_elements_single( $session, $obj->get_value( $field->get_name ), $field->get_name, 0, $obj );
+			foreach my $element ( @{$merged_elements} )
+			{
+				my $cols = [ ];
+				foreach my $subelement ( @{$element} )
+				{
+					$td_merged->appendChild( $subelement->{el} );
+					$td_merged->appendChild( $session->make_element( 'br' ) );
+				}
+			}
+
+
+			$tr->appendChild($td_left);
+			$tr->appendChild($td_right);
+			$tr->appendChild($td_merged);
+			$table->appendChild( $tr );
+		}
+	}
+
+	$frag->appendChild( $p4 );
+	$frag->appendChild( $table );
+
+	$form->appendChild( $frag );
+	$form->appendChild( $self->render_buttons );
+
+	return $form;
+}
+
+
+sub redirect_to_me_url
+{
+	my( $self ) = @_;
+	return $self->SUPER::redirect_to_me_url."&duplicateid=".$self->{processor}->{duplicateid}.$self->workflow->get_state_params;
+}
+
+sub render_buttons
+{
+	my( $self ) = @_;
+
+	my %buttons = ( _order=>[], _class=>"ep_form_button_bar" );
+
+	if( defined $self->workflow->get_prev_stage_id )
+	{
+		push @{$buttons{_order}}, "prev";
+		$buttons{prev} = $self->phrase( "prev" );
+	}
+
+	push @{$buttons{_order}}, "stop", "merge";
+	$buttons{stop} = $self->phrase( "stop" );
+	$buttons{merge} = $self->phrase( "merge" );
+
+	if( defined $self->workflow->get_next_stage_id )
+	{
+		push @{$buttons{_order}}, "next";
+		$buttons{next} = $self->phrase( "next" );
+	}
+	return $self->{session}->render_action_buttons( %buttons );
+}
+
+sub render_hidden_bits
+{
+	my( $self ) = @_;
+
+	my $chunk = $self->{session}->make_doc_fragment;
+
+	$chunk->appendChild( $self->{session}->render_hidden_field( "duplicateid", $self->{processor}->{dupeid} ) );
+	$chunk->appendChild( $self->SUPER::render_hidden_bits );
+
+	return $chunk;
+}
+
+1;
+
+

Property changes on: perl_lib/EPrints/Plugin/Screen/Author_Instance/MergeDetails.pm
___________________________________________________________________
Added: svn:mergeinfo

Index: perl_lib/EPrints/Plugin/Screen/Author_Instance/Staff/Edit.pm
===================================================================
--- perl_lib/EPrints/Plugin/Screen/Author_Instance/Staff/Edit.pm	(revision 0)
+++ perl_lib/EPrints/Plugin/Screen/Author_Instance/Staff/Edit.pm	(revision 224)
@@ -0,0 +1,49 @@
+
+package EPrints::Plugin::Screen::Author_Instance::Staff::Edit;
+
+use EPrints::Plugin::Screen::Author_Instance::Edit;
+
+@ISA = ( 'EPrints::Plugin::Screen::Author_Instance::Edit' );
+
+use strict;
+
+sub new
+{
+	my( $class, %params ) = @_;
+
+	my $self = $class->SUPER::new(%params);
+
+	$self->{actions} = [qw/ stop save next prev /];
+
+	$self->{icon} = "action_edit.png";
+
+	$self->{appears} = [
+		{
+			place => "author_instance_actions",
+			position => 100,
+		},
+	];
+
+	$self->{staff} = 1;
+
+	return $self;
+}
+
+sub workflow
+{
+	my( $self ) = @_;
+
+	return $self->SUPER::workflow( 1 );
+}
+
+sub can_be_viewed
+{
+	my( $self ) = @_;
+
+	return $self->allow( "author_instance/staff/edit" );
+}
+
+
+
+1;
+
Index: perl_lib/EPrints/Plugin/Screen/Author_Instance/View.pm
===================================================================
--- perl_lib/EPrints/Plugin/Screen/Author_Instance/View.pm	(revision 0)
+++ perl_lib/EPrints/Plugin/Screen/Author_Instance/View.pm	(revision 224)
@@ -0,0 +1,48 @@
+
+package EPrints::Plugin::Screen::Author_Instance::View;
+
+use EPrints::Plugin::Screen::Author_Instance;
+
+@ISA = ( 'EPrints::Plugin::Screen::Author_Instance' );
+
+use strict;
+
+sub new
+{
+	my( $class, %params ) = @_;
+
+	my $self = $class->SUPER::new(%params);
+
+	return $self;
+}
+
+sub render
+{
+	my( $self ) = @_;
+	
+	my $session = $self->{session};
+
+	my $page = $session->make_doc_fragment();
+
+	my ($data,$title) = $self->{processor}->{author_instance}->render; 
+
+	my $div = $self->{session}->make_element( "div", class=>"ep_block" );
+	$page->appendChild( $div );
+	$div->appendChild( $data );
+	
+	$page->appendChild( $self->render_action_list( "author_instance_actions", ['instanceid'] ) );
+
+	return $page;
+}
+
+
+sub can_be_viewed
+{
+	my( $self ) = @_;
+
+	return $self->allow( "author_instance/view" );
+}
+
+
+1;
+
Index: perl_lib/EPrints/Plugin/Screen/Author_Instance/Remove.pm
===================================================================
--- perl_lib/EPrints/Plugin/Screen/Author_Instance/Remove.pm	(revision 0)
+++ perl_lib/EPrints/Plugin/Screen/Author_Instance/Remove.pm	(revision 224)
@@ -0,0 +1,98 @@
+package EPrints::Plugin::Screen::Author_Instance::Remove;
+
+our @ISA = ( 'EPrints::Plugin::Screen::Author_Instance' );
+
+use strict;
+
+sub new
+{
+	my( $class, %params ) = @_;
+
+	my $self = $class->SUPER::new(%params);
+
+	$self->{appears} = [
+		{
+			place => "author_actions",
+			position => 1600,
+		}
+	];
+	
+	$self->{actions} = [qw/ remove cancel /];
+
+	return $self;
+}
+
+
+sub can_be_viewed
+{
+	my( $self ) = @_;
+
+	return $self->allow( "author_instance/remove" );
+}
+
+sub render
+{
+	my( $self ) = @_;
+
+	my $div = $self->{session}->make_element( "div", class=>"ep_block" );
+
+	$div->appendChild( $self->html_phrase("sure_delete", 
+		title=>$self->{processor}->{user}->render_description() ) );
+
+	my %buttons = (
+		cancel => $self->{session}->phrase(
+				"lib/submissionform:action_cancel" ),
+		remove => $self->{session}->phrase(
+				"lib/submissionform:action_remove" ),
+		_order => [ "remove", "cancel" ]
+	);
+
+	my $form= $self->render_form;
+	$form->appendChild( 
+		$self->{session}->render_action_buttons( 
+			%buttons ) );
+	$div->appendChild( $form );
+
+	return( $div );
+}	
+
+sub allow_remove
+{
+	my( $self ) = @_;
+
+	return $self->can_be_viewed;
+}
+
+sub allow_cancel
+{
+	my( $self ) = @_;
+
+	return 1;
+}
+
+sub action_cancel
+{
+	my( $self ) = @_;
+
+	$self->{processor}->{screenid} = "Author::View";
+}
+
+sub action_remove
+{
+	my( $self ) = @_;
+
+	$self->{processor}->{screenid} = "Admin";
+
+	if( !$self->{processor}->{user}->remove )
+	{
+		my $db_error = $self->{session}->get_database->error;
+		$self->{session}->get_repository->log( "DB error removing Author ".$self->{processor}->{user}->get_value( "userid" ).": $db_error" );
+		$self->{processor}->add_message( "message", $self->html_phrase( "user_not_removed" ) );
+		return;
+	}
+
+	$self->{processor}->add_message( "message", $self->html_phrase( "user_removed" ) );
+}
+
+
+1;
Index: perl_lib/EPrints/Plugin/Screen/Author_Instance/Merge.pm
===================================================================
--- perl_lib/EPrints/Plugin/Screen/Author_Instance/Merge.pm	(revision 0)
+++ perl_lib/EPrints/Plugin/Screen/Author_Instance/Merge.pm	(revision 224)
@@ -0,0 +1,238 @@
+
+package EPrints::Plugin::Screen::Author_Instance::Merge;
+
+use EPrints::Plugin::Screen::Author_Instance;
+
+@ISA = ( 'EPrints::Plugin::Screen::Author_Instance' );
+
+use strict;
+
+sub properties_from
+{
+	my( $self ) = @_;
+
+	# Fire the parents properties_from
+	$self->SUPER::properties_from;
+
+
+	# Get the duplicateid, used when directing away from this screen
+	my $duplicateid = $self->{session}->param( "duplicateid" );
+
+	if( defined $duplicateid )
+	{
+		$self->{processor}->{duplicateid} = $duplicateid;
+		$self->{processor}->{duplicate} = new EPrints::DataObj::Author_Instance(
+						$self->{session},
+						$duplicateid );
+	}
+}
+
+sub new
+{
+	my( $class, %params ) = @_;
+
+	my $self = $class->SUPER::new(%params);
+
+	$self->{actions} = [qw/ stop merge /];
+
+	$self->{appears} = [
+		{
+			place => "author_instance_actions",
+			position => 200,
+		}
+	];
+
+	return $self;
+}
+
+sub can_be_viewed
+{
+	my( $self ) = @_;
+
+	return $self->allow( "author_instance/merge" );
+}
+
+sub from
+{
+	my( $self ) = @_;
+
+	if( defined $self->{processor}->{internal} )
+	{
+		my $from_ok = $self->workflow->update_from_form( $self->{processor},undef,1 );
+		$self->uncache_workflow;
+		return unless $from_ok;
+	}
+
+	$self->EPrints::Plugin::Screen::from;
+}
+
+sub allow_stop
+{
+	my( $self ) = @_;
+
+	return $self->can_be_viewed;
+}
+
+sub action_stop
+{
+	my( $self ) = @_;
+
+	$self->{processor}->{screenid} = "Author_Instance::View";
+}
+
+
+sub allow_merge
+{
+	my( $self ) = @_;
+
+	return $self->can_be_viewed;
+}
+
+sub action_merge
+{
+	my( $self ) = @_;
+
+	$self->uncache_workflow;
+
+	$self->{processor}->{screenid} = "Author_Instance::MergeDetails";
+}
+
+
+sub allow_prev
+{
+	my( $self ) = @_;
+
+	return $self->can_be_viewed;
+}
+
+sub action_prev
+{
+	my( $self ) = @_;
+
+	$self->workflow->update_from_form( $self->{processor} );
+	$self->uncache_workflow;
+	$self->workflow->prev;
+}
+
+
+sub allow_next
+{
+	my( $self ) = @_;
+
+	return $self->can_be_viewed;
+}
+
+sub action_next
+{
+	my( $self ) = @_;
+
+	my $from_ok = $self->workflow->update_from_form( $self->{processor} );
+	$self->uncache_workflow;
+	return unless $from_ok;
+
+	if( !defined $self->workflow->get_next_stage_id )
+	{
+		$self->{processor}->{screenid} = $self->screen_after_flow;
+		return;
+	}
+
+	$self->workflow->next;
+}
+
+
+
+sub screen_after_flow
+{
+	my( $self ) = @_;
+
+	return "Author_Instance::MergeDetails";
+}
+
+
+sub render
+{
+	my( $self ) = @_;
+
+# 	$self->{processor}->before_messages(
+# 		$self->render_blister( $self->workflow->get_stage_id, 1 ) );
+
+	my $form = $self->render_form;
+	my $session = $self->{session};
+	$form->appendChild( $self->render_buttons );
+
+	my $frag = $session->make_element( 'div', 'align'=>'center' );
+
+	my $p1 = $session->make_element( 'p' );
+	$p1->appendChild( $session->html_phrase( "Plugin/Screen/Author_Instance/Merge:author_instance_merge_desc" ) );
+
+	$frag->appendChild( $p1 );
+
+	my $p2 = $session->make_element( 'p' );
+	my $dataset = $session->get_repository->get_dataset( 'author_instance' );
+	my $instanceid = $session->param("instanceid");
+	my $obj = $dataset->get_object( $session, $instanceid );
+	$p2->appendChild( $session->html_phrase( "Plugin/Screen/Author_Instance/Merge:primary_author_instance" ) );
+ 	$p2->appendChild($obj->render_citation_link);
+	$frag->appendChild( $p2 );
+
+	my $p3 = $session->make_element( 'p' );
+	$p3->appendChild( $session->html_phrase( "Plugin/Screen/Author_Instance/Merge:duplicate_author_instance" ) );
+
+	my %element_opts = ( name=>"duplicateid", id=>"duplicateid", type=>"text" );
+
+	my $input_element = $session->make_element( 'input', %element_opts );
+	$p3->appendChild( $input_element );
+
+	my %search_opts = (
+		class=>"ep_form_internal_button",
+		name=>"_internal_find",
+		id=>"_internal_find",
+		type=>"submit",
+		onclick=>"popup_appendfield('duplicateid', '".$session->get_repository->get_conf( "http_cgiurl" ) ."/users/popup/author_instance?validate=false&basename=duplicateid&fieldname=duplicateid&instanceid=', 400, 400); return false");
+	my $find = $session->make_element( 'button', %search_opts );
+	$find->appendChild( $session->html_phrase( "Plugin/Screen/Author_Instance/Merge:Find" ) );
+	$p3->appendChild($find);
+
+	$frag->appendChild( $p3 );
+
+	$form->appendChild( $frag );
+	$form->appendChild( $self->render_buttons );
+
+	return $form;
+}
+
+
+sub redirect_to_me_url
+{
+	my( $self ) = @_;
+
+	return $self->SUPER::redirect_to_me_url.$self->workflow->get_state_params;
+}
+
+sub render_buttons
+{
+	my( $self ) = @_;
+
+	my %buttons = ( _order=>[], _class=>"ep_form_button_bar" );
+
+	if( defined $self->workflow->get_prev_stage_id )
+	{
+		push @{$buttons{_order}}, "prev";
+		$buttons{prev} = $self->phrase( "prev" );
+	}
+
+	push @{$buttons{_order}}, "stop", "merge";
+	$buttons{stop} = $self->phrase( "stop" );
+	$buttons{merge} = $self->phrase( "merge" );
+
+	if( defined $self->workflow->get_next_stage_id )
+	{
+		push @{$buttons{_order}}, "next";
+		$buttons{next} = $self->phrase( "next" );
+	}
+	return $self->{session}->render_action_buttons( %buttons );
+}
+
+1;
+
+
Index: perl_lib/EPrints/Plugin/Screen/Author_Instance/Items.pm
===================================================================
--- perl_lib/EPrints/Plugin/Screen/Author_Instance/Items.pm	(revision 0)
+++ perl_lib/EPrints/Plugin/Screen/Author_Instance/Items.pm	(revision 224)
@@ -0,0 +1,346 @@
+
+package EPrints::Plugin::Screen::Author_Instance::Items;
+
+use EPrints::Plugin::Screen;
+
+@ISA = ( 'EPrints::Plugin::Screen' );
+
+use strict;
+
+sub new
+{
+	my( $class, %params ) = @_;
+
+	my $self = $class->SUPER::new(%params);
+
+	$self->{appears} = [
+		{
+			place => "author_actions",
+			position => 100,
+		}
+	];
+
+	$self->{actions} = [qw/ col_left col_right remove_col add_col /];
+
+	return $self;
+}
+
+sub redirect_to_me_url
+{
+	my( $self ) = @_;
+
+	return $self->SUPER::redirect_to_me_url."&authorid=".$self->{processor}->{authorid};
+}
+
+sub can_be_viewed
+{
+	my( $self ) = @_;
+
+	return $self->allow( "author_instance/items" );
+}
+
+sub allow_col_left { return $_[0]->can_be_viewed; }
+sub allow_col_right { return $_[0]->can_be_viewed; }
+sub allow_remove_col { return $_[0]->can_be_viewed; }
+sub allow_add_col { return $_[0]->can_be_viewed; }
+
+sub action_col_left
+{
+ 	my( $self ) = @_;
+ 
+ 	my $col_id = $self->{session}->param( "colid" );
+ 	my $v = $self->{session}->current_user->get_value( "authorinstance_fields" );
+ 
+ 	my @newlist = @$v;
+ 	my $a = $newlist[$col_id];
+ 	my $b = $newlist[$col_id-1];
+ 	$newlist[$col_id] = $b;
+ 	$newlist[$col_id-1] = $a;
+ 
+ 	$self->{session}->current_user->set_value( "authorinstance_fields", \@newlist );
+ 	$self->{session}->current_user->commit();
+}
+
+sub action_col_right
+{
+ 	my( $self ) = @_;
+ 
+ 	my $col_id = $self->{session}->param( "colid" );
+ 	my $v = $self->{session}->current_user->get_value( "authorinstance_fields" );
+ 
+ 	my @newlist = @$v;
+ 	my $a = $newlist[$col_id];
+ 	my $b = $newlist[$col_id+1];
+ 	$newlist[$col_id] = $b;
+ 	$newlist[$col_id+1] = $a;
+ 	
+ 	$self->{session}->current_user->set_value( "authorinstance_fields", \@newlist );
+ 	$self->{session}->current_user->commit();
+}
+sub action_add_col
+{
+ 	my( $self ) = @_;
+ 
+ 	my $col = $self->{session}->param( "col" );
+ 	my $v = $self->{session}->current_user->get_value( "authorinstance_fields" );
+ 
+ 	my @newlist = @$v;
+ 	push @newlist, $col;	
+ 	
+ 	$self->{session}->current_user->set_value( "authorinstance_fields", \@newlist );
+ 	$self->{session}->current_user->commit();
+}
+sub action_remove_col
+{
+ 	my( $self ) = @_;
+ 
+ 	my $col_id = $self->{session}->param( "colid" );
+ 	my $v = $self->{session}->current_user->get_value( "authorinstance_fields" );
+ 
+ 	my @newlist = @$v;
+ 	splice( @newlist, $col_id, 1 );
+ 	
+ 	$self->{session}->current_user->set_value( "authorinstance_fields", \@newlist );
+ 	$self->{session}->current_user->commit();
+}
+	
+sub render_links
+{
+	my( $self ) = @_;
+
+	my $style = $self->{session}->make_element( "style", type=>"text/css" );
+	$style->appendChild( $self->{session}->make_text( ".ep_tm_main { width: 90%; }" ) );
+
+	return $style;
+}
+
+sub render
+{
+	my( $self ) = @_;
+
+	my $session = $self->{session};
+
+	my $chunk = $session->make_doc_fragment;
+
+	my $user = $session->current_user;
+
+	if( $session->get_lang->has_phrase( $self->html_phrase_id( "intro" ) ) )
+	{
+		my $intro_div_outer = $session->make_element( "div", class => "ep_toolbox" );
+		my $intro_div = $session->make_element( "div", class => "ep_toolbox_content" );
+		$intro_div->appendChild( $self->html_phrase( "intro" ) );
+		$intro_div_outer->appendChild( $intro_div );
+		$chunk->appendChild( $intro_div_outer );
+	}
+
+	my $imagesurl = $session->get_repository->get_conf( "rel_path" )."/style/images";
+
+	my %options;
+ 	$options{session} = $session;
+	$options{id} = "ep_review_instructions";
+	$options{title} = $session->html_phrase( "Plugin/Screen/Author_Instance/Items:help_title" );
+	$options{content} = $session->html_phrase( "Plugin/Screen/Author_Instance/Items:help" );
+	$options{collapsed} = 1;
+	$options{show_icon_url} = "$imagesurl/help.gif";
+	my $box = $session->make_element( "div", style=>"text-align: left" );
+	$box->appendChild( EPrints::Box::render( %options ) );
+	$chunk->appendChild( $box );
+
+	$chunk->appendChild( $self->render_action_list_bar( "author_instance_tools", ['authorid'] ) );
+
+
+	### Get the items owned by the current user
+	my $ds = $session->get_repository->get_dataset( "author_instance" );
+	
+	my $searchexp = new EPrints::Search(
+		session=>$self->{session},
+		custom_order=>"instanceid",
+		dataset=>$ds );
+
+	# TODO: Should we pull this out of the params or not?
+	$searchexp->add_field(
+		$ds->get_field( "authorid" ),
+ 		$session->param('authorid') );
+
+	my $list = $searchexp->perform_search;
+
+	my $columns = $session->current_user->get_value( "authorinstance_fields" );
+	if( !EPrints::Utils::is_set( $columns ) )
+	{
+		$columns = [ "instanceid","authorid","display_name","created_date"];
+		$session->current_user->set_value( "authorinstance_fields", $columns );
+		$session->current_user->commit;
+	}
+
+	my $len = scalar @{$columns};
+
+	my $final_row = undef;
+	if( $len > 1 )
+	{	
+		$final_row = $session->make_element( "tr" );
+		my $imagesurl = $session->get_repository->get_conf( "rel_path" )."/style/images";
+		for(my $i=0; $i<$len;++$i )
+		{
+			my $col = $columns->[$i];
+			# Column headings
+			my $td = $session->make_element( "td", class=>"ep_columns_alter" );
+			$final_row->appendChild( $td );
+	
+			my $acts_table = $session->make_element( "table", cellpadding=>0, cellspacing=>0, border=>0, width=>"100%" );
+			my $acts_row = $session->make_element( "tr" );
+			my $acts_td1 = $session->make_element( "td", align=>"left", width=>"14" );
+			my $acts_td2 = $session->make_element( "td", align=>"center", width=>"100%");
+			my $acts_td3 = $session->make_element( "td", align=>"right", width=>"14" );
+			$acts_table->appendChild( $acts_row );
+			$acts_row->appendChild( $acts_td1 );
+			$acts_row->appendChild( $acts_td2 );
+			$acts_row->appendChild( $acts_td3 );
+			$td->appendChild( $acts_table );
+
+			if( $i!=0 )
+			{
+				my $form_l = $session->render_form( "post" );
+				$form_l->appendChild( 
+					$session->render_hidden_field( "screen", "Author_Instance::Items" ) );
+				$form_l->appendChild( 
+					$session->render_hidden_field( "colid", $i ) );
+				$form_l->appendChild( $session->make_element( 
+					"input",
+					type=>"image",
+					value=>"Move Left",
+					title=>"Move Left",
+					src => "$imagesurl/left.png",
+					alt => "<",
+					name => "_action_col_left" ) );
+				$form_l->appendChild($session->render_hidden_field( "authorid", $session->param('authorid') ) );
+				$acts_td1->appendChild( $form_l );
+			}
+			else
+			{
+				$acts_td1->appendChild( $session->make_element("img",src=>"$imagesurl/noicon.png",alt=>"") );
+			}
+
+			my $msg = $self->phrase( "remove_column_confirm" );
+			my $form_rm = $session->render_form( "post" );
+			$form_rm->appendChild( 
+				$session->render_hidden_field( "screen", "Author_Instance::Items" ) );
+			$form_rm->appendChild( 
+				$session->render_hidden_field( "colid", $i ) );
+			$form_rm->appendChild( $session->make_element( 
+				"input",
+				type=>"image",
+				value=>"Remove Column",
+				title=>"Remove Column",
+				src => "$imagesurl/delete.png",
+				alt => "X",
+				onclick => "if( window.event ) { window.event.cancelBubble = true; } return confirm( ".EPrints::Utils::js_string($msg).");",
+				name => "_action_remove_col" ) );
+			$form_rm->appendChild($session->render_hidden_field( "authorid", $session->param('authorid') ) );
+			$acts_td2->appendChild( $form_rm );
+
+			if( $i!=$len-1 )
+			{
+				my $form_r = $session->render_form( "post" );
+				$form_r->appendChild( 
+					$session->render_hidden_field( "screen", "Author_Instance::Items" ) );
+				$form_r->appendChild( 
+					$session->render_hidden_field( "colid", $i ) );
+				$form_r->appendChild( $session->make_element( 
+					"input",
+					type=>"image",
+					value=>"Move Right",
+					title=>"Move Right",
+					src => "$imagesurl/right.png",
+					alt => ">",
+					name => "_action_col_right" ) );
+				$form_r->appendChild($session->render_hidden_field( "authorid", $session->param('authorid') ) );
+				$acts_td3->appendChild( $form_r );
+			}
+			else
+			{
+				$acts_td3->appendChild( $session->make_element("img",src=>"$imagesurl/noicon.png",alt=>"")  );
+			}
+		}
+		my $td = $session->make_element( "td", class=>"ep_columns_alter ep_columns_alter_last" );
+		$final_row->appendChild( $td );
+	}
+
+	# Paginate list
+	my %opts = (
+		params => {
+			screen => "Author_Instance::Items",
+			authorid => $session->param('authorid'),
+		},
+		columns => [@{$columns}, undef ],
+		render_result => sub {
+			my( $session, $author_instance ) = @_;
+			my $tr = $session->make_element( "tr" );
+
+			my $first = 1;
+			for( @$columns )
+			{
+				my $td = $session->make_element( "td", class=>"ep_columns_cell ep_columns_cell_inbox".($first?" ep_columns_cell_first":"")." ep_columns_cell_$_"  );
+				$first = 0;
+				$tr->appendChild( $td );
+				$td->appendChild( $author_instance->render_value( $_ ) );
+			}
+
+			$self->{processor}->{author_instance} = $author_instance;
+			$self->{processor}->{instanceid} = $author_instance->get_id;
+			my $td = $session->make_element( "td", class=>"ep_columns_cell ep_columns_cell_last", align=>"left" );
+			$tr->appendChild( $td );
+			$td->appendChild( 
+				$self->render_action_list_icons( "author_instance_actions", ['instanceid'] ) );
+			delete $self->{processor}->{author_instance};
+			return $tr;
+		},
+		rows_after => $final_row,
+	);
+	$chunk->appendChild( EPrints::Paginate::Columns->paginate_list( $session, "_authorinstance", $list, %opts ) );
+
+
+	# Add form
+	my $div = $session->make_element( "div", class=>"ep_columns_add" );
+	my $form_add = $session->render_form( "post" );
+	$form_add->appendChild( $session->render_hidden_field( "screen", "Author_Instance::Items" ) );
+
+	my $colcurr = {};
+	foreach( @$columns ) { $colcurr->{$_} = 1; }
+	my $fieldnames = {};
+        foreach my $field ( $ds->get_fields )
+        {
+                next unless $field->get_property( "show_in_fieldlist" );
+		next if $colcurr->{$field->get_name};
+		my $name = EPrints::Utils::tree_to_utf8( $field->render_name( $session ) );
+		my $parent = $field->get_property( "parent_name" );
+		if( defined $parent ) 
+		{
+			my $pfield = $ds->get_field( $parent );
+			$name = EPrints::Utils::tree_to_utf8( $pfield->render_name( $session )).": $name";
+		}
+		$fieldnames->{$field->get_name} = $name;
+        }
+
+	my @tags = sort { $fieldnames->{$a} cmp $fieldnames->{$b} } keys %$fieldnames;
+
+	$form_add->appendChild( $session->render_option_list( 
+		name => 'col',
+		height => 1,
+		multiple => 0,
+		'values' => \@tags,
+		labels => $fieldnames ) );
+		
+	$form_add->appendChild( 
+			$session->render_button(
+				class=>"ep_form_action_button",
+				name=>"_action_add_col", 
+				value => $self->phrase( "add" ) ) );
+	$form_add->appendChild($session->render_hidden_field( "authorid", $session->param('authorid') ) );
+	$div->appendChild( $form_add );
+	$chunk->appendChild( $div );
+	# End of Add form
+	return $chunk;
+}
+
+
+1;

Property changes on: perl_lib/EPrints/Plugin/Screen/Author_Instance
___________________________________________________________________
Added: svn:mergeinfo

Index: perl_lib/EPrints/Plugin/Screen/NewAuthor.pm
===================================================================
--- perl_lib/EPrints/Plugin/Screen/NewAuthor.pm	(revision 0)
+++ perl_lib/EPrints/Plugin/Screen/NewAuthor.pm	(revision 224)
@@ -0,0 +1,149 @@
+
+package EPrints::Plugin::Screen::NewAuthor;
+
+use EPrints::Plugin::Screen;
+
+@ISA = ( 'EPrints::Plugin::Screen' );
+
+use strict;
+
+sub new
+{
+	my( $class, %params ) = @_;
+
+	my $self = $class->SUPER::new(%params);
+
+	$self->{actions} = [qw/ create cancel /];
+
+	$self->{appears} = [
+		{ 
+			place => "admin_actions", 	
+			position => 1000, 
+		},
+	];
+
+	return $self;
+}
+
+sub can_be_viewed
+{
+	my ( $self ) = @_;
+
+	return $self->allow( "create_author" );
+}
+
+sub allow_cancel
+{
+	my ( $self ) = @_;
+
+	return 1;
+}
+
+sub action_cancel
+{
+	my( $self ) = @_;
+
+	$self->{processor}->{screenid} = "Admin";
+}
+
+sub allow_create
+{
+	my ( $self ) = @_;
+
+	return $self->allow( "create_author" );
+}
+
+sub action_create
+{
+	my( $self ) = @_;
+
+	my $session = $self->{session};
+	my $ds = $session->get_repository->get_dataset( "author" );
+
+	my $candidate_firstname = $session->param( "author_given" );
+	my $candidate_lastname = $session->param( "author_family" );
+
+	unless( EPrints::Utils::is_set( $candidate_lastname ) || EPrints::Utils::is_set( $candidate_firstname ) )
+	{
+		$self->{processor}->add_message( 
+			"warning",
+			$self->html_phrase( "no_name" ) );
+		return;
+	}
+
+	# Attempt to create a new author
+	# Author is the name of the field, but its a name field
+	# So we need a subhash of the individual elements for it!
+	$self->{processor}->{author} = $ds->create_object( $self->{session}, {
+		author => {given=>$candidate_firstname, family=>$candidate_lastname },
+		} );
+
+	if( !defined $self->{processor}->{author} )
+	{
+		my $db_error = session->get_database->error;
+		$session->get_repository->log( "Database Error: $db_error" );
+		$self->{processor}->add_message( 
+			"error",
+			$self->html_phrase( "db_error" ) );
+		return;
+	}
+
+	$self->{processor}->{authorid} = $self->{processor}->{author}->get_id;
+	$self->{processor}->{screenid} = "Author::Staff::Edit";
+}
+
+sub render
+{
+	my( $self ) = @_;
+
+	my $session = $self->{session};
+
+	my $page = $session->make_element( "div", class=>"ep_block" );
+
+	$page->appendChild( $self->html_phrase( "blurb" ) );
+
+	my %buttons = (
+		cancel => $self->phrase( "action:cancel:title" ),
+		create => $self->phrase( "action:create:title" ),
+		_order => [ "create", "cancel" ]
+	);
+
+	my $form = $session->render_form( "GET" );
+	$form->appendChild( 
+		$session->render_hidden_field ( "screen", "NewAuthor" ) );		
+	my $ds = $session->get_repository->get_dataset( "author" );
+	my $div = $session->make_element( "div", style=>"margin-bottom: 1em" );
+	# TODO: Work out how to do this better!
+	$div->appendChild( $session->make_text( "Given Name" ) );
+	$div->appendChild( $session->make_text( ": " ) );
+	$div->appendChild( 
+		$session->make_element( 
+			"input",
+			"maxlength"=>"255",
+			"name"=>"author_given",
+			"id"=>"author_given",
+			"class"=>"ep_form_text",
+			"size"=>"20", ));
+	$form->appendChild( $div );
+
+	$div = $session->make_element( "div", style=>"margin-bottom: 1em" );
+	# TODO: Work out how to do this better!
+	$div->appendChild( $session->make_text( "Family Name" ) );
+	$div->appendChild( $session->make_text( ": " ) );
+	$div->appendChild( 
+		$session->make_element( 
+			"input",
+			"maxlength"=>"255",
+			"name"=>"author_family",
+			"id"=>"author_family",
+			"class"=>"ep_form_text",
+			"size"=>"20", ));
+	$form->appendChild( $div );
+	$form->appendChild( $session->render_action_buttons( %buttons ) );
+	
+	$page->appendChild( $form );
+
+	return( $page );
+}	
+
+1;
Index: perl_lib/EPrints/Plugin/Screen/Author/Edit.pm
===================================================================
--- perl_lib/EPrints/Plugin/Screen/Author/Edit.pm	(revision 0)
+++ perl_lib/EPrints/Plugin/Screen/Author/Edit.pm	(revision 224)
@@ -0,0 +1,182 @@
+
+package EPrints::Plugin::Screen::Author::Edit;
+
+use EPrints::Plugin::Screen::Author;
+
+@ISA = ( 'EPrints::Plugin::Screen::Author' );
+
+use strict;
+
+sub new
+{
+	my( $class, %params ) = @_;
+
+	my $self = $class->SUPER::new(%params);
+
+	$self->{actions} = [qw/ stop save next prev /];
+
+	$self->{appears} = [
+		{
+			place => "author_actions",
+			position => 2000,
+		}
+	];
+
+	$self->{staff} = 0;
+
+	return $self;
+}
+
+sub can_be_viewed
+{
+	my( $self ) = @_;
+
+	return $self->allow( "author/edit" );
+}
+
+sub from
+{
+	my( $self ) = @_;
+
+	if( defined $self->{processor}->{internal} )
+	{
+		my $from_ok = $self->workflow->update_from_form( $self->{processor},undef,1 );
+		$self->uncache_workflow;
+		return unless $from_ok;
+	}
+
+	$self->EPrints::Plugin::Screen::from;
+}
+
+sub allow_stop
+{
+	my( $self ) = @_;
+
+	return $self->can_be_viewed;
+}
+
+sub action_stop
+{
+	my( $self ) = @_;
+
+	$self->{processor}->{screenid} = "Author::View";
+}	
+
+
+sub allow_save
+{
+	my( $self ) = @_;
+
+	return $self->can_be_viewed;
+}
+
+sub action_save
+{
+	my( $self ) = @_;
+
+	$self->workflow->update_from_form( $self->{processor} );
+	$self->uncache_workflow;
+	
+	$self->{processor}->{screenid} = "Author::View";
+}
+
+
+sub allow_prev
+{
+	my( $self ) = @_;
+
+	return $self->can_be_viewed;
+}
+	
+sub action_prev
+{
+	my( $self ) = @_;
+
+	$self->workflow->update_from_form( $self->{processor} );
+	$self->uncache_workflow;
+	$self->workflow->prev;
+}
+
+
+sub allow_next
+{
+	my( $self ) = @_;
+
+	return $self->can_be_viewed;
+}
+
+sub action_next
+{
+	my( $self ) = @_;
+
+	my $from_ok = $self->workflow->update_from_form( $self->{processor} );
+	$self->uncache_workflow;
+	return unless $from_ok;
+
+	if( !defined $self->workflow->get_next_stage_id )
+	{
+		$self->{processor}->{screenid} = $self->screen_after_flow;
+		return;
+	}
+
+	$self->workflow->next;
+}
+
+
+
+sub screen_after_flow
+{
+	my( $self ) = @_;
+
+	return "Author::View";
+}
+
+
+sub render
+{
+	my( $self ) = @_;
+
+	my $form = $self->render_form;
+	my $session = $self->{session};
+	$form->appendChild( $self->render_buttons );
+	$form->appendChild( $self->workflow->render );
+	$form->appendChild( $self->render_buttons );
+	
+	return $form;
+}
+
+
+sub redirect_to_me_url
+{
+	my( $self ) = @_;
+
+	return $self->SUPER::redirect_to_me_url.$self->workflow->get_state_params;
+}
+
+sub render_buttons
+{
+	my( $self ) = @_;
+
+	my %buttons = ( _order=>[], _class=>"ep_form_button_bar" );
+
+	if( defined $self->workflow->get_prev_stage_id )
+	{
+		push @{$buttons{_order}}, "prev";
+		$buttons{prev} = $self->phrase( "prev" );
+	}
+
+	push @{$buttons{_order}}, "stop", "save";
+	$buttons{stop} = $self->phrase( "stop" );
+	$buttons{save} = $self->phrase( "save" );
+
+	if( defined $self->workflow->get_next_stage_id )
+	{
+		push @{$buttons{_order}}, "next";
+		$buttons{next} = $self->phrase( "next" );
+	}	
+	return $self->{session}->render_action_buttons( %buttons );
+}
+
+1;
+
+
Index: perl_lib/EPrints/Plugin/Screen/Author/MergeDetails.pm
===================================================================
--- perl_lib/EPrints/Plugin/Screen/Author/MergeDetails.pm	(revision 0)
+++ perl_lib/EPrints/Plugin/Screen/Author/MergeDetails.pm	(revision 224)
@@ -0,0 +1,308 @@
+
+package EPrints::Plugin::Screen::Author::MergeDetails;
+
+use EPrints::Plugin::Screen::Author;
+
+@ISA = ( 'EPrints::Plugin::Screen::Author' );
+
+use strict;
+
+sub properties_from
+{
+	my( $self ) = @_;
+
+	# sets authorid and author to the current author, if any
+	$self->SUPER::properties_from;
+
+	my $dupeid = $self->{session}->param( "duplicateid" );
+	if( defined $dupeid )
+	{
+		$self->{processor}->{dupeid} = $dupeid;
+		$self->{processor}->{dupe} = new EPrints::DataObj::Author(
+						$self->{session},
+						$dupeid );
+	}
+
+	if( !defined $self->{processor}->{dupe} )
+	{
+		$self->{processor}->{screenid} = "Error";
+		$self->{processor}->add_message( "error",
+			$self->html_phrase(
+				"no_such_author_dupe",
+				id => $self->{session}->make_text(
+						$self->{processor}->{dupeid} ) ) );
+		return;
+	}
+}
+
+sub new
+{
+	my( $class, %params ) = @_;
+
+	my $self = $class->SUPER::new(%params);
+
+	$self->{actions} = [qw/ stop merge /];
+
+	return $self;
+}
+
+sub can_be_viewed
+{
+	my( $self ) = @_;
+
+	return $self->allow( "author/merge" );
+}
+
+sub from
+{
+	my( $self ) = @_;
+
+	if( defined $self->{processor}->{internal} )
+	{
+		my $from_ok = $self->workflow->update_from_form( $self->{processor},undef,1 );
+		$self->uncache_workflow;
+		return unless $from_ok;
+	}
+
+	$self->EPrints::Plugin::Screen::from;
+}
+
+sub allow_stop
+{
+	my( $self ) = @_;
+
+	return $self->can_be_viewed;
+}
+
+sub action_stop
+{
+	my( $self ) = @_;
+
+	$self->{processor}->{screenid} = "Author::View";
+}
+
+
+sub allow_merge
+{
+	my( $self ) = @_;
+
+	return $self->can_be_viewed;
+}
+
+sub action_merge
+{
+	my( $self ) = @_;
+	my $session = $self->{session};
+
+	# This is so god forsakenly wrong...
+	my $dataset = $session->get_repository->get_dataset( 'author' );
+	my $authorid = $session->param("authorid");
+	my $dataobj = $dataset->get_object( $session, $authorid );
+
+	# Grab the duplicate...
+	my $dupeid = $session->param("duplicateid");
+	my $dupeobj = $dataset->get_object( $session, $dupeid );
+
+	use Data::Dumper;
+
+	foreach my $field ( $dataset->get_fields )
+	{
+		if( $field->get_property( "multiple" ) )
+		{
+			# Throw this all together, very important that this is a reference otherwise something else gets angry later down the line
+			my @merged_values = ( @{$dataobj->get_value( $field->{name} )}, @{$dupeobj->get_value( $field->{name} )} );
+			$dataobj->set_value( $field->{name}, \@merged_values );
+		}
+		else
+		{
+			my $value = $field->form_value_single( $self->{session}, $field->{name}, $dataobj );
+			$dataobj->set_value( $field->{name}, $value );
+		}
+	}
+
+	my $database = $session->get_database;
+ 	my $sql  = "UPDATE ". $database->quote_identifier('author_instance');
+	   $sql .= " SET ". $database->quote_identifier('authorid') . " = " . EPrints::Database::prep_int($authorid);
+	   $sql .= " WHERE ". $database->quote_identifier('authorid') ." = ". EPrints::Database::prep_int($dupeid);
+ 	my $sth = $database->prepare( $sql );
+ 	$database->execute( $sth , $sql );
+
+	$dataobj->commit; # commit the new one
+	$dupeobj->remove; # remove the old one
+
+	# and we're done!
+	$self->{processor}->{screenid} = "Author::View";
+}
+
+
+sub screen_after_flow
+{
+	my( $self ) = @_;
+
+	return "Author::View";
+}
+
+
+sub render
+{
+	my( $self ) = @_;
+
+# 	$self->{processor}->before_messages(
+# 		$self->render_blister( $self->workflow->get_stage_id, 1 ) );
+
+	my $form = $self->render_form;
+	my $session = $self->{session};
+	$form->appendChild( $self->render_buttons );
+
+	my $frag = $session->make_element( 'div', 'align'=>'center' );
+
+	my $p1 = $session->make_element( 'p' );
+	$p1->appendChild( $session->html_phrase( "Plugin/Screen/Author/MergeDetails:author_merge_desc" ) );
+
+	$frag->appendChild( $p1 );
+
+	my $dataset = $session->get_repository->get_dataset( 'author' );
+	my $authorid = $session->param("authorid");
+
+	my $p2 = $session->make_element( 'p' );
+	my $obj = $dataset->get_object( $session, $authorid );
+	$p2->appendChild( $session->html_phrase( "Plugin/Screen/Author/MergeDetails:primary_author" ) );
+ 	$p2->appendChild($obj->render_citation_link);
+	$frag->appendChild( $p2 );
+
+	my $p3 = $session->make_element( 'p' );
+	my $duplicateid = $session->param("duplicateid");
+	my $dupeobj = $dataset->get_object( $session, $duplicateid );
+	$p3->appendChild( $session->html_phrase( "Plugin/Screen/Author/MergeDetails:duplicate_author" ) );
+ 	$p3->appendChild($dupeobj->render_citation_link);
+	$frag->appendChild( $p3 );
+
+	my $p4 = $session->make_element( 'p' );
+	my $base_data = $obj->get_data;
+	use Data::Dumper;
+
+	my $table = $session->make_element( "table", class=>"ep_form_input_grid" );
+	foreach my $field ( $dataset->get_fields )
+	{
+		my $reftype = ref( $base_data->{$field->get_name} );
+		my $field = $dataset->get_field( $field->get_name );
+		my $value = $obj->get_value( $field->get_name );
+		my $basename = $field->get_name;
+		my $staff = 0;
+
+		next if $field->get_name eq $dataset->get_key_field->get_name;
+
+		unless( $field->get_property( "multiple" ) )
+		{
+# 			$p4->appendChild( $field->render_single_value( $session, $obj->get_value( $field->get_name ) ) );
+# 			$p4->appendChild( $session->make_element( 'br' ) );
+			my $tr = $session->make_element( "tr" );
+			# override the style sheet
+			my %common_td_style = ( style=>"vertical-align: top;" );
+			my $td_fieldname = $session->make_element( "td", %common_td_style );
+			$td_fieldname->appendChild( $session->make_text( $field->get_name ) );
+			$tr->appendChild( $td_fieldname );
+			# Single fields
+			my $td_left = $session->make_element( "td", %common_td_style );
+			$td_left->appendChild( $field->render_single_value( $session, $obj->get_value( $field->get_name ) ) );
+# 			my $left_elements = $field->get_input_elements_single( $session, $obj->get_value( $field->get_name ), 'left_'.$field->get_name, 0, $obj );
+# 			foreach my $element ( @{$left_elements} )
+# 			{
+# 				my $cols = [ ];
+# 				foreach my $subelement ( @{$element} )
+# 				{
+# 					#$td_left->appendChild( $session->make_text( Dumper( $field->get_input_col_titles( $session ) ) ) );
+# 					$td_left->appendChild( $subelement->{el} );
+# 					$td_left->appendChild( $session->make_element( 'br' ) );
+# 				}
+# 			}
+
+			my $td_right = $session->make_element( "td", %common_td_style );
+ 			$td_right->appendChild( $field->render_single_value( $session, $dupeobj->get_value( $field->get_name ) ) );
+# 			my $right_elements = $field->get_input_elements_single( $session, $dupeobj->get_value( $field->get_name ), 'right_'.$field->get_name, 0, $dupeobj );
+# 			foreach my $element ( @{$right_elements} )
+# 			{
+# 				my $cols = [ ];
+# 				foreach my $subelement ( @{$element} )
+# 				{
+# 					#$td_right->appendChild( $session->make_text( Dumper( $field->get_input_col_titles( $session ) ) ) );
+# 					$td_right->appendChild( $subelement->{el} );
+# 					$td_right->appendChild( $session->make_element( 'br' ) );
+# 				}
+# 			}
+
+			my $td_merged = $session->make_element( "td", %common_td_style );
+			my $merged_elements = $field->get_input_elements_single( $session, $obj->get_value( $field->get_name ), $field->get_name, 0, $obj );
+			foreach my $element ( @{$merged_elements} )
+			{
+				my $cols = [ ];
+				foreach my $subelement ( @{$element} )
+				{
+					$td_merged->appendChild( $subelement->{el} );
+					$td_merged->appendChild( $session->make_element( 'br' ) );
+				}
+			}
+
+
+			$tr->appendChild($td_left);
+			$tr->appendChild($td_right);
+			$tr->appendChild($td_merged);
+			$table->appendChild( $tr );
+		}
+	}
+
+	$frag->appendChild( $p4 );
+	$frag->appendChild( $table );
+
+	$form->appendChild( $frag );
+	$form->appendChild( $self->render_buttons );
+
+	return $form;
+}
+
+
+sub redirect_to_me_url
+{
+	my( $self ) = @_;
+	return $self->SUPER::redirect_to_me_url."&duplicateid=".$self->{processor}->{duplicateid}.$self->workflow->get_state_params;
+}
+
+sub render_buttons
+{
+	my( $self ) = @_;
+
+	my %buttons = ( _order=>[], _class=>"ep_form_button_bar" );
+
+	if( defined $self->workflow->get_prev_stage_id )
+	{
+		push @{$buttons{_order}}, "prev";
+		$buttons{prev} = $self->phrase( "prev" );
+	}
+
+	push @{$buttons{_order}}, "stop", "merge";
+	$buttons{stop} = $self->phrase( "stop" );
+	$buttons{merge} = $self->phrase( "merge" );
+
+	if( defined $self->workflow->get_next_stage_id )
+	{
+		push @{$buttons{_order}}, "next";
+		$buttons{next} = $self->phrase( "next" );
+	}
+	return $self->{session}->render_action_buttons( %buttons );
+}
+
+sub render_hidden_bits
+{
+	my( $self ) = @_;
+
+	my $chunk = $self->{session}->make_doc_fragment;
+
+	$chunk->appendChild( $self->{session}->render_hidden_field( "duplicateid", $self->{processor}->{dupeid} ) );
+	$chunk->appendChild( $self->SUPER::render_hidden_bits );
+
+	return $chunk;
+}
+
+1;
+
+

Property changes on: perl_lib/EPrints/Plugin/Screen/Author/MergeDetails.pm
___________________________________________________________________
Added: svn:mergeinfo

Index: perl_lib/EPrints/Plugin/Screen/Author/Staff/Edit.pm
===================================================================
--- perl_lib/EPrints/Plugin/Screen/Author/Staff/Edit.pm	(revision 0)
+++ perl_lib/EPrints/Plugin/Screen/Author/Staff/Edit.pm	(revision 224)
@@ -0,0 +1,47 @@
+
+package EPrints::Plugin::Screen::Author::Staff::Edit;
+
+use EPrints::Plugin::Screen::Author::Edit;
+
+@ISA = ( 'EPrints::Plugin::Screen::Author::Edit' );
+
+use strict;
+
+sub new
+{
+	my( $class, %params ) = @_;
+
+	my $self = $class->SUPER::new(%params);
+
+	$self->{actions} = [qw/ stop save next prev /];
+
+	$self->{appears} = [
+		{
+			place => "author_actions",
+			position => 1000,
+		}
+	];
+
+	$self->{staff} = 1;
+
+	return $self;
+}
+
+sub workflow
+{
+	my( $self ) = @_;
+
+	return $self->SUPER::workflow( 1 );
+}
+
+sub can_be_viewed
+{
+	my( $self ) = @_;
+
+	return $self->allow( "author/staff/edit" );
+}
+
+
+
+1;
+
Index: perl_lib/EPrints/Plugin/Screen/Author/View.pm
===================================================================
--- perl_lib/EPrints/Plugin/Screen/Author/View.pm	(revision 0)
+++ perl_lib/EPrints/Plugin/Screen/Author/View.pm	(revision 224)
@@ -0,0 +1,55 @@
+
+package EPrints::Plugin::Screen::Author::View;
+
+use EPrints::Plugin::Screen::Author;
+
+@ISA = ( 'EPrints::Plugin::Screen::Author' );
+
+use strict;
+
+sub new
+{
+	my( $class, %params ) = @_;
+
+	my $self = $class->SUPER::new(%params);
+
+	$self->{appears} = [
+		{
+			place => "key_tools",
+			position => 200,
+		},
+	];
+
+	return $self;
+}
+
+sub render
+{
+	my( $self ) = @_;
+	
+	my $session = $self->{session};
+
+	my $page = $session->make_doc_fragment();
+
+	my ($data,$title) = $self->{processor}->{author}->render; 
+
+	my $div = $self->{session}->make_element( "div", class=>"ep_block" );
+	$page->appendChild( $div );
+	$div->appendChild( $data );
+	
+	$page->appendChild( $self->render_action_list( "author_actions", ['authorid'] ) );
+
+	return $page;
+}
+
+
+sub can_be_viewed
+{
+	my( $self ) = @_;
+
+	return $self->allow( "author/view" );
+}
+
+
+1;
+
Index: perl_lib/EPrints/Plugin/Screen/Author/Remove.pm
===================================================================
--- perl_lib/EPrints/Plugin/Screen/Author/Remove.pm	(revision 0)
+++ perl_lib/EPrints/Plugin/Screen/Author/Remove.pm	(revision 224)
@@ -0,0 +1,98 @@
+package EPrints::Plugin::Screen::Author::Remove;
+
+our @ISA = ( 'EPrints::Plugin::Screen::Author' );
+
+use strict;
+
+sub new
+{
+	my( $class, %params ) = @_;
+
+	my $self = $class->SUPER::new(%params);
+
+	$self->{appears} = [
+		{
+			place => "author_actions",
+			position => 1600,
+		}
+	];
+	
+	$self->{actions} = [qw/ remove cancel /];
+
+	return $self;
+}
+
+
+sub can_be_viewed
+{
+	my( $self ) = @_;
+
+	return $self->allow( "author/remove" );
+}
+
+sub render
+{
+	my( $self ) = @_;
+
+	my $div = $self->{session}->make_element( "div", class=>"ep_block" );
+
+	$div->appendChild( $self->html_phrase("sure_delete", 
+		title=>$self->{processor}->{author}->render_description() ) );
+
+	my %buttons = (
+		cancel => $self->{session}->phrase(
+				"lib/submissionform:action_cancel" ),
+		remove => $self->{session}->phrase(
+				"lib/submissionform:action_remove" ),
+		_order => [ "remove", "cancel" ]
+	);
+
+	my $form= $self->render_form;
+	$form->appendChild( 
+		$self->{session}->render_action_buttons( 
+			%buttons ) );
+	$div->appendChild( $form );
+
+	return( $div );
+}	
+
+sub allow_remove
+{
+	my( $self ) = @_;
+
+	return $self->can_be_viewed;
+}
+
+sub allow_cancel
+{
+	my( $self ) = @_;
+
+	return 1;
+}
+
+sub action_cancel
+{
+	my( $self ) = @_;
+
+	$self->{processor}->{screenid} = "Author::View";
+}
+
+sub action_remove
+{
+	my( $self ) = @_;
+
+	$self->{processor}->{screenid} = "FirstTool";
+
+	if( !$self->{processor}->{author}->remove )
+	{
+		my $db_error = $self->{session}->get_database->error;
+		$self->{session}->get_repository->log( "DB error removing Author ".$self->{processor}->{author}->get_value( "authorid" ).": $db_error" );
+		$self->{processor}->add_message( "message", $self->html_phrase( "author_not_removed" ) );
+		return;
+	}
+
+	$self->{processor}->add_message( "message", $self->html_phrase( "author_removed" ) );
+}
+
+
+1;
Index: perl_lib/EPrints/Plugin/Screen/Author/Merge.pm
===================================================================
--- perl_lib/EPrints/Plugin/Screen/Author/Merge.pm	(revision 0)
+++ perl_lib/EPrints/Plugin/Screen/Author/Merge.pm	(revision 224)
@@ -0,0 +1,238 @@
+
+package EPrints::Plugin::Screen::Author::Merge;
+
+use EPrints::Plugin::Screen::Author;
+
+@ISA = ( 'EPrints::Plugin::Screen::Author' );
+
+use strict;
+
+sub properties_from
+{
+	my( $self ) = @_;
+
+	# Fire the parents properties_from
+	$self->SUPER::properties_from;
+
+
+	# Get the duplicateid, used when directing away from this screen
+	my $duplicateid = $self->{session}->param( "duplicateid" );
+
+	if( defined $duplicateid )
+	{
+		$self->{processor}->{duplicateid} = $duplicateid;
+		$self->{processor}->{duplicate} = new EPrints::DataObj::Author( 
+						$self->{session}, 
+						$duplicateid );
+	}
+}
+
+sub new
+{
+	my( $class, %params ) = @_;
+
+	my $self = $class->SUPER::new(%params);
+
+	$self->{actions} = [qw/ stop merge /];
+
+	$self->{appears} = [
+		{
+			place => "author_actions",
+			position => 20,
+		}
+	];
+
+	return $self;
+}
+
+sub can_be_viewed
+{
+	my( $self ) = @_;
+
+	return $self->allow( "author/merge" );
+}
+
+sub from
+{
+	my( $self ) = @_;
+
+	if( defined $self->{processor}->{internal} )
+	{
+		my $from_ok = $self->workflow->update_from_form( $self->{processor},undef,1 );
+		$self->uncache_workflow;
+		return unless $from_ok;
+	}
+
+	$self->EPrints::Plugin::Screen::from;
+}
+
+sub allow_stop
+{
+	my( $self ) = @_;
+
+	return $self->can_be_viewed;
+}
+
+sub action_stop
+{
+	my( $self ) = @_;
+
+	$self->{processor}->{screenid} = "Author::View";
+}	
+
+
+sub allow_merge
+{
+	my( $self ) = @_;
+
+	return $self->can_be_viewed;
+}
+
+sub action_merge
+{
+	my( $self ) = @_;
+
+	$self->uncache_workflow;
+	
+	$self->{processor}->{screenid} = "Author::MergeDetails";
+}
+
+
+sub allow_prev
+{
+	my( $self ) = @_;
+
+	return $self->can_be_viewed;
+}
+	
+sub action_prev
+{
+	my( $self ) = @_;
+
+	$self->workflow->update_from_form( $self->{processor} );
+	$self->uncache_workflow;
+	$self->workflow->prev;
+}
+
+
+sub allow_next
+{
+	my( $self ) = @_;
+
+	return $self->can_be_viewed;
+}
+
+sub action_next
+{
+	my( $self ) = @_;
+
+	my $from_ok = $self->workflow->update_from_form( $self->{processor} );
+	$self->uncache_workflow;
+	return unless $from_ok;
+
+	if( !defined $self->workflow->get_next_stage_id )
+	{
+		$self->{processor}->{screenid} = $self->screen_after_flow;
+		return;
+	}
+
+	$self->workflow->next;
+}
+
+
+
+sub screen_after_flow
+{
+	my( $self ) = @_;
+
+	return "Author::MergeDetails";
+}
+
+
+sub render
+{
+	my( $self ) = @_;
+
+# 	$self->{processor}->before_messages( 
+# 		$self->render_blister( $self->workflow->get_stage_id, 1 ) );
+
+	my $form = $self->render_form;
+	my $session = $self->{session};
+	$form->appendChild( $self->render_buttons );
+  
+	my $frag = $session->make_element( 'div', 'align'=>'center' );
+
+	my $p1 = $session->make_element( 'p' );
+	$p1->appendChild( $session->html_phrase( "Plugin/Screen/Author/Merge:author_merge_desc" ) );
+	
+	$frag->appendChild( $p1 );
+
+	my $p2 = $session->make_element( 'p' );
+	my $dataset = $session->get_repository->get_dataset( 'author' );
+	my $authorid = $session->param("authorid");
+	my $obj = $dataset->get_object( $session, $authorid );
+	$p2->appendChild( $session->html_phrase( "Plugin/Screen/Author/Merge:primary_author" ) );
+ 	$p2->appendChild($obj->render_citation_link);
+	$frag->appendChild( $p2 );
+
+	my $p3 = $session->make_element( 'p' );
+	$p3->appendChild( $session->html_phrase( "Plugin/Screen/Author/Merge:duplicate_author" ) );
+    
+	my %element_opts = ( name=>"duplicateid", id=>"duplicateid", type=>"text" );
+
+	my $input_element = $session->make_element( 'input', %element_opts );
+	$p3->appendChild( $input_element );
+
+	my %search_opts = ( 
+		class=>"ep_form_internal_button", 
+		name=>"_internal_find", 
+		id=>"_internal_find", 
+		type=>"submit", 
+		onclick=>"popup_appendfield('duplicateid', '".$session->get_repository->get_conf( "http_cgiurl" ) ."/users/popup/author?validate=false&basename=duplicateid&fieldname=duplicateid&authorid=', 400, 400); return false");
+	my $find = $session->make_element( 'button', %search_opts );
+	$find->appendChild( $session->html_phrase( "Plugin/Screen/Author/Merge:Find" ) );
+	$p3->appendChild($find);
+
+	$frag->appendChild( $p3 );
+
+	$form->appendChild( $frag );
+	$form->appendChild( $self->render_buttons );
+	
+	return $form;
+}
+
+
+sub redirect_to_me_url
+{
+	my( $self ) = @_;
+
+	return $self->SUPER::redirect_to_me_url.$self->workflow->get_state_params;
+}
+
+sub render_buttons
+{
+	my( $self ) = @_;
+
+	my %buttons = ( _order=>[], _class=>"ep_form_button_bar" );
+
+	if( defined $self->workflow->get_prev_stage_id )
+	{
+		push @{$buttons{_order}}, "prev";
+		$buttons{prev} = $self->phrase( "prev" );
+	}
+
+	push @{$buttons{_order}}, "stop", "merge";
+	$buttons{stop} = $self->phrase( "stop" );
+	$buttons{merge} = $self->phrase( "merge" );
+
+	if( defined $self->workflow->get_next_stage_id )
+	{
+		push @{$buttons{_order}}, "next";
+		$buttons{next} = $self->phrase( "next" );
+	}	
+	return $self->{session}->render_action_buttons( %buttons );
+}
+
+1;
+
+
Index: perl_lib/EPrints/Plugin/Screen/Staff/AuthorSearch.pm
===================================================================
--- perl_lib/EPrints/Plugin/Screen/Staff/AuthorSearch.pm	(revision 0)
+++ perl_lib/EPrints/Plugin/Screen/Staff/AuthorSearch.pm	(revision 224)
@@ -0,0 +1,83 @@
+
+package EPrints::Plugin::Screen::Staff::AuthorSearch;
+
+@ISA = ( 'EPrints::Plugin::Screen::AbstractSearch' );
+
+use strict;
+
+sub new
+{
+	my( $class, %params ) = @_;
+
+	my $self = $class->SUPER::new(%params);
+	
+	$self->{appears} = [
+		{
+			place => "admin_actions",
+			position => 600,
+		},
+	];
+
+	return $self;
+}
+
+sub search_dataset
+{
+	my( $self ) = @_;
+
+	return $self->{session}->get_repository->get_dataset( "author" );
+}
+
+sub search_filters
+{
+	my( $self ) = @_;
+
+	return;
+}
+
+sub allow_export { return 1; }
+
+sub allow_export_redir { return 1; }
+
+sub can_be_viewed
+{
+	my( $self ) = @_;
+
+	return $self->allow( "staff/author_search" );
+}
+
+sub from
+{
+	my( $self ) = @_;
+
+	my $sconf = $self->{session}->get_repository->get_conf( "search", "author" );
+	$self->{processor}->{sconf} = $sconf;
+
+	$self->SUPER::from;
+}
+
+sub _vis_level
+{
+	my( $self ) = @_;
+
+	return "staff";
+}
+
+sub get_controls_before
+{
+	my( $self ) = @_;
+
+	return $self->get_basic_controls_before;	
+}
+
+sub render_result_row
+{
+	my( $self, $session, $result, $searchexp, $n ) = @_;
+
+	return $result->render_citation_link_staff(
+			$self->{processor}->{sconf}->{citation},  #undef unless specified
+			n => [$n,"INTEGER"] );
+}
+
+
+
Index: perl_lib/EPrints/Plugin/InputForm/Component/Field/Itemref.pm
===================================================================
--- perl_lib/EPrints/Plugin/InputForm/Component/Field/Itemref.pm	(revision 0)
+++ perl_lib/EPrints/Plugin/InputForm/Component/Field/Itemref.pm	(revision 224)
@@ -0,0 +1,152 @@
+package EPrints::Plugin::InputForm::Component::Field::Itemref;
+
+use EPrints;
+use EPrints::Plugin::InputForm::Component::Field;
+@ISA = ( "EPrints::Plugin::InputForm::Component::Field" );
+
+use Unicode::String qw(latin1);
+
+use strict;
+
+sub new
+{
+
+	my( $class, %opts ) = @_;
+
+	my $self = $class->SUPER::new( %opts );
+	
+	$self->{name} = "Itemref";
+	$self->{visible} = "all";
+	$self->{visdepth} = 1;
+	return $self;
+}
+
+
+sub render_content
+{
+	my( $self, $surround ) = @_;
+	
+	my $value;
+	if( $self->{dataobj} )
+	{
+		$value = $self->{dataobj}->get_value( $self->{config}->{field}->{name} );
+	}
+	else
+	{
+		$value = $self->{default};
+	}
+
+	my $session = $self->{session};
+	my $field = $self->{config}->{field};
+	my $item = $self->{workflow}->{item};
+
+	my $input = $self->{session}->make_element( "div" );
+
+	my $maxlength = $field->get_max_input_size;
+	my $size = ( $maxlength > $field->{input_cols} ?
+					$field->{input_cols} : 
+					$maxlength );
+
+
+	my $dataset = $self->{dataobj}->get_dataset;
+	my $obj = $self->{dataobj};
+	my $hidden_fields = undef;
+	my $basename = $self->{prefix}; 
+	my $staff = 0;
+
+	if( defined $basename )
+	{
+		$basename = $basename."_".$field->{name};
+	}
+	else
+	{
+		$basename = $field->{name};
+	}
+
+	if( defined $self->{config}->{field}->{toform} )
+	{
+		$value = $self->{config}->{field}->call_property( "toform", $value, $session );
+	}
+
+	my $elements = $field->get_input_elements( 
+		    $session,
+		    $self->{dataobj}->get_value( $self->{config}->{field}->{name} ), # value 
+		    0, # Staff can be zero here, the parent works that way...
+		    $self->{dataobj}, # obj
+		    $self->{prefix}.'_'.$field->{name}, # name?
+	);
+	
+	
+	if ( defined $field->{external_lookup_url} && length( $field->{external_lookup_url} ) ) 
+	{
+	    my %options;
+	    my $url = $field->{external_lookup_url} ."?validate=true&basename=". $field->{name} ."&fieldname=$basename&". $field->{external_lookup_params};
+	    $options{onclick} = "popup_appendfield('$basename', '$url', 400, 400);";
+	    $options{class} = "ep_form_internal_button";
+	    $options{type} = "button";
+	    my $lookup = $session->make_element("button", %options);
+	    $lookup->appendChild($session->html_phrase("lib/metafield/itemref:find_entry"));
+	    push @{ $elements->[0] }, {el=>$lookup};
+	}
+
+
+	my $table = $session->make_element( "table", border=>0, cellpadding=>0, cellspacing=>0, class=>"ep_form_input_grid" );
+
+	my $col_titles = $field->get_input_col_titles( $session, $staff );
+	if( defined $col_titles )
+	{
+		my $tr = $session->make_element( "tr" );
+		my $th;
+		my $x = 0;
+		if( $field->get_property( "multiple" ) && $field->{input_ordered})
+		{
+			$th = $session->make_element( "th", class=>"empty_heading", id=>$basename."_th_".$x++ );
+			$tr->appendChild( $th );
+		}
+
+		if( !defined $col_titles )
+		{
+			$th = $session->make_element( "th", class=>"empty_heading", id=>$basename."_th_".$x++ );
+			$tr->appendChild( $th );
+		}	
+		else
+		{
+			foreach my $col_title ( @{$col_titles} )
+			{
+				$th = $session->make_element( "th", id=>$basename."_th_".$x++ );
+				$th->appendChild( $col_title );
+				$tr->appendChild( $th );
+			}
+		}
+		$table->appendChild( $tr );
+	}
+
+	my $y = 0;
+	foreach my $row ( @{$elements} )
+	{
+		my $x = 0;
+		my $tr = $session->make_element( "tr" );
+		foreach my $item ( @{$row} )
+		{
+			my %opts = ( valign=>"top", id=>$basename."_cell_".$x++."_".$y );
+			foreach my $prop ( keys %{$item} )
+			{
+				next if( $prop eq "el" );
+				$opts{$prop} = $item->{$prop};
+			}	
+			my $td = $session->make_element( "td", %opts );
+			if( defined $item->{el} )
+			{
+				$td->appendChild( $item->{el} );
+			}
+			$tr->appendChild( $td );
+		}
+		$table->appendChild( $tr );
+		$y++;
+	}
+
+	$input->appendChild($table);	
+
+	return $input;
+}
+

Property changes on: perl_lib/EPrints/Plugin/InputForm/Component/Field/Itemref.pm
___________________________________________________________________
Added: svn:mergeinfo

Index: perl_lib/EPrints/Plugin/InputForm/Component/Field/Creator.pm
===================================================================
--- perl_lib/EPrints/Plugin/InputForm/Component/Field/Creator.pm	(revision 0)
+++ perl_lib/EPrints/Plugin/InputForm/Component/Field/Creator.pm	(revision 224)
@@ -0,0 +1,161 @@
+package EPrints::Plugin::InputForm::Component::Field::Creator;
+
+use EPrints;
+use EPrints::Plugin::InputForm::Component::Field;
+@ISA = ( "EPrints::Plugin::InputForm::Component::Field" );
+
+use Unicode::String qw(latin1);
+
+use strict;
+
+sub new
+{
+
+	my( $class, %opts ) = @_;
+
+	my $self = $class->SUPER::new( %opts );
+	
+	$self->{name} = "Itemref";
+	$self->{visible} = "all";
+	$self->{visdepth} = 1;
+	return $self;
+}
+
+
+sub render_content
+{
+	my( $self, $surround ) = @_;
+	
+	my $value;
+	if( $self->{dataobj} )
+	{
+		$value = $self->{dataobj}->get_value( $self->{config}->{field}->{name} );
+	}
+	else
+	{
+		$value = $self->{default};
+	}
+
+	my $session = $self->{session};
+	my $field = $self->{config}->{field};
+	my $item = $self->{workflow}->{item};
+
+	my $input = $self->{session}->make_element( "div" );
+
+	my $maxlength = $field->get_max_input_size;
+	my $size = ( $maxlength > $field->{input_cols} ?
+					$field->{input_cols} : 
+					$maxlength );
+
+
+	my $dataset = $self->{dataobj}->get_dataset;
+	my $obj = $self->{dataobj};
+	my $hidden_fields = undef;
+	my $basename = $self->{prefix};
+	my $staff = 0;
+
+	if( defined $basename )
+	{
+		$basename = $basename."_".$field->{name};
+	}
+	else
+	{
+		$basename = $field->{name};
+	}
+
+	if( defined $self->{config}->{field}->{toform} )
+	{
+		$value = $self->{config}->{field}->call_property( "toform", $value, $session );
+	}
+
+	my $elements = $field->get_input_elements( 
+		    $session,
+		    $self->{dataobj}->get_value( $self->{config}->{field}->{name} ), # value 
+		    0, # Staff can be zero here, the parent works that way...
+		    $self->{dataobj}, # obj
+		    $self->{prefix}.'_'.$field->{name}, # name?
+	);
+
+
+	my $table = $session->make_element( "table", border=>0, cellpadding=>0, cellspacing=>0, class=>"ep_form_input_grid" );
+
+	my $col_titles = $field->get_input_col_titles( $session, $staff );
+	if( defined $col_titles )
+	{
+		my $tr = $session->make_element( "tr" );
+		my $th;
+		my $x = 0;
+		if( $field->get_property( "multiple" ) && $field->{input_ordered})
+		{
+			$th = $session->make_element( "th", class=>"empty_heading", id=>$basename."_th_".$x++ );
+			$tr->appendChild( $th );
+		}
+
+		if( !defined $col_titles )
+		{
+			$th = $session->make_element( "th", class=>"empty_heading", id=>$basename."_th_".$x++ );
+			$tr->appendChild( $th );
+		}	
+		else
+		{
+			foreach my $col_title ( @{$col_titles} )
+			{
+				$th = $session->make_element( "th", id=>$basename."_th_".$x++ );
+				$th->appendChild( $col_title );
+				$tr->appendChild( $th );
+			}
+		}
+		$table->appendChild( $tr );
+	}
+
+	my $y = 0;
+	foreach my $row ( @{$elements} )
+	{
+		my $x = 0;
+		my $oc = 0;
+		my $tr = $session->make_element( "tr" );
+		foreach my $item ( @{$row} )
+		{
+			my %opts = ( valign=>"top", id=>$basename."_cell_".$x++."_".$y );
+			foreach my $prop ( keys %{$item} )
+			{
+				next if( $prop eq "el" );
+				$opts{$prop} = $item->{$prop};
+			}	
+			my $td = $session->make_element( "td", %opts );
+			if( defined $item->{el} )
+			{
+				$td->appendChild( $item->{el} );
+			}
+			$oc++;
+			$tr->appendChild( $td );
+		}
+
+		# If the external_lookup_url is defined, not blank and the row we're on has more than two columns
+		if ( defined $field->{external_lookup_url} 
+		  && length( $field->{external_lookup_url} ) 
+		  && $oc > 2) 
+		{
+		    my %options;
+		    my $url = $field->{external_lookup_url} ."?basename=".$field->{name}."&fieldname=".$basename."_". ($y + 1) ."_id&". $field->{external_lookup_params};
+		    $options{onclick} = "popup_appendfield('".$basename."_". ($y + 1) ."_id', '$url', 400, 400);";
+		    $options{class} = "ep_form_internal_button";
+		    $options{type} = "button";
+		    my $lookup = $session->make_element("button", %options);
+		    $lookup->appendChild($session->html_phrase("lib/metafield/itemref:find_entry"));
+
+		    my $button_td = $session->make_element( "td" );
+		    $button_td->appendChild($lookup);
+		    $tr->appendChild( $button_td );
+
+		}
+
+		$table->appendChild( $tr );
+		$y++;
+	}
+
+	$input->appendChild($table);	
+
+	return $input;
+}
+

Property changes on: perl_lib/EPrints/Plugin/InputForm/Component/Field/Creator.pm
___________________________________________________________________
Added: svn:mergeinfo

Index: perl_lib/EPrints.pm
===================================================================
--- perl_lib/EPrints.pm	(revision 217)
+++ perl_lib/EPrints.pm	(revision 224)
@@ -132,6 +132,8 @@
 use EPrints::DataObj::Subject;
 use EPrints::DataObj::SavedSearch;
 use EPrints::DataObj::User;
+use EPrints::DataObj::Author;
+use EPrints::DataObj::Author_Instance;
 use EPrints::DataSet;
 use EPrints::Email;
 use EPrints::Extras;
Index: cgi/users/popup/author
===================================================================
--- cgi/users/popup/author	(revision 0)
+++ cgi/users/popup/author	(revision 224)
@@ -0,0 +1,114 @@
+use EPrints;
+
+use strict;
+
+my $session = EPrints::Session->new();
+
+# security?
+# my thoughts exactly...
+
+my $content = "text/html";
+my $family = $session->param( "_author_family" );
+my $given = $session->param( "_author_given" );
+my $id = $session->param( "authorid" );
+my $fieldname = $session->param( "fieldname" );
+my $basename = $session->param( "basename" );
+my $validate = $session->param( "validate" );
+
+my $database = $session->get_database;
+my $dataset = $session->get_repository->get_dataset( "author" );
+my $author_field = $dataset->get_field( "author" );
+my $email_field = $dataset->get_field( "primary_email" );
+my $id_field = $dataset->get_field( "authorid" );
+
+my @fields = ($author_field->get_sql_names, $id_field->get_sql_names, );
+
+my $Q_table = $database->quote_identifier($dataset->get_sql_table_name);
+my $Q_authorid = $database->quote_identifier( "authorid" );
+my $Q_num_matches = $database->quote_identifier( "num_matches" );
+
+my $sql = "SELECT " .
+	join(",", map { $database->quote_identifier($_) } @fields) .
+	" FROM $Q_table" .
+	" WHERE " .
+	" $Q_table.$Q_authorid LIKE ". $database->quote_value(EPrints::Database::prep_like_value($id).'%') .
+	" OR ".$database->quote_identifier("author_family")." LIKE ".$database->quote_value(EPrints::Database::prep_like_value($id).'%') .
+	" OR ".$database->quote_identifier("author_given")." LIKE ".$database->quote_value(EPrints::Database::prep_like_value($id).'%') .
+	" OR ".$database->quote_identifier("primary_email")." LIKE ".$database->quote_value(EPrints::Database::prep_like_value($id).'%');
+$sql .= " GROUP BY ".join(",",map { $database->quote_identifier($_) } @fields) .
+	" ORDER BY " .
+	$database->quote_identifier("author_family").",".
+	$database->quote_identifier("author_given") .
+	" LIMIT 40";
+
+my @rows;
+
+my $sth = $session->get_database->prepare( $sql );
+$session->get_database->execute( $sth , $sql );
+while( my( $h,$g,$f,$l,$id ) = $sth->fetchrow_array )
+{
+	my $row = {};
+	push @rows, $row;
+
+	my $frag = $session->make_doc_fragment;
+
+	my $desc = "$h $g $f $l"; 
+	$desc .= " ($id)" if defined $id;
+	$desc .= " ";
+	my $onclick = "window.opener.document.getElementById('$fieldname').value = $id;";
+	# if we need to validate, try to do that then; for some reason just submitting the form doesn't work?!?
+        if( length($validate) > 0 && $validate eq 'true' ) {
+		$onclick .= "window.opener.document.getElementsByName('_internal_". $basename ."_null')[0].click();";
+	}
+        $onclick .= "window.close();";
+	$a = $session->make_element('a', onclick=>$onclick, href=>"#");
+	$a->appendChild( $session->make_text( $desc ) );
+	my $small = $session->make_element( "small" );
+	$a->appendChild( $small );
+	$frag->appendChild( $a );
+	
+
+	$row->{xhtml} = $frag;
+	$row->{values} = [];
+}
+
+my $ul = EPrints::Extras::render_lookup_list( $session, \@rows );
+
+$session->send_http_header( content_type => "text/html; charset=UTF-8" );
+
+
+my $url = $session->get_url(
+		scheme => "http",
+		host => 1,
+		path => "cgi",
+	);
+
+# <?xml version="1.0" encoding="UTF-8" ?>
+print <<END;
+<html>
+<!-- $sql -->
+  <head>
+    <title>Author picker</title>
+  </head>
+
+  <body>
+    <form method="get" action="$url/users/popup/author">
+    <input type="hidden" name="fieldname" value="$fieldname" />
+    <input type="hidden" name="validate" value="$validate" />
+    <input type="hidden" name="basename" value="$basename" />
+    <input type="text" name="authorid" value="$id" /><input type="submit" value="Find" />
+    </form>
+END
+
+print EPrints::XML::to_string( $ul, "utf-8", 1 );
+
+print <<END;
+    
+  </body>
+</html>
+END
+
+EPrints::XML::dispose( $ul );
+
+$session->terminate;
+

Property changes on: cgi/users/popup/author
___________________________________________________________________
Added: svn:executable
   + *

Index: cgi/users/popup/usq_dept
===================================================================
--- cgi/users/popup/usq_dept	(revision 0)
+++ cgi/users/popup/usq_dept	(revision 224)
@@ -0,0 +1,96 @@
+use EPrints;
+
+use strict;
+
+my $session = EPrints::Session->new();
+
+# security?
+# my thoughts exactly...
+
+#my $content = "text/xml";
+my $content = "text/html";
+my $id = $session->param( "deptid" );
+my $fieldname = $session->param( "fieldname" );
+my $basename = $session->param( "basename" );
+my $validate = $session->param( "validate" );
+
+my $database = $session->get_database;
+
+my @fields = qw/ deptid dept_name /; 
+my $sql = "SELECT " .
+	join(",", map { $database->quote_identifier($_) } @fields) .
+	" FROM usq_dept_tree" .
+	" WHERE " .
+	"     dept_name LIKE ". $database->quote_value(EPrints::Database::prep_like_value($id).'%') .
+	" OR deptid = ".$database->quote_value(EPrints::Database::prep_int($id)) .
+	" LIMIT 40";
+
+my @rows;
+
+my $sth = $session->get_database->prepare( $sql );
+$session->get_database->execute( $sth , $sql );
+while( my( $id, $dept_name ) = $sth->fetchrow_array )
+{
+	my $row = {};
+	push @rows, $row;
+
+	my $frag = $session->make_doc_fragment;
+	my $onclick = "window.opener.document.getElementById('$fieldname').value = $id;";
+	# if we need to validate, try to do that then; for some reason just submitting the form doesn't work?!?
+        if( length($validate) > 0 && $validate eq 'true' ) {
+		$onclick .= "window.opener.document.getElementsByName('_internal_". $basename ."_null')[0].click();";
+	}
+        $onclick .= "window.close();";
+	$a = $session->make_element('a', onclick=>$onclick, href=>"#");
+	$a->appendChild( $session->make_text( $dept_name ) );
+	my $small = $session->make_element( "small" );
+	$small->appendChild( $session->make_text( "(". $id .")" ) );
+	$a->appendChild( $small );
+	$frag->appendChild( $a );
+	
+
+	$row->{xhtml} = $frag;
+	$row->{values} = [];
+}
+
+my $ul = EPrints::Extras::render_lookup_list( $session, \@rows );
+
+#$session->send_http_header( content_type => "text/xml; charset=UTF-8" );
+$session->send_http_header( content_type => "text/html; charset=UTF-8" );
+
+
+my $url = $session->get_url(
+		scheme => "http",
+		host => 1,
+		path => "cgi",
+	);
+
+# <?xml version="1.0" encoding="UTF-8" ?>
+print <<END;
+<html>
+<!-- $sql -->
+  <head>
+    <title>Author picker</title>
+  </head>
+
+  <body>
+    <form method="get" action="$url/users/popup/usq_dept">
+    <input type="hidden" name="fieldname" value="$fieldname" />
+    <input type="hidden" name="validate" value="$validate" />
+    <input type="hidden" name="basename" value="$basename" />
+    <input type="text" name="deptid" value="$id" /><input type="submit" value="Find" />
+    </form>
+END
+
+print EPrints::XML::to_string( $ul, "utf-8", 1 );
+
+print <<END;
+    
+  </body>
+</html>
+END
+
+EPrints::XML::dispose( $ul );
+
+$session->terminate;
+

Property changes on: cgi/users/popup/usq_dept
___________________________________________________________________
Added: svn:executable
   + *

Index: cgi/users/popup/author_instance
===================================================================
--- cgi/users/popup/author_instance	(revision 0)
+++ cgi/users/popup/author_instance	(revision 224)
@@ -0,0 +1,163 @@
+use EPrints;
+
+use strict;
+
+my $session = EPrints::Session->new();
+
+# security?
+# my thoughts exactly...
+
+my $content = "text/html";
+my $family = $session->param( "_author_family" );
+my $given = $session->param( "_author_given" );
+my $id = $session->param( "authorid" );
+my $fieldname = $session->param( "fieldname" );
+my $basename = $session->param( "basename" );
+my $validate = $session->param( "validate" );
+
+my $database = $session->get_database;
+my $dataset = $session->get_repository->get_dataset( "author" );
+my $author_field = $dataset->get_field( "author" );
+my $email_field = $dataset->get_field( "primary_email" );
+my $id_field = $dataset->get_field( "authorid" );
+
+my @fields = ($author_field->get_sql_names, $id_field->get_sql_names, );
+
+my $Q_table = $database->quote_identifier($dataset->get_sql_table_name);
+my $Q_authorid = $database->quote_identifier( "authorid" );
+my $Q_num_matches = $database->quote_identifier( "num_matches" );
+
+my $inner_dataset = $session->get_repository->get_dataset( "author_instance" );
+my $author_id = $inner_dataset->get_field( "authorid" );
+my $instance_id = $inner_dataset->get_field( "instanceid" );
+my $preferred = $inner_dataset->get_field( "preferred" );
+my $display_name = $inner_dataset->get_field( "display_name" );
+my @inner_fields = ( $author_id->get_sql_names, 
+		  $instance_id->get_sql_names,
+		  $preferred->get_sql_names,
+		  $display_name->get_sql_names );
+
+
+my $AI_table = $database->quote_identifier($inner_dataset->get_sql_table_name);
+my $AI_authorid = $database->quote_identifier( "authorid" );
+my $AI_instanceid = $database->quote_identifier( "instanceid" );
+
+
+my $authorid_subquery = "SELECT $AI_table.$AI_authorid FROM $AI_table " .
+	" WHERE $AI_table.$AI_instanceid = " . EPrints::Database::prep_int($id);
+
+my $sql = "SELECT " .
+	join(",", map { $database->quote_identifier($_) } @fields) .
+	" FROM $Q_table" .
+	" WHERE " .
+	" $Q_table.$Q_authorid LIKE ". $database->quote_value(EPrints::Database::prep_like_value($id).'%') .
+	" OR ".$database->quote_identifier("author_family")." LIKE ".$database->quote_value(EPrints::Database::prep_like_value($id).'%') .
+	" OR ".$database->quote_identifier("author_given")." LIKE ".$database->quote_value(EPrints::Database::prep_like_value($id).'%') .
+	" OR ".$database->quote_identifier("primary_email")." LIKE ".$database->quote_value(EPrints::Database::prep_like_value($id).'%') .
+	" OR ".$database->quote_identifier("authorid")." IN (". $authorid_subquery .")";
+$sql .= " GROUP BY ".join(",",map { $database->quote_identifier($_) } @fields) .
+	" ORDER BY " .
+	$database->quote_identifier("author_family").",".
+	$database->quote_identifier("author_given") .
+	" LIMIT 40";
+
+my @rows;
+
+my $sth = $database->prepare( $sql );
+$database->execute( $sth , $sql );
+while( my( $h,$g,$f,$l,$id ) = $sth->fetchrow_array )
+{
+	my $row = {};
+	push @rows, $row;
+
+	my $frag = $session->make_doc_fragment;
+
+	my $desc = "$h $g $f $l"; 
+	$desc .= " ($id)" if defined $id;
+	$desc .= " ";
+	$frag->appendChild( $session->make_text( $desc ) );
+	my $br = $session->make_element( "br" );
+	$frag->appendChild( $br );
+
+  
+	# Handle situation of individual instances
+	# We could probably do this in one select and handle the processing in a larger
+	# loop, we could handle this in a two query pattern with a single query to find
+	# all of the authors that we care about and then create a query with the set of
+	# all of these authors included to pull everything back or you can do it the
+	# absolute low level minimum simplest way that I'm using right here that will
+	# create a query for n many authors that are there. Should probably do something
+	# really nifty in perl here that will take the second method, or perhaps the first
+	# method in a really weird way - but my perl-fu isn't that grand
+	my $inner_sql = "SELECT ".
+	    join(",", map { $database->quote_identifier($_) } @inner_fields) .
+	    " FROM $AI_table" .
+	    " WHERE " .
+	    " $AI_table.$AI_authorid = ". $database->quote_value( EPrints::Database::prep_int($id) );
+
+	my $inner_sth = $session->get_database->prepare( $inner_sql );
+	$session->get_database->execute( $inner_sth, $inner_sql );
+
+	my $inner_ul = $session->make_element( "ul" );
+	while( my( $inner_aid, $inner_iid, $inner_p, $inner_d ) = $inner_sth->fetchrow_array )
+	{
+	    my $inner_li = $session->make_element( "li" );
+
+	    my $onclick = "window.opener.document.getElementById('$fieldname').value = $inner_iid;";
+	    # if we need to validate, try to do that then; for some reason just submitting the form doesn't work?!?
+	    if( length($validate) > 0 && $validate eq 'true' ) {
+		    $onclick .= "window.opener.document.getElementsByName('_internal_". $basename ."_null')[0].click();";
+	    }
+	    $onclick .= "window.close();";
+	    my $inner_a = $session->make_element('a', onclick=>$onclick, href=>"#");
+	    $inner_a->appendChild( $session->make_text( length($inner_d) ? $inner_d : "UNSPECIFIED" . " (". $inner_iid . ")") );
+	    $inner_li->appendChild( $inner_a );
+	    $inner_p eq "TRUE" ? $inner_li->appendChild( $session->make_text( "*" ) ) : 1;
+	    $inner_ul->appendChild( $inner_li );
+	}
+	$frag->appendChild($inner_ul);
+
+	$row->{xhtml} = $frag;
+	$row->{values} = [];
+}
+
+my $ul = EPrints::Extras::render_lookup_list( $session, \@rows );
+
+$session->send_http_header( content_type => "text/html; charset=UTF-8" );
+
+
+my $url = $session->get_url(
+		scheme => "http",
+		host => 1,
+		path => "cgi",
+	);
+
+# <?xml version="1.0" encoding="UTF-8" ?>
+print <<END;
+<html>
+<!-- $sql -->
+  <head>
+    <title>Author picker</title>
+  </head>
+
+  <body>
+    <form method="get" action="$url/users/popup/author_instance">
+    <input type="hidden" name="fieldname" value="$fieldname" />
+    <input type="hidden" name="validate" value="$validate" />
+    <input type="hidden" name="basename" value="$basename" />
+    <input type="text" name="authorid" value="$id" /><input type="submit" value="Find" />
+    </form>
+END
+
+print EPrints::XML::to_string( $ul, "utf-8", 1 );
+
+print <<END;
+    
+  </body>
+</html>
+END
+
+EPrints::XML::dispose( $ul );
+
+$session->terminate;
+
Index: cgi/users/popup/user
===================================================================
--- cgi/users/popup/user	(revision 0)
+++ cgi/users/popup/user	(revision 224)
@@ -0,0 +1,116 @@
+use EPrints;
+
+use strict;
+
+my $session = EPrints::Session->new();
+
+# security?
+# my thoughts exactly...
+
+my $content = "text/html";
+my $family = $session->param( "_name_family" );
+my $given = $session->param( "_name_given" );
+my $id = $session->param( "userid" );
+my $fieldname = $session->param( "fieldname" );
+my $basename = $session->param( "basename" );
+my $validate = $session->param( "validate" );
+
+my $database = $session->get_database;
+my $dataset = $session->get_repository->get_dataset( "user" );
+my $name_field = $dataset->get_field( "name" );
+my $id_field = $dataset->get_field( "userid" );
+my $username_field = $dataset->get_field( "username" );
+
+my @fields = ($username_field->get_sql_names, $name_field->get_sql_names, $id_field->get_sql_names, );
+
+my $Q_table = $database->quote_identifier($dataset->get_sql_table_name);
+my $Q_userid = $database->quote_identifier( "userid" );
+my $Q_num_matches = $database->quote_identifier( "num_matches" );
+
+my $sql = "SELECT " .
+	join(",", map { $database->quote_identifier($_) } @fields) .
+	" FROM $Q_table" .
+	" WHERE " .
+	" $Q_table.$Q_userid LIKE ". $database->quote_value(EPrints::Database::prep_like_value($id).'%') .
+	" OR ".$database->quote_identifier("name_family")." LIKE ".$database->quote_value(EPrints::Database::prep_like_value($id).'%') .
+	" OR ".$database->quote_identifier("name_given")." LIKE ".$database->quote_value(EPrints::Database::prep_like_value($id).'%') .
+	" OR ".$database->quote_identifier("username")." LIKE ".$database->quote_value(EPrints::Database::prep_like_value($id).'%');
+$sql .= " GROUP BY ".join(",",map { $database->quote_identifier($_) } @fields) .
+	" ORDER BY " .
+	$database->quote_identifier("name_family").",".
+	$database->quote_identifier("name_given") .
+	" LIMIT 40";
+
+my @rows;
+
+my $sth = $session->get_database->prepare( $sql );
+$session->get_database->execute( $sth , $sql );
+while( my( $username, $h,$g,$f,$l,$id ) = $sth->fetchrow_array )
+{
+	my $row = {};
+	push @rows, $row;
+
+	my $frag = $session->make_doc_fragment;
+
+	my $desc = "$h $g $f $l"; 
+	$desc .= " ($id)" if defined $id;
+	$desc .= " ";
+        my $onclick = "window.opener.document.getElementById('$fieldname').value = $id;";
+        # if we need to validate, try to do that then; for some reason just submitting the form doesn't work?!?
+        if( length($validate) > 0 && $validate eq 'true' ) {
+                $onclick .= "window.opener.document.getElementsByName('_internal_". $basename ."_null')[0].click();";
+                #$onclick .= "alert(window.opener.EPJS_button_pushed( '_internal_". $basename ."_null' )); if(window.opener.EPJS_button_pushed( '_internal_". $basename ."_null' )) { window.opener.document.getElementById('$fieldname').form.submit(); }";
+        }
+        $onclick .= "window.close();";
+        $a = $session->make_element('a', onclick=>$onclick, href=>"#");
+	$a->appendChild( $session->make_text( $desc ) );
+	my $small = $session->make_element( "small" );
+	$a->appendChild( $small );
+	$frag->appendChild( $a );
+	
+	$small->appendChild( $session->make_text( "($username)" ) );
+
+	$row->{xhtml} = $frag;
+	$row->{values} = [];
+}
+
+my $ul = EPrints::Extras::render_lookup_list( $session, \@rows );
+
+$session->send_http_header( content_type => "text/html; charset=UTF-8" );
+
+
+my $url = $session->get_url(
+		scheme => "http",
+		host => 1,
+		path => "cgi",
+	);
+
+# <?xml version="1.0" encoding="UTF-8" ?>
+print <<END;
+<html>
+<!-- $sql -->
+  <head>
+    <title>User picker</title>
+  </head>
+
+  <body>
+    <form method="get" action="$url/users/popup/user">
+    <input type="hidden" name="fieldname" value="$fieldname" />
+    <input type="hidden" name="validate" value="$validate" />
+    <input type="hidden" name="basename" value="$basename" />
+    <input type="text" name="userid" value="$id" /><input type="submit" value="Find" />
+    </form>
+END
+
+print EPrints::XML::to_string( $ul, "utf-8", 1 );
+
+print <<END;
+    
+  </body>
+</html>
+END
+
+EPrints::XML::dispose( $ul );
+
+$session->terminate;
+

Property changes on: cgi/users/popup/user
___________________________________________________________________
Added: svn:executable
   + *

Index: lib/lang/en/phrases/system.xml
===================================================================
--- lib/lang/en/phrases/system.xml	(revision 217)
+++ lib/lang/en/phrases/system.xml	(revision 224)
@@ -1961,4 +1961,100 @@
 
 <epp:phrase id="user_fieldname_permission_group">Permission Group</epp:phrase>
 
+
+<!--**********************************************************************
+Author ID Support
+***********************************************************************-->
+<epp:phrase id="datasetname_author">Author</epp:phrase>
+<epp:phrase id="datasethelp_author">Used to store individual authors that might be linked to users but not necessarily</epp:phrase>
+<epp:phrase id="datasetname_author_instance">Author Instance</epp:phrase>
+<epp:phrase id="datasethelp_author_instance">Used to link instances of author details to ePrints.</epp:phrase>
+
+
+<epp:phrase id="Plugin/Screen/NewAuthor:title">New author</epp:phrase>
+<epp:phrase id="Plugin/Screen/NewAuthor:blurb">Add a new author to the system by specifying their name details.</epp:phrase>
+<epp:phrase id="Plugin/Screen/NewAuthor:action:create:title">Create new author</epp:phrase>
+<epp:phrase id="Plugin/Screen/NewAuthor:action:cancel:title">Cancel</epp:phrase>
+<epp:phrase id="Plugin/Screen/NewAuthor:description">Create a new author within ePrints to assign distinct citations to a single identity.</epp:phrase>
+
+<epp:phrase id="Plugin/Screen/Staff/AuthorSearch:title">Search authors</epp:phrase>
+<epp:phrase id="Plugin/Screen/Staff/AuthorSearch:description">Search for authors recorded in this repository.</epp:phrase>
+
+<epp:phrase id="Plugin/Screen/Author/Staff/Edit:title">Edit Author</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author/Staff/Edit:stop">Cancel edit</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author/Staff/Edit:save">Save author</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author/Staff/Edit:description">Edit an authors detail</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author/Staff/Edit:no_such_author">No such author</epp:phrase>
+
+<epp:phrase id="Plugin/Screen/Author/View:title">View Author</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author/Remove:title">Remove author</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author/Remove:description">Remove this author from the system</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author/Remove:author_removed">Author removed from system</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author/Remove:author_removed">Author removed from system.</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author/Remove:sure_delete">Are you sure you want to delete this author? This operation cannot be undone!</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author/View:no_such_author">There is no matching author.</epp:phrase>
+
+<epp:phrase id="Plugin/Screen/NewAuthor_Instance:title">Create author instance</epp:phrase>
+<epp:phrase id="Plugin/Screen/NewAuthor_Instance:description">Create a new instance identifier for an author</epp:phrase>
+<epp:phrase id="Plugin/Screen/NewAuthor_Instance:blurb">Enter the author ID of the author you wish to create a new instance.</epp:phrase>
+<epp:phrase id="Plugin/Screen/NewAuthor_Instance:action:create:title">Create instance</epp:phrase>
+<epp:phrase id="Plugin/Screen/NewAuthor_Instance:action:cancel:title">Cancel</epp:phrase>
+<epp:phrase id="Plugin/Screen/NewAuthor_Instance:no_id">No author ID specified. An author ID is required to link the instance to an author.</epp:phrase>
+
+<epp:phrase id="Plugin/Screen/Author_Instance/Edit:no_such_author_instance">No such author instance exists.</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author_Instance/Edit:description">Edit this author instance.</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author_Instance/Edit:save">Save Author Instance</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author_Instance/Edit:stop">Cancel</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author_Instance/Edit:title">Edit Author Instance</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author_Instance/View:no_such_author_instance">No such author instance found.</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author_Instance/View:title">View author instance</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author_Instance/Items:add">Add Column</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author_Instance/Items:title">List Author Instances</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author_Instance/Items:description">View specific instances of this author</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author_Instance/Items:remove_column_confirm">Are you sure you want to remove this column?</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author_Instance/Items:help_title">Author Instances</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author_Instance/Items:help">Instances identifying points of an author. Some authors may only ever have a single instance however authors may have multiple instances if they shift roles as they submit to the repository (e.g. members of different departments or different universities).</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author_Instance/Remove:description">Remove an instance of an author from the system.</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author_Instance/Remove:title">Remote author instance</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author_Instance/Staff/Edit:description">Provide details about this particular author instace</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author_Instance/Staff/Edit:save">Save</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author_Instance/Staff/Edit:stop">Cancel</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author_Instance/Staff/Edit:title">Edit Author Instance</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author_Instance/Merge:title">Merge author instances</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author_Instance/Merge:description">Merge another author instance into this one</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author_Instance/Merge:stop">Cancel merge</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author_Instance/Merge:merge">Merge instances</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author_Instance/Merge:author_instance_merge_desc">Please select the other author that you wish to merge into this author entry. Note that this row will remain and the other entry will have instances repointed to this one. The next screen will allow you to control the final values.</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author_Instance/Merge:primary_author_instance">Primary instance: </epp:phrase>
+<epp:phrase id="Plugin/Screen/Author_Instance/Merge:duplicate_author_instance">Duplicate instance ID: </epp:phrase>
+<epp:phrase id="Plugin/Screen/Author_Instance/Merge:Find">Find instance</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author_Instance/MergeDetails:title">Merge author instances</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author_Instance/MergeDetails:stop">Cancel merge</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author_Instance/MergeDetails:merge">Merge instances</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author_Instance/MergeDetails:author_instance_merge_desc">This screen permits you to merge the two author instance records. The base record is the default value and will be retained. The values of the base records and the duplicate are displayed for reference. In most instances the Author ID should not be changed, you should merge the authors first or alter the individual author instance record.</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author_Instance/MergeDetails:primary_author_instance">Primary instance: </epp:phrase>
+<epp:phrase id="Plugin/Screen/Author_Instance/MergeDetails:duplicate_author_instance">Duplicate instance: </epp:phrase>
+<epp:phrase id="Plugin/Screen/Author_Instance/MergeDetails:automerge_field">Automatically merged</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author_Instance/MergeDetails:automerge">Multiple type fields will be automerged though there may be duplicates. These fields may contain duplicates</epp:phrase>
+<epp:phrase id="Plugin/Screen/NewAuthor_Instance:no_name">No name</epp:phrase>
+
+<epp:phrase id="Plugin/Screen/Author/Merge:title">Merge authors</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author/Merge:description">Merge another author into this ones</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author/Merge:stop">Cancel merge</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author/Merge:merge">Merge authors</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author/Merge:author_merge_desc">Please select the other author that you wish to merge into this author entry. Note that this row will remain and the other entry will have instances repointed to this one. The next screen will allow you to control the final values.</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author/Merge:primary_author">Primary author: </epp:phrase>
+<epp:phrase id="Plugin/Screen/Author/Merge:duplicate_author">Duplicate author ID: </epp:phrase>
+<epp:phrase id="Plugin/Screen/Author/Merge:Find">Find author</epp:phrase>
+
+<epp:phrase id="Plugin/Screen/Author/MergeDetails:title">Merge authors</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author/MergeDetails:stop">Cancel merge</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author/MergeDetails:merge">Merge authors</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author/MergeDetails:author_merge_desc">This screen permits you to merge the two author records. The base record is the default value. The values of the base records and the duplicate are displayed for reference.</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author/MergeDetails:primary_author">Primary author: </epp:phrase>
+<epp:phrase id="Plugin/Screen/Author/MergeDetails:duplicate_author">Duplicate author: </epp:phrase>
+<epp:phrase id="Plugin/Screen/Author/MergeDetails:automerge_field">Automatically merged</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author/MergeDetails:automerge">Multiple type fields will be automerged though there may be duplicates. These fields may contain duplicates</epp:phrase>
+<epp:phrase id="Plugin/Screen/Author/MergeDetails:no_such_author">No such author</epp:phrase>
+
 </epp:phrases>
Index: lib/lang/en/phrases/metafield.xml
===================================================================
--- lib/lang/en/phrases/metafield.xml	(revision 217)
+++ lib/lang/en/phrases/metafield.xml	(revision 224)
@@ -322,4 +322,42 @@
 <epp:phrase id="metafield_fieldopt_input_style_short">Short</epp:phrase>
 <epp:phrase id="metafield_fieldopt_fields_input_style_short">Short</epp:phrase>
 
+<!-- Author ID Updates -->
+<epp:phrase id="lib/metafield/itemref:validate">Validate</epp:phrase>
+<epp:phrase id="lib/metafield/namevalue:name">Name</epp:phrase>
+<epp:phrase id="lib/metafield/namevalue:value">Value</epp:phrase>
+
+<epp:phrase id="metafield_fieldopt_type_namevalue">namevalue</epp:phrase>
+<epp:phrase id="metafield_optdetails_type_namevalue">A field with a name-value entry type indexed on the value. Useful for multiple value fields that use a flexible key.</epp:phrase>
+<epp:phrase id="lib/searchfield:help_namevalue">Name-value pairs store and allow searching the value</epp:phrase>
+
+<epp:phrase id="author_fieldname_author">Author Name</epp:phrase>
+<epp:phrase id="author_fieldname_authorid">Author Unique ID</epp:phrase>
+<epp:phrase id="author_fieldname_userid">Author User ID</epp:phrase>
+<epp:phrase id="author_fieldname_primary_email">Primary Email Address</epp:phrase>
+<epp:phrase id="author_fieldname_alternate_email">Alternate Email Addresses</epp:phrase>
+<epp:phrase id="author_fieldname_external_id">External IDs</epp:phrase>
+<epp:phrase id="author_fieldname_bio">Author Biography</epp:phrase>
+<epp:phrase id="author_instance_fieldhelp_display_name">Display name of this instance</epp:phrase>
+
+
+<epp:phrase id="ordername_author_byname">Order by author name</epp:phrase>
+
+<epp:phrase id="author_fieldhelp_author">Details about the author's name</epp:phrase>
+<epp:phrase id="author_fieldhelp_userid">The author's ePrints user ID (if they have an equivalent user account)</epp:phrase>
+<epp:phrase id="author_fieldhelp_primary_email">The author's primary email address</epp:phrase>
+<epp:phrase id="author_fieldhelp_alternate_email">Alternate email addresses that the author might use</epp:phrase>
+<epp:phrase id="author_fieldhelp_external_id">External identifiers for the user with the name-value pairs of the external source and their preferred identity value</epp:phrase>
+<epp:phrase id="author_fieldhelp_bio">A short copy of the author's biography that can be displayed on relevant pages.</epp:phrase>
+
+<epp:phrase id="author_misc_nodescription">No description available for this author</epp:phrase>
+<epp:phrase id="author_instance_fieldhelp_authorid">Author ID linked to this instance</epp:phrase>
+<epp:phrase id="author_instance_fieldhelp_preferred">Is this the preferred author instance for this author</epp:phrase>
+<epp:phrase id="author_instance_fieldname_authorid">Author Unique Identifier</epp:phrase>
+<epp:phrase id="author_instance_fieldname_instanceid">Author Instance Unique Identifier</epp:phrase>
+<epp:phrase id="author_instance_fieldname_preferred">Preferred Author Instance</epp:phrase>
+<epp:phrase id="author_instance_fieldname_created_date">Instance Creation Date</epp:phrase>
+<epp:phrase id="author_instance_fieldname_display_name">Instance Display Name</epp:phrase>
+<epp:phrase id="lib/metafield/itemref:find_entry">Find entry</epp:phrase>
+
 </epp:phrases>
Index: lib/defaultcfg/cfg.d/author_instance_fields_default.pl
===================================================================
--- lib/defaultcfg/cfg.d/author_instance_fields_default.pl	(revision 0)
+++ lib/defaultcfg/cfg.d/author_instance_fields_default.pl	(revision 224)
@@ -0,0 +1,7 @@
+
+$c->{set_author_instance_defaults} = sub
+{
+	my( $data, $session ) = @_;
+
+};
+
Index: lib/defaultcfg/cfg.d/author_instance_render.pl
===================================================================
--- lib/defaultcfg/cfg.d/author_instance_render.pl	(revision 0)
+++ lib/defaultcfg/cfg.d/author_instance_render.pl	(revision 224)
@@ -0,0 +1,41 @@
+
+######################################################################
+
+=item $xhtmlfragment = author_render( $author, $session )
+
+This subroutine takes a author object and renders the XHTML view
+of this author for public viewing.
+
+Takes the L<$author|EPrints::DataObj::Author> to render and the current L<$session|EPrints::Session>.
+
+Returns an $xhtmlfragment (see L<EPrints::XML>).
+
+=cut
+
+######################################################################
+
+
+$c->{author_instance_render} = sub
+{
+	my( $author_instance, $session ) = @_;
+
+	my $html;	
+
+	my( $info, $p, $a );
+	$info = $session->make_doc_fragment;
+
+
+	# Render the public information about this author_instance.
+	$p = $session->make_element( "p" );
+	$p->appendChild( $author_instance->render_value("display_name") );
+	$info->appendChild( $p );
+	$p = $session->make_element( "p" );
+	# There is probably a better way of grabbing an author object and rendering a citation...
+	my $author = new EPrints::DataObj::Author($session, $author_instance->get_value("authorid") );
+	$p->appendChild( $author->render_citation_link );
+	$info->appendChild( $p );
+	
+
+	return( $info );
+};
+
Index: lib/defaultcfg/cfg.d/author_fields.pl
===================================================================
--- lib/defaultcfg/cfg.d/author_fields.pl	(revision 0)
+++ lib/defaultcfg/cfg.d/author_fields.pl	(revision 224)
@@ -0,0 +1,29 @@
+
+$c->{fields}->{author} = [
+
+          {
+            'name' => 'userid',
+            'type' => 'itemref',
+	    'datasetid' => 'user'
+          },
+
+          {
+            'name' => 'primary_email',
+            'type' => 'text',
+	    'text_index' => 1,
+          },
+
+	  {
+            'name' => 'alternate_email',
+            'type' => 'text',
+	    'multiple' => 1,
+	    'text_index' => 1,
+          },
+
+	  {
+	    'name' => 'external_id',
+	    'type' => 'namevalue',
+	    'multiple' => 1,
+	    'text_index' => 1,
+	  },
+];
Index: lib/defaultcfg/cfg.d/author_fields_automatic.pl
===================================================================
--- lib/defaultcfg/cfg.d/author_fields_automatic.pl	(revision 0)
+++ lib/defaultcfg/cfg.d/author_fields_automatic.pl	(revision 224)
@@ -0,0 +1,8 @@
+
+$c->{set_author_automatic_fields} = sub
+{
+	my( $author ) = @_;
+
+
+};
+
Index: lib/defaultcfg/cfg.d/search.pl
===================================================================
--- lib/defaultcfg/cfg.d/search.pl	(revision 217)
+++ lib/defaultcfg/cfg.d/search.pl	(revision 224)
@@ -131,6 +131,24 @@
 	show_zero_results => 1,
 };
 
+$c->{search}->{author} =
+{
+	search_fields => [
+		{ meta_fields => [ "author", ] },
+		{ meta_fields => [ "authorid", ] },
+		{ meta_fields => [ "userid", ] },
+#		{ meta_fields => [ "dept","org" ] },
+		{ meta_fields => [ "primary_email", "alternate_email" ] },
+		{ meta_fields => [ "external_id" ] },
+	],
+	citation => "result",
+	page_size => 20,
+	order_methods => {
+		"byname" 	 =>  "author",
+	},
+	default_order => "byname",
+};
+
 # If set to true, this option causes name searches to match the
 # starts of surnames. eg. if true then "smi" will match the name
 # "Smith".
Index: lib/defaultcfg/cfg.d/author_instance_fields.pl
===================================================================
--- lib/defaultcfg/cfg.d/author_instance_fields.pl	(revision 0)
+++ lib/defaultcfg/cfg.d/author_instance_fields.pl	(revision 224)
@@ -0,0 +1,4 @@
+
+$c->{fields}->{author_instance} = [
+
+];
Index: lib/defaultcfg/cfg.d/author_instance_fields_automatic.pl
===================================================================
--- lib/defaultcfg/cfg.d/author_instance_fields_automatic.pl	(revision 0)
+++ lib/defaultcfg/cfg.d/author_instance_fields_automatic.pl	(revision 224)
@@ -0,0 +1,8 @@
+
+$c->{set_author_instance_automatic_fields} = sub
+{
+	my( $author_instance ) = @_;
+
+
+};
+
Index: lib/defaultcfg/cfg.d/author_fields_default.pl
===================================================================
--- lib/defaultcfg/cfg.d/author_fields_default.pl	(revision 0)
+++ lib/defaultcfg/cfg.d/author_fields_default.pl	(revision 224)
@@ -0,0 +1,7 @@
+
+$c->{set_author_defaults} = sub
+{
+	my( $data, $session ) = @_;
+
+};
+
Index: lib/defaultcfg/cfg.d/author_render.pl
===================================================================
--- lib/defaultcfg/cfg.d/author_render.pl	(revision 0)
+++ lib/defaultcfg/cfg.d/author_render.pl	(revision 224)
@@ -0,0 +1,36 @@
+
+######################################################################
+
+=item $xhtmlfragment = author_render( $author, $session )
+
+This subroutine takes a author object and renders the XHTML view
+of this author for public viewing.
+
+Takes the L<$author|EPrints::DataObj::Author> to render and the current L<$session|EPrints::Session>.
+
+Returns an $xhtmlfragment (see L<EPrints::XML>).
+
+=cut
+
+######################################################################
+
+
+$c->{author_render} = sub
+{
+	my( $author, $session ) = @_;
+
+	my $html;	
+
+	my( $info, $p, $a );
+	$info = $session->make_doc_fragment;
+
+
+	# Render the public information about this author.
+	$p = $session->make_element( "p" );
+	$p->appendChild( $author->render_value("author") );
+	$info->appendChild( $p );
+	
+
+	return( $info );
+};
+
Index: lib/defaultcfg/workflows/author/default.xml
===================================================================
--- lib/defaultcfg/workflows/author/default.xml	(revision 0)
+++ lib/defaultcfg/workflows/author/default.xml	(revision 224)
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<workflow xmlns="http://eprints.org/ep3/workflow" xmlns:epc="http://eprints.org/ep3/control">
+
+  <flow>
+      <stage ref="default"/>
+  </flow>
+
+  <stage name="default">
+      <component><field ref="author"/></component>
+      <component type="Field::Itemref"><field ref="userid" external_lookup_url="{$config{perl_url}}/users/popup/user" external_lookup_params="userid="/></component>
+      <component><field ref="primary_email"/></component>
+      <component><field ref="alternate_email"/></component>
+      <component><field ref="external_id"/></component>
+      <component><field ref="bio"/></component>
+  </stage>
+
+</workflow>
Index: lib/defaultcfg/workflows/author_instance/default.xml
===================================================================
--- lib/defaultcfg/workflows/author_instance/default.xml	(revision 0)
+++ lib/defaultcfg/workflows/author_instance/default.xml	(revision 224)
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<workflow xmlns="http://eprints.org/ep3/workflow" xmlns:epc="http://eprints.org/ep3/control">
+
+  <flow>
+      <stage ref="default" />
+  </flow>
+
+  <stage name="default">
+      <component type="Field::Itemref"><field ref="authorid" external_lookup_url="{$config{perl_url}}/users/popup/author" external_lookup_params="authorid=" /></component>
+      <component><field ref="display_name" /></component>
+      <component><field ref="preferred" /></component>      
+  </stage>
+
+</workflow>
+
Index: lib/static/javascript/auto/50_popup.js
===================================================================
--- lib/static/javascript/auto/50_popup.js	(revision 0)
+++ lib/static/javascript/auto/50_popup.js	(revision 224)
@@ -0,0 +1,30 @@
+/**
+ * Popup Image Support
+ *
+ *
+ */
+
+/**
+ * Simple function to open a url in a new, named, window
+ */
+function popup(url, width, height) {
+	/* open a new popup window */
+	popupwindow = window.open(url, 'popup', 'scrollbars=yes,resizable=yes,height='+height+',width='+width+'');
+	/* set focus to the window in case it doesn't have it  */
+	if (window.focus) {popupwindow.focus()}
+	/* And off we go! */
+	return false;
+}
+
+/**
+ * Function to populate popup with a given field
+ */
+function popup_appendfield(fieldname, url, width, height) {
+	/* Get the original element */
+	element = document.getElementById(fieldname);
+	if(element && element.value) {
+		return popup(url + element.value, width, height);
+	} else {
+	 	return popup(url, width, height);
+	}
+}
Index: lib/citations/author/default.xml
===================================================================
--- lib/citations/author/default.xml	(revision 0)
+++ lib/citations/author/default.xml	(revision 224)
@@ -0,0 +1,15 @@
+<?xml version="1.0" ?>
+
+<!-- 
+	Citation Styles for author records.
+-->
+
+<cite:citation xmlns="http://www.w3.org/1999/xhtml" xmlns:cite="http://eprints.org/ep3/citation" xmlns:epc="http://eprints.org/ep3/control">
+
+<cite:linkhere><span class="ep_author_citation"><epc:choose>
+  <epc:when test="author"><epc:print expr="author"/></epc:when>
+  <epc:when test="email">Unnamed author with email <epc:print expr="email"/></epc:when>
+  <epc:otherwise>Unnamed author</epc:otherwise>
+</epc:choose></span></cite:linkhere>
+
+</cite:citation>
Index: lib/citations/author/result.xml
===================================================================
--- lib/citations/author/result.xml	(revision 0)
+++ lib/citations/author/result.xml	(revision 224)
@@ -0,0 +1,15 @@
+<?xml version="1.0" ?>
+
+<!-- 
+	Citation Styles for author records.
+-->
+
+<cite:citation xmlns="http://www.w3.org/1999/xhtml" xmlns:cite="http://eprints.org/ep3/citation" xmlns:epc="http://eprints.org/ep3/control">
+
+<cite:linkhere><span class="ep_author_citation"><epc:choose>
+  <epc:when test="author"><epc:print expr="author"/></epc:when>
+  <epc:when test="email">Unnamed author with email <epc:print expr="email"/></epc:when>
+  <epc:otherwise>Unnamed author</epc:otherwise>
+</epc:choose></span></cite:linkhere>
+
+</cite:citation>
Index: lib/citations/author_instance/default.xml
===================================================================
--- lib/citations/author_instance/default.xml	(revision 0)
+++ lib/citations/author_instance/default.xml	(revision 224)
@@ -0,0 +1,14 @@
+<?xml version="1.0" ?>
+
+<!-- 
+	Citation Styles for author instance records.
+-->
+
+<cite:citation xmlns="http://www.w3.org/1999/xhtml" xmlns:cite="http://eprints.org/ep3/citation" xmlns:epc="http://eprints.org/ep3/control">
+
+<cite:linkhere><span class="ep_author_instance_citation"><epc:choose>
+  <epc:when test="display_name"><epc:print expr="display_name"/></epc:when>
+  <epc:otherwise>Unnamed author instance</epc:otherwise>
+</epc:choose></span></cite:linkhere>
+
+</cite:citation>
Index: lib/citations/author_instance/result.xml
===================================================================
--- lib/citations/author_instance/result.xml	(revision 0)
+++ lib/citations/author_instance/result.xml	(revision 224)
@@ -0,0 +1,14 @@
+<?xml version="1.0" ?>
+
+<!-- 
+	Citation Styles for author instance records.
+-->
+
+<cite:citation xmlns="http://www.w3.org/1999/xhtml" xmlns:cite="http://eprints.org/ep3/citation" xmlns:epc="http://eprints.org/ep3/control">
+
+<cite:linkhere><span class="ep_author_instance_citation"><epc:choose>
+  <epc:when test="display_name"><epc:print expr="display_name"/></epc:when>
+  <epc:otherwise>Unnamed author instance</epc:otherwise>
+</epc:choose></span></cite:linkhere>
+
+</cite:citation>
