Include Javascript in the workflow
Sometimes you need to augment an EPrints workflow in a specific way. One of the ways you can do this is using javascript but it is not immediately clear how to do that. There are several options available which may suit what you need to do.
Contents
Pure Javascript
This should be the prefered method although it is not always straight forward to use depending what your trying to do. EPrints stores javascript files in eprints_root/archives/archive_id/cfg/static/javascript/auto/
and it EPrints ships with PrototypeJS. If your workflow problem is specific enough you can simply use
$$('.any-css-selectors').each( function( matching_element ) { // your code here });
Custom input renderer
You can overwrite the input renderer for the field you wish to modify. This gives you access to information used to render the field.
{
'name' => 'courses',
'type' => 'text',
'multiple' => 1,
'text_index' => 1,
'render_input' => sub {
my ( $field, $repository, $current_value, $dataset, $staff, $hidden_fields, $object, $basename ) = @_;
my $dom = $field->render_input_field_actual( $repository, $current_value, $dataset, $staff, $hidden_fields, $object, $basename );
my $script = $repository->xml->create_element("script", type=>"text/javascript");
my $perl = "print STDERR 'This will be printed to the error log.';
$script->appendChild($repository->xml->create_text_node('
// your javascript here '." which can have $perl interlaced "
));
}
},
Example custom input renderer
Below is an example of a custom renderer. This is for a multiple select form element, where some of the options have become deprecated. The code will add a message to a warning box if either when the page loads or whilst the user is selecting options they choose an option that is deprecated. However, it will not prevent them from choosing this option.
{
'name' => 'divisions',
'type' => 'subject',
'multiple' => 1,
'top' => 'divisions',
'browse_link' => 'divisions',
'render_input' => sub {
my ( $field, $repository, $current_value, $dataset, $staff, $hidden_fields, $object, $basename ) = @_;
my $messagebox = $repository->xml->create_element("div", id=>$basename."_messagebox", class=>"ep_msg_warning_content_no_table", style=>"display: none;");
my $messagelist = $repository->xml->create_element("div", id=>$basename."_messagelist");
$messagebox->appendChild($messagelist);
my $dom = $field->render_input_field_actual( $repository, $current_value, $dataset, $staff, $hidden_fields, $object, $basename );
my $script = $repository->make_javascript('var selectmenu = document.getElementById("'.$basename.'");
window.addEventListener("load", function(){ setDivisionsMessage(selectmenu) });
selectmenu.addEventListener("click", function(){ setDivisionsMessage(selectmenu); });
function setDivisionsMessage(selectmenu){
var messagebox = document.getElementById("'.$basename.'_messagebox");
var messagelist = document.getElementById("'.$basename.'_messagelist");
messagelist.innerHTML = "";
var historical_divisions = [ "cen_sis", "cen_mpm", "fac_acc", "fac_fin", "fac_ms", "fac_mar", "fac_om", "fac_ob", "fac_sts", "fac_sei" ];
for (var i=0, j=selectmenu.options.length; i<j; i++) {
if (selectmenu.options[i].selected && historical_divisions.indexOf(selectmenu.options[i].value) != -1){
var message = document.createElement("li");
message.appendChild(document.createTextNode(selectmenu.options[i].innerHTML + " is a historical centre. Please considering choosing a different centre"));
messagelist.appendChild(message);
}
}
messagebox.style.display = (messagelist.children.length > 0 ? "block" : "none");
}
');
my $superdom = $repository->xml->create_element("div");
$superdom->appendChild($messagebox);
$superdom->appendChild($dom);
$superdom->appendChild($script);
return $superdom;
}
},
XHTML Component
You if you are in hurry or prototyping then you can use a HTML Component
<component type='XHTML'>
<script type='text/javascript'>
//your javascript goes here
</script>
</component>
The downside of this approach is it leaves a tiny bit of workflow component floating in your workflow so you probably wouldn't use it in production.