'
out << renderedElement
out << ((helpText.size() > 0) ? ' ' : '')
// add an disabled input box for feedback purposes
// @see dateElement(...)
if (addExampleElement) {
def exampleAttrs = new LinkedHashMap()
exampleAttrs.name = attrs.get('name') + 'Example'
exampleAttrs.class = 'isExample'
exampleAttrs.disabled = 'disabled'
exampleAttrs.size = 30
out << textField(exampleAttrs)
}
// add an disabled input box for feedback purposes
// @see dateElement(...)
if (addExample2Element) {
def exampleAttrs = new LinkedHashMap()
exampleAttrs.name = attrs.get('name') + 'Example2'
exampleAttrs.class = 'isExample'
exampleAttrs.disabled = 'disabled'
exampleAttrs.size = 30
out << textField(exampleAttrs)
}
out << '
'
// add help content if it is available
if (helpText.size() > 0) {
out << '
'
out << ' ' + helpText
out << '
'
}
out << '
'
}
/**
* bind an ajax submit to an onChange event
* @param attrs
* @return attrs
*/
private getAjaxOnChange = { attrs ->
// work variables
def internetExplorer = (request.getHeader("User-Agent") =~ /MSIE/)
def ajaxOnChange = attrs.remove('ajaxOnChange')
// is ajaxOnChange defined
if ( ajaxOnChange ) {
if (!attrs.onChange) attrs.onChange = ''
// add onChange AjaxSubmit javascript
if (internetExplorer) {
// - somehow IE submits these onchanges twice which messes up some parts of the wizard
// (especially the events page). In order to bypass this issue I have introduced an
// if statement utilizing the 'before' and 'after' functionality of the submitToRemote
// function. This check expects lastRequestTime to be in the global Javascript scope,
// (@see pageContent) and calculates the time difference in miliseconds between two
// onChange executions. If this is more than 100 miliseconds the request is executed,
// otherwise it will be ignored... --> 20100527 - Jeroen Wesbeek
attrs.onChange += ajaxSubmitJs(
[
before: "var execute=true;try { var currentTime=new Date().getTime();execute = ((currentTime-lastRequestTime) > 100);lastRequestTime=currentTime; } catch (e) {};if (execute) { 1",
after: "}",
functionName: ajaxOnChange,
url: attrs.get('url'),
update: attrs.get('update'),
afterSuccess: attrs.get('afterSuccess')
],
''
)
} else {
// this another W3C browser that actually behaves as expected... damn you IE, DAMN YOU!
attrs.onChange += ajaxSubmitJs(
[
functionName: ajaxOnChange,
url: attrs.get('url'),
update: attrs.get('update'),
afterSuccess: attrs.get('afterSuccess')
],
''
)
}
}
return attrs
}
/**
* render an ajaxButtonElement
* @param Map attrs
* @param Closure body (help text)
*/
def ajaxButtonElement = { attrs, body ->
baseElement.call(
'ajaxButton',
attrs,
body
)
}
/**
* render a textFieldElement
* @param Map attrs
* @param Closure body (help text)
*/
def textFieldElement = { attrs, body ->
// set default size, or scale to max length if it is less than the default size
if (!attrs.get("size")) {
if (attrs.get("maxlength")) {
attrs.size = ((attrs.get("maxlength") as int) > defaultTextFieldSize) ? defaultTextFieldSize : attrs.get("maxlength")
} else {
attrs.size = defaultTextFieldSize
}
}
// render template element
baseElement.call(
'textField',
attrs,
body
)
}
/**
* render a textAreaElement
* @param Map attrs
* @param Closure body (help text)
*/
def textAreaElement = { attrs, body ->
// set default size, or scale to max length if it is less than the default size
// render template element
baseElement.call(
'textArea',
attrs,
body
)
}
/**
* render a select form element
* @param Map attrs
* @param Closure body (help text)
*/
def selectElement = { attrs, body ->
baseElement.call(
'select',
attrs,
body
)
}
/**
* render a checkBox form element
* @param Map attrs
* @param Closure body (help text)
*/
def checkBoxElement = { attrs, body ->
baseElement.call(
'checkBox',
attrs,
body
)
}
/**
* render a set of radio form elements
* @param Map attrs
* @param Closure body (help text)
*/
def radioElement = { attrs, body ->
baseElement.call(
'radioList',
attrs,
body
)
}
/**
* render a set of radio elements
* @param Map attrs
* @param Closure body (help text)
*/
def radioList = { attrs ->
def checked = true
attrs.elements.each {
out << radio(
name: attrs.name,
value: it,
checked: (attrs.value == it || (!attrs.value && checked))
)
out << it
checked = false
}
}
/**
* render a dateElement
* NOTE: datepicker is attached through wizard.js!
* @param Map attrs
* @param Closure body (help text)
*/
def dateElement = { attrs, body ->
// transform value?
if (attrs.value instanceof Date) {
// transform date instance to formatted string (dd/mm/yyyy)
attrs.value = String.format('%td/%
// transform value?
if (attrs.value instanceof Date) {
// transform date instance to formatted string (dd/mm/yyyy)
attrs.value = String.format('%td/%
// render template element
baseElement.call(
'ajaxButton',
attrs,
body
)
}
/**
* Term form element
* @param Map attributes
* @param Closure help content
*/
def termElement = { attrs, body ->
// render term element
baseElement.call(
'termSelect',
attrs,
body
)
}
/**
* Term select element
* @param Map attributes
*/
// TODO: change termSelect to use Term accessions instead of preferred names, to make it possible to track back
// terms from multiple ontologies with possibly the same preferred name
def termSelect = { attrs ->
def from = []
// got ontologies?
if (attrs.ontologies) {
// are the ontologies a string?
if (attrs.ontologies instanceof String) {
attrs.ontologies.split(/\,/).each() { ncboId ->
// trim the id
ncboId.trim()
// fetch all terms for this ontology
def ontology = Ontology.findAllByNcboId(ncboId)
// does this ontology exist?
if (ontology) {
ontology.each() {
Term.findAllByOntology(it).each() {
// key = ncboId:concept-id
from[ from.size() ] = it.name
}
}
}
}
} else if (attrs.ontologies instanceof Set) {
// are they a set instead?
def ontologyList = ""
// iterate through set
attrs.ontologies.each() { ontology ->
if (ontology) {
ontologyList += ontology.ncboId + ","
Term.findAllByOntology(ontology).each() {
from[ from.size() ] = it.name
}
// strip trailing comma
attrs.ontologies = ontologyList[0..-2]
}
}
}
// sort alphabetically
from.sort()
// add a dummy field?
if (attrs.remove('addDummy')) {
from.add(0,'')
}
// define 'from'
attrs.from = from
// add 'rel' attribute
attrs.rel = 'term'
// got an ajaxOnChange defined?
attrs = getAjaxOnChange.call(
attrs
)
out << select(attrs)
} else {
out << "ontologies missing!"
}
}
/**
* Ontology form element
* @param Map attributes
* @param Closure help content
*/
def ontologyElement = { attrs, body ->
// @see http://www.bioontology.org/wiki/index.php/NCBO_Widgets#Term-selection_field_on_a_form
// @see ontology-chooser.js, table-editor.js
baseElement.call(
'textField',
[
name: attrs.name,
value: attrs.value,
description: attrs.description,
rel: 'ontology-' + ((attrs.ontology) ? attrs.ontology : 'all'),
size: 25
],
body
)
out << hiddenField(
name: attrs.name + '-concept_id'
)
out << hiddenField(
name: attrs.name + '-ontology_id'
)
out << hiddenField(
name: attrs.name + '-full_id'
)
}
/**
* Study form element
* @param Map attributes
* @param Closure help content
*/
def studyElement = { attrs, body ->
// render study element
baseElement.call(
'studySelect',
attrs,
body
)
}
/**
* render a study select element
* @param Map attrs
*/
def studySelect = { attrs ->
// Find all studies the user has access to (max 100)
attrs.from = Study.giveWritableStudies(AuthenticationService.getLoggedInUser(), 100);
// got a name?
if (!attrs.name) {
attrs.name = "study"
}
// got result?
if (attrs.from.size() > 0) {
out << select(attrs)
} else {
// no, return false to make sure this element
// is not rendered in the template
return false
}
}
/**
* Template form element
* @param Map attributes
* @param Closure help content
*/
def templateElement = { attrs, body ->
// render template element
baseElement.call(
'templateSelect',
attrs,
body
)
}
/**
* render a template select element
* @param Map attrs
*/
def templateSelect = { attrs ->
def entity = attrs.remove('entity')
// add the entity class name to the element
// do we have crypto information available?
if (grailsApplication.config.crypto) {
// generate a Blowfish encrypted and Base64 encoded string.
attrs['entity'] = URLEncoder.encode(
Blowfish.encryptBase64(
entity.toString().replaceAll(/^class /, ''),
grailsApplication.config.crypto.shared.secret
)
)
} else {
// base64 only; this is INSECURE! As this class
// is instantiated elsewehere. Possibly exploitable!
attrs['entity'] = URLEncoder.encode(entity.toString().replaceAll(/^class /, '').bytes.encodeBase64())
}
// fetch templates
attrs.from = (entity) ? Template.findAllByEntity(entity) : Template.findAll()
// got a name?
if (!attrs.name) {
attrs.name = 'template'
}
// add a rel element if it does not exist
if (!attrs.rel) {
attrs.rel = 'template'
}
// got an ajaxOnChange defined?
attrs = getAjaxOnChange.call(
attrs
)
// got result?
if (attrs.from.size() > 0 || attrs.get('addDummy')) {
// transform all values into strings
def from = []
attrs.from.each { from[ from.size() ] = it.toString() }
// sort alphabetically
from.sort()
// add a dummy field?
if (attrs.remove('addDummy')) {
from.add(0,'')
}
// set attributes
attrs.from = from
attrs.value = (attrs.value) ? attrs.value.toString() : ''
// output select element
out << select(attrs)
} else {
// no, return false to make sure this element
// is not rendered in the template
return false
}
}
/**
* File form element
* @param Map attributes
* @param Closure help content
*/
def fileFieldElement = { attrs, body ->
// render term element
baseElement.call(
'fileField',
attrs,
body
)
}
/**
* file field.
* @param attributes
*/
def fileField = { attrs ->
/*
out << ''
if( attrs.value ) {
out << 'Now contains: ' + attrs.value + ''
}
*/
out << '
Upload
';
out << '';
out << '';
out << '';
out << '\n";
}
/**
* Protocol form element
* @param Map attributes
* @param Closure help content
*/
def protocolElement = { attrs, body ->
// render protocol element
baseElement.call(
'protocolSelect',
attrs,
body
)
}
/**
* render a protocol select element
* @param Map attrs
*/
def protocolSelect = { attrs ->
// fetch all protocold
attrs.from = Protocol.findAll() // for now, all protocols
// got a name?
if (!attrs.name) {
attrs.name = 'protocol'
}
out << select(attrs)
}
def show = { attrs ->
// is object parameter set?
def o = attrs.object
println o.getProperties();
o.getProperties().each {
println it
}
out << "!! test version of 'show' tag !!"
}
/**
* render table headers for all subjectFields in a template
* @param Map attributes
*/
def templateColumnHeaders = { attrs ->
def entity = (attrs.get('entity'))
def template = (entity && entity instanceof TemplateEntity) ? entity.template : null
def columnWidths= (attrs.get('columnWidths')) ? attrs.remove('columnWidths') : []
// got a template?
if (template) {
// render template fields
entity.giveFields().each() {
// Format the column name by:
// - separating combined names (SampleName --> Sample Name)
// - capitalizing every seperate word
def ucName = it.name.replaceAll(/[a-z][A-Z][a-z]/) {
it[0] + ' ' + it[1..2]
}.replaceAll(/\w+/) {
it[0].toUpperCase() + ((it.size() > 1) ? it[1..-1] : '')
}
// strip spaces
def ucNameSpaceless = ucName.replaceAll(/ /) { '' }
// do we have to use a specific width for this column?
if (columnWidths[ucName]) {
out << '
' + ucName + (it.unit ? " (${it.unit})" : '')
}
if (it.comment) {
out << ''
out << '
' + it.comment + '
'
}
out << '
'
}
}
}
def templateColumns = { attrs ->
// render template fields as columns
attrs.renderType = 'column'
out << renderTemplateFields(attrs)
}
def templateElements = { attrs ->
// render template fields as form elements
attrs.renderType = 'element'
out << renderTemplateFields(attrs)
}
/**
* render form elements based on an entity's template
* @param Map attributes
* @param String body
*/
def renderTemplateFields = { attrs ->
def renderType = attrs.remove('renderType')
def entity = (attrs.get('entity'))
def prependName = (attrs.get('name')) ? attrs.remove('name')+'_' : ''
def template = (entity && entity instanceof TemplateEntity) ? entity.template : null
def inputElement= null
def addDummy = (attrs.get('addDummy')) ? true : false
// got a template?
if (template) {
// render template fields
entity.giveFields().each() {
def fieldValue = entity.getFieldValue(it.name)
def helpText = (it.comment && renderType == 'element') ? it.comment : ''
def ucName = it.name[0].toUpperCase() + it.name.substring(1)
// output column opening element?
if (renderType == 'column') {
out << '
'
}
switch (it.type.toString()) {
case ['STRING', 'DOUBLE', 'LONG']:
inputElement = (renderType == 'element') ? 'textFieldElement' : 'textField'
out << "$inputElement"(
description : ucName,
name : prependName + it.escapedName(),
value : fieldValue,
required : it.isRequired()
){helpText}
break
case 'TEXT':
inputElement = (renderType == 'element') ? 'textAreaElement' : 'textField'
out << "$inputElement"(
description : ucName,
name : prependName + it.escapedName(),
value : fieldValue,
required : it.isRequired()
){helpText}
break
case 'STRINGLIST':
inputElement = (renderType == 'element') ? 'selectElement' : 'select'
if (!it.listEntries.isEmpty()) {
out << "$inputElement"(
description : ucName,
name : prependName + it.escapedName(),
from : it.listEntries,
value : fieldValue,
required : it.isRequired()
){helpText}
} else {
out << 'no values!!'
}
break
case 'ONTOLOGYTERM':
// @see http://www.bioontology.org/wiki/index.php/NCBO_Widgets#Term-selection_field_on_a_form
// @see ontology-chooser.js
inputElement = (renderType == 'element') ? 'termElement' : 'termSelect'
// override addDummy to always add the dummy...
addDummy = true
if (it.ontologies) {
out << "$inputElement"(
description : ucName,
name : prependName + it.escapedName(),
value : fieldValue.toString(),
ontologies : it.ontologies,
addDummy : addDummy,
required : it.isRequired()
){helpText}
} else {
out << "$inputElement"(
description : ucName,
name : prependName + it.escapedName(),
value : fieldValue.toString(),
addDummy : addDummy,
required : it.isRequired()
){helpText}
}
break
case 'ONTOLOGYTERM-old':
// @see http://www.bioontology.org/wiki/index.php/NCBO_Widgets#Term-selection_field_on_a_form
// @see ontology-chooser.js
inputElement = (renderType == 'element') ? 'textFieldElement' : 'textField'
out << "$inputElement"(
name : prependName + it.escapedName(),
value : fieldValue,
rel : 'ontology-all',
size : 100,
required: it.isRequired()
)
out << hiddenField(
name: prependName + it.name + '-concept_id',
value: fieldValue
)
out << hiddenField(
name: prependName + it.escapedName() + '-ontology_id',
value: fieldValue
)
out << hiddenField(
name: prependName + it.escapedName() + '-full_id',
value: fieldValue
)
break
case 'DATE':
inputElement = (renderType == 'element') ? 'dateElement' : 'textField'
// transform value?
if (fieldValue instanceof Date) {
if (fieldValue.getHours() == 0 && fieldValue.getMinutes() == 0) {
// transform date instance to formatted string (dd/mm/yyyy)
fieldValue = String.format('%td/%!' + it.type + ''
break
}
// output column closing element?
if (renderType == 'column') {
out << '
'
}
}
}
}
def PublicationSelectElement = { attrs, body ->
attrs.description = 'Publications';
// render list with publications currently available
baseElement.call(
'_publicationList',
attrs,
body
)
attrs.description = '';
// render 'Add publication button'
baseElement.call(
'_publicationAddButton',
attrs,
body
)
}
/**
* Renders a input box for publications
*/
def publicationSelect = { attrs, body ->
if (attrs.get('value') == null) {
attrs.value = [];
}
if (attrs.get('description') == null) {
attrs.description = '';
}
out << '';
out << '';
}
def _publicationList = { attrs, body ->
def display_none = 'none';
if (!attrs.get('value') || attrs.get('value').size() == 0) {
display_none = 'inline';
}
// Add a unordered list
out << '
';
out << '
';
out << '';
out << 'No publications selected';
out << '';
out << '
';
out << '
';
// Add the publications using javascript
out << '';
def ids;
if (attrs.get('value') && attrs.get('value').size() > 0) {
ids = attrs.get('value').id.join(',')
} else {
ids = '';
}
out << '';
}
def _publicationAddButton = { attrs, body ->
// Output the dialog for the publications
out << '
';
out << '
Search for a publication on pubmed. You can search on a part of the title, authors or pubmed ID.
';
out << publicationSelect(attrs, body);
out << '
';
out << '';
out << '';
}
def ContactSelectElement = { attrs, body ->
attrs.description = 'Contacts';
// render list with publications currently available
baseElement.call(
'_contactList',
attrs,
body
)
attrs.description = '';
// render 'publications list'
out << '
'
baseElement.call(
'_personSelect',
attrs,
body
)
baseElement.call(
'_roleSelect',
attrs,
body
)
baseElement.call(
'_contactAddButtonAddition',
attrs,
body
)
out << '
';
// render 'Add contact button'
baseElement.call(
'_contactAddDialogButton',
attrs,
body
)
}
def _contactList = { attrs, body ->
def display_none = 'none';
if (!attrs.get('value') || attrs.get('value').size() == 0) {
display_none = 'inline';
}
// Add a unordered list
out << '
';
out << '
';
out << '';
out << 'No contacts selected';
out << '';
out << '
';
out << '
';
// Add the contacts using javascript
out << '';
def ids = '';
if (attrs.get('value') && attrs.get('value').size() > 0) {
ids = attrs.get('value').collect { it.person.id + '-' + it.role.id }
ids = ids.join(',');
}
out << '';
}
def _contactAddSelect = { attrs, body ->
out << _personSelect(attrs) + _roleSelect(attrs);
}
def _contactAddButtonAddition = { attrs, body ->
out << '';
out << '';
}
def _contactAddDialogButton = { attrs, body ->
out << '';
}
/**
* Person select element
* @param Map attributes
*/
def _personSelect = { attrs ->
def selectAttrs = new LinkedHashMap();
// define 'from'
def persons = Person.findAll().sort({ a, b -> a.lastName == b.lastName ? (a.firstName <=> b.firstName) : (a.lastName <=> b.lastName) } as Comparator);
selectAttrs.from = persons.collect { it.lastName + ', ' + it.firstName + (it.prefix ? ' ' + it.prefix : '') }
selectAttrs.keys = persons.id;
// add 'rel' attribute
selectAttrs.rel = 'person'
selectAttrs.name = attrs.name + '_person';
// add a dummy field
selectAttrs.from.add(0,'')
selectAttrs.keys.add(0,'')
out << "Person: " + select(selectAttrs)
}
/**
* Role select element
* @param Map attributes
*/
def _roleSelect = { attrs ->
def selectAttrs = new LinkedHashMap();
// define 'from'
def roles = PersonRole.findAll();
selectAttrs.from = roles.collect { it.name };
selectAttrs.keys = roles.id;
// add 'rel' attribute
selectAttrs.rel = 'role'
selectAttrs.name = attrs.name + '_role';
// add a dummy field
selectAttrs.from.add(0,'')
selectAttrs.keys.add(0,'')
out << "Role: " + select(selectAttrs)
}
def UserSelectElement = { attrs, body ->
// render list with publications currently available
baseElement.call(
'_userList',
attrs,
body
)
attrs.description = '';
// render 'Add user button'
baseElement.call(
'_userAddButton',
attrs,
body
)
}
/**
* Renders an input box for publications
*/
def userSelect = { attrs, body ->
if (attrs.get('value') == null) {
attrs.value = [];
}
if (attrs.get('description') == null) {
attrs.description = '';
}
out << '';
}
def _userList = { attrs, body ->
def display_none = 'none';
if (!attrs.get('value') || attrs.get('value').size() == 0) {
display_none = 'inline';
}
// Add a unordered list
out << '
';
out << '
';
out << '';
out << '-';
out << '';
out << '
';
out << '
';
// Add the publications using javascript
out << '';
def ids;
if (attrs.get('value') && attrs.get('value').size() > 0) {
ids = attrs.get('value').id.join(',')
} else {
ids = '';
}
out << '';
}
def _userAddButton =