source: trunk/grails-app/taglib/dbnp/studycapturing/WizardTagLib.groovy @ 349

Last change on this file since 349 was 349, checked in by duh, 12 years ago
  • added more templates to bootstrap
  • added a 300ms delay to ontology-chooser
  • refactored wizard subject page's "add subjects" dialogue (not working yet!) to incorporate an ontology field instead of a term select... this has to change though...
  • added template elements to tag library (ajaxButtonField and ontologyField)
  • minified ontology-chooser javascript
  • minified wizard.css
  • Property svn:keywords set to Date Rev Author
File size: 20.3 KB
RevLine 
[86]1package dbnp.studycapturing
[96]2
[86]3import org.codehaus.groovy.grails.plugins.web.taglib.JavascriptTagLib
[140]4import dbnp.studycapturing.*
5import dbnp.data.*
[86]6
7/**
8 * Wizard tag library
9 *
[96]10 * @author Jeroen Wesbeek
11 * @since 20100113
[86]12 * @package wizard
13 *
14 * Revision information:
15 * $Rev: 349 $
16 * $Author: duh $
17 * $Date: 2010-04-19 11:05:48 +0000 (ma, 19 apr 2010) $
18 */
19class WizardTagLib extends JavascriptTagLib {
[96]20        // define the tag namespace (e.g.: <wizard:action ... />
21        static namespace = "wizard"
[86]22
[96]23        // define the AJAX provider to use
24        static ajaxProvider = "jquery"
[89]25
[96]26        // define default text field width
27        static defaultTextFieldSize = 25;
[86]28
[96]29        /**
30         * ajaxButton tag, this is a modified version of the default
31         * grails submitToRemote tag to work with grails webflows.
32         * Usage is identical to submitToRemote with the only exception
33         * that a 'name' form element attribute is required. E.g.
34         * <wizard:ajaxButton name="myAction" value="myButton ... />
35         *
[101]36         * you can also provide a javascript function to execute after
37         * success. This behaviour differs from the default 'after'
38         * action which always fires after a button press...
39         *
[96]40         * @see http://blog.osx.eu/2010/01/18/ajaxifying-a-grails-webflow/
41         * @see http://www.grails.org/WebFlow
42         * @see http://www.grails.org/Tag+-+submitToRemote
43         * @todo perhaps some methods should be moved to a more generic
[189]44         *        'webflow' taglib or plugin
[96]45         * @param Map attributes
46         * @param Closure body
47         */
[246]48        def ajaxButton = {attrs, body ->
[96]49                // get the jQuery version
50                def jQueryVersion = grailsApplication.getMetadata()['plugins.jquery']
[86]51
[96]52                // fetch the element name from the attributes
53                def elementName = attrs['name'].replaceAll(/ /, "_")
[86]54
[101]55                // javascript function to call after success
56                def afterSuccess = attrs['afterSuccess']
57
[216]58                // src parameter?
59                def src = attrs['src']
60                def alt = attrs['alt']
61
[96]62                // generate a normal submitToRemote button
63                def button = submitToRemote(attrs, body)
[86]64
[96]65                /**
66                 * as of now (grails 1.2.0 and jQuery 1.3.2.4) the grails webflow does
67                 * not properly work with AJAX as the submitToRemote button does not
68                 * handle and submit the form properly. In order to support webflows
69                 * this method modifies two parts of a 'normal' submitToRemote button:
70                 *
71                 * 1) replace 'this' with 'this.form' as the 'this' selector in a button
72                 *    action refers to the button and / or the action upon that button.
73                 *    However, it should point to the form the button is part of as the
74                 *    the button should submit the form data.
75                 * 2) prepend the button name to the serialized data. The default behaviour
76                 *    of submitToRemote is to remove the element name altogether, while
77                 *    the grails webflow expects a parameter _eventId_BUTTONNAME to execute
78                 *    the appropriate webflow action. Hence, we are going to prepend the
79                 *    serialized formdata with an _eventId_BUTTONNAME parameter.
80                 */
81                if (jQueryVersion =~ /^1.([1|2|3]).(.*)/) {
82                        // fix for older jQuery plugin versions
83                        button = button.replaceFirst(/data\:jQuery\(this\)\.serialize\(\)/, "data:\'_eventId_${elementName}=1&\'+jQuery(this.form).serialize()")
84                } else {
85                        // as of jQuery plugin version 1.4.0.1 submitToRemote has been modified and the
86                        // this.form part has been fixed. Consequently, our wrapper has changed as well...
87                        button = button.replaceFirst(/data\:jQuery/, "data:\'_eventId_${elementName}=1&\'+jQuery")
88                }
[246]89
[101]90                // add an after success function call?
91                // usefull for performing actions on success data (hence on refreshed
92                // wizard pages, such as attaching tooltips)
93                if (afterSuccess) {
94                        button = button.replaceFirst(/\.html\(data\)\;/, '.html(data);' + afterSuccess + ';')
95                }
[88]96
[216]97                // got an src parameter?
98                if (src) {
99                        def replace = 'type="image" src="' + src + '"'
100
101                        if (alt) replace = replace + ' alt="' + alt + '"'
102
103                        button = button.replaceFirst(/type="button"/, replace)
104                }
105
[101]106                // replace double semi colons
[138]107                button = button.replaceAll(/;{2,}/, ';')
[246]108
[96]109                // render button
110                out << button
111        }
[88]112
[96]113        /**
[240]114         * generate a ajax submit JavaScript
115         * @see WizardTagLib::ajaxFlowRedirect
116         * @see WizardTagLib::baseElement (ajaxSubmitOnChange)
117         */
[246]118        def ajaxSubmitJs = {attrs, body ->
[240]119                // define AJAX provider
120                setProvider([library: ajaxProvider])
121
122                // got a function name?
123                def functionName = attrs.remove('functionName')
124                if (functionName && !attrs.get('name')) {
125                        attrs.name = functionName
126                }
127
128                // generate an ajax button
129                def button = this.ajaxButton(attrs, body)
130
131                // strip the button part to only leave the Ajax call
[246]132                button = button.replaceFirst(/<[^\"]*\"jQuery.ajax/, 'jQuery.ajax')
133                button = button.replaceFirst(/return false.*/, '')
[240]134
135                // change form if a form attribute is present
136                if (attrs.get('form')) {
137                        button = button.replaceFirst(/this\.form/,
138                                "\\\$('" + attrs.get('form') + "')"
139                        )
140                }
141
142                out << button
143        }
144
145        /**
[101]146         * generate ajax webflow redirect javascript
147         *
148         * As we have an Ajaxified webflow, the initial wizard page
149         * cannot contain a wizard form, as upon a failing submit
150         * (e.g. the form data does not validate) the form should be
151         * shown again. However, the Grails webflow then renders the
152         * complete initial wizard page into the success div. As this
153         * ruins the page layout (a page within a page) we want the
154         * initial page to redirect to the first wizard form to enter
155         * the webflow correctly. We do this by emulating an ajax post
156         * call which updates the wizard content with the first wizard
157         * form.
158         *
159         * Usage: <wizard:ajaxFlowRedirect form="form#wizardForm" name="next" url="[controller:'wizard',action:'pages']" update="[success:'wizardPage',failure:'wizardError']" />
160         * form = the form identifier
161         * name = the action to execute in the webflow
162         * update = the divs to update upon success or error
163         *
[240]164         * OR: to generate a JavaScript function you can call yourself, use 'functionName' instead of 'name'
165         *
[101]166         * Example initial webflow action to work with this javascript:
167         * ...
[246]168         * mainPage {*  render(view: "/wizard/index")
169         *      onRender {*             flow.page = 1
170         *}*    on("next").to "pageOne"
171         *}* ...
[101]172         *
173         * @param Map attributes
174         * @param Closure body
175         */
[246]176        def ajaxFlowRedirect = {attrs, body ->
[101]177                // generate javascript
[240]178                out << '<script type="text/javascript">'
[101]179                out << '$(document).ready(function() {'
[240]180                out << ajaxSubmitJs(attrs, body)
[101]181                out << '});'
182                out << '</script>'
183        }
184
185        /**
[96]186         * render the content of a particular wizard page
187         * @param Map attrs
[107]188         * @param Closure body  (help text)
[96]189         */
190        def pageContent = {attrs, body ->
191                // define AJAX provider
192                setProvider([library: ajaxProvider])
[89]193
[96]194                // render new body content
195                out << render(template: "/wizard/common/tabs")
196                out << '<div class="content">'
197                out << body()
198                out << '</div>'
199                out << render(template: "/wizard/common/navigation")
[103]200                out << render(template: "/wizard/common/error")
[96]201        }
202
[98]203        /**
[145]204         * generate a base form element
[246]205         * @param String inputElement name
206         * @param Map attributes
207         * @param Closure help content
[98]208         */
[246]209        def baseElement = {inputElement, attrs, help ->
[107]210                // work variables
[145]211                def description = attrs.remove('description')
[107]212                def addExampleElement = attrs.remove('addExampleElement')
[246]213                def addExample2Element = attrs.remove('addExample2Element')
[349]214                def helpText = help().trim()
[107]215
[240]216                // got an ajax onchange action?
217                def ajaxOnChange = attrs.remove('ajaxOnChange')
218                if (ajaxOnChange) {
219                        if (!attrs.onChange) attrs.onChange = ''
220
221                        // add onChange AjaxSubmit javascript
222                        attrs.onChange += ajaxSubmitJs(
223                                [
224                                        functionName: ajaxOnChange,
225                                        url: attrs.get('url'),
226                                        update: attrs.get('update'),
227                                        afterSuccess: attrs.get('afterSuccess')
228                                ],
229                                ''
230                        )
231                }
232
[238]233                // execute inputElement call
234                def renderedElement = "$inputElement"(attrs)
235
236                // if false, then we skip this element
237                if (!renderedElement) return false
238
[145]239                // render a form element
[96]240                out << '<div class="element">'
241                out << ' <div class="description">'
[145]242                out << description
[96]243                out << ' </div>'
244                out << ' <div class="input">'
[238]245                out << renderedElement
[349]246                if (helpText.size() > 0) {
[145]247                        out << '        <div class="helpIcon"></div>'
[107]248                }
249
250                // add an disabled input box for feedback purposes
251                // @see dateElement(...)
252                if (addExampleElement) {
253                        def exampleAttrs = new LinkedHashMap()
[246]254                        exampleAttrs.name = attrs.get('name') + 'Example'
255                        exampleAttrs.class = 'isExample'
[107]256                        exampleAttrs.disabled = 'disabled'
[145]257                        exampleAttrs.size = 30
[107]258                        out << textField(exampleAttrs)
259                }
260
[209]261                // add an disabled input box for feedback purposes
262                // @see dateElement(...)
263                if (addExample2Element) {
264                        def exampleAttrs = new LinkedHashMap()
[246]265                        exampleAttrs.name = attrs.get('name') + 'Example2'
266                        exampleAttrs.class = 'isExample'
[209]267                        exampleAttrs.disabled = 'disabled'
268                        exampleAttrs.size = 30
269                        out << textField(exampleAttrs)
270                }
271
[96]272                out << ' </div>'
273
[107]274                // add help content if it is available
[349]275                if (helpText.size() > 0) {
[107]276                        out << '  <div class="helpContent">'
[349]277                        out << '    ' + helpText
[96]278                        out << '  </div>'
279                }
280
281                out << '</div>'
282        }
[107]283
[145]284        /**
[349]285         * render an ajaxButtonElement
286         * @param Map attrs
287         * @param Closure body  (help text)
288         */
289        def ajaxButtonElement = { attrs, body ->
290                baseElement.call(
291                        'ajaxButton',
292                        attrs,
293                        body
294                )
295        }
296
297        /**
[145]298         * render a textFieldElement
299         * @param Map attrs
300         * @param Closure body  (help text)
301         */
[246]302        def textFieldElement = {attrs, body ->
[145]303                // set default size, or scale to max length if it is less than the default size
304                if (!attrs.get("size")) {
305                        if (attrs.get("maxlength")) {
306                                attrs.size = ((attrs.get("maxlength") as int) > defaultTextFieldSize) ? defaultTextFieldSize : attrs.get("maxlength")
307                        } else {
308                                attrs.size = defaultTextFieldSize
309                        }
310                }
[140]311
[145]312                // render template element
313                baseElement.call(
314                        'textField',
315                        attrs,
316                        body
317                )
[140]318        }
319
[107]320        /**
[209]321         * render a select form element
322         * @param Map attrs
323         * @param Closure body  (help text)
324         */
[246]325        def selectElement = {attrs, body ->
[209]326                baseElement.call(
327                        'select',
328                        attrs,
329                        body
330                )
331        }
332
333        /**
334         * render a checkBox form element
335         * @param Map attrs
336         * @param Closure body  (help text)
337         */
[246]338        def checkBoxElement = {attrs, body ->
[209]339                baseElement.call(
340                        'checkBox',
341                        attrs,
342                        body
343                )
344        }
345
346        /**
[107]347         * render a dateElement
[145]348         * NOTE: datepicker is attached through wizard.js!
[107]349         * @param Map attrs
350         * @param Closure body  (help text)
351         */
[246]352        def dateElement = {attrs, body ->
[138]353                // transform value?
354                if (attrs.value instanceof Date) {
355                        // transform date instance to formatted string (dd/mm/yyyy)
356                        attrs.value = String.format('%td/%<tm/%<tY', attrs.value)
357                }
[246]358
[250]359                // add 'rel' field to identity the datefield using javascript
360                attrs.rel = 'date'
361
[107]362                // set some textfield values
[209]363                attrs.maxlength = (attrs.maxlength) ? attrs.maxlength : 10
[107]364                attrs.addExampleElement = true
[246]365
[107]366                // render a normal text field
[145]367                //out << textFieldElement(attrs,body)
368                textFieldElement.call(
369                        attrs,
370                        body
371                )
[107]372        }
[209]373
374        /**
375         * render a dateElement
376         * NOTE: datepicker is attached through wizard.js!
377         * @param Map attrs
378         * @param Closure body  (help text)
379         */
[246]380        def timeElement = {attrs, body ->
[209]381                // transform value?
382                if (attrs.value instanceof Date) {
383                        // transform date instance to formatted string (dd/mm/yyyy)
384                        attrs.value = String.format('%td/%<tm/%<tY %<tH:%<tM', attrs.value)
385                }
386
[250]387                // add 'rel' field to identity the field using javascript
388                attrs.rel = 'datetime'
389
[209]390                attrs.addExampleElement = true
391                attrs.addExample2Element = true
392                attrs.maxlength = 16
393
394                // render a normal text field
395                //out << textFieldElement(attrs,body)
396                textFieldElement.call(
397                        attrs,
398                        body
399                )
400        }
[246]401
[145]402        /**
403         * Template form element
[246]404         * @param Map attributes
405         * @param Closure help content
[145]406         */
[246]407        def speciesElement = {attrs, body ->
[145]408                // render template element
409                baseElement.call(
410                        'speciesSelect',
411                        attrs,
412                        body
413                )
414        }
[138]415
416        /**
[209]417         * Button form element
[246]418         * @param Map attributes
419         * @param Closure help content
[209]420         */
[246]421        def buttonElement = {attrs, body ->
[209]422                // render template element
423                baseElement.call(
424                        'ajaxButton',
425                        attrs,
426                        body
427                )
428        }
429
430        /**
[138]431         * render a species select element
432         * @param Map attrs
433         */
[246]434        def speciesSelect = {attrs ->
[159]435                // fetch the speciesOntology
436                // note that this is a bit nasty, probably the ontologyName should
[209]437                // be configured in a configuration file... --> TODO: centralize species configuration
[159]438                def speciesOntology = Ontology.findByName('NCBI Taxonomy')
439
[138]440                // fetch all species
[159]441                attrs.from = Term.findAllByOntology(speciesOntology)
[138]442
443                // got a name?
444                if (!attrs.name) {
[159]445                        // nope, use a default name
[138]446                        attrs.name = 'species'
447                }
448
449                out << select(attrs)
450        }
[140]451
[349]452        /**
453         * Ontology form element
454         * @param Map attributes
455         * @param Closure help content
456         */
457        def ontologyElement = { attrs, body ->
458                // @see http://www.bioontology.org/wiki/index.php/NCBO_Widgets#Term-selection_field_on_a_form
459                // @see ontology-chooser.js, table-editor.js
460                baseElement.call(
461                        'textField',
462                        [
463                            name: attrs.name,
464                                value: attrs.value,
465                                description: attrs.description,
466                                rel: 'ontology-' + ((attrs.ontology) ? attrs.ontology : 'all') + '-name',
467                                size: 25
468                        ],
469                        body
470                )
471                out << hiddenField(
472                        name: attrs.name + '-concept_id'
473                )
474                out << hiddenField(
475                        name: attrs.name + '-ontology_id'
476                )
477                out << hiddenField(
478                        name: attrs.name + '-full_id'
479                )
480        }
[341]481
[140]482        /**
[341]483         * Study form element
484         * @param Map attributes
485         * @param Closure help content
486         */
487        def studyElement = { attrs, body ->
488                // render study element
489                baseElement.call(
490                        'studySelect',
491                        attrs,
492                        body
493                )
494        }
495
496
497        /**
498         * render a study select element
499         * @param Map attrs
500         */
501        def studySelect = { attrs ->
502                // for now, just fetch all studies
503                attrs.from = Study.findAll()
504
505                // got a name?
506                if (!attrs.name) {
507                        attrs.name = "study"
508                }
509
510                // got result?
511                if (attrs.from.size() > 0) {
512                        out << select(attrs)
513                } else {
514                        // no, return false to make sure this element
515                        // is not rendered in the template
516                        return false
517                }
518        }
519
520        /**
[145]521         * Template form element
[246]522         * @param Map attributes
523         * @param Closure help content
[145]524         */
[246]525        def templateElement = {attrs, body ->
[145]526                // render template element
527                baseElement.call(
528                        'templateSelect',
529                        attrs,
530                        body
531                )
532        }
[246]533
[145]534        /**
[140]535         * render a template select element
536         * @param Map attrs
537         */
[246]538        def templateSelect = {attrs ->
[238]539                def entity = attrs.remove('entity')
[140]540
[238]541                // fetch templates
[246]542                if (attrs.remove('addDummy')) {
543                        attrs.from = ['']
544                        if (entity && entity instanceof Class) {
545                                Template.findAllByEntity(entity).each() {
546                                        attrs.from[attrs.from.size()] = it
547                                }
548                        }
549                } else {
550                        attrs.from = (entity) ? Template.findAllByEntity(entity) : Template.findAll()
551                }
[238]552
[140]553                // got a name?
554                if (!attrs.name) {
555                        attrs.name = 'template'
556                }
[238]557
558                // got result?
[246]559                if (attrs.from.size() > 0) {
[238]560                        out << select(attrs)
561                } else {
562                        // no, return false to make sure this element
563                        // is not rendered in the template
564                        return false
565                }
[140]566        }
[145]567
[157]568        /**
[209]569         * Term form element
[246]570         * @param Map attributes
571         * @param Closure help content
[209]572         */
[246]573        def termElement = {attrs, body ->
[209]574                // render term element
575                baseElement.call(
576                        'termSelect',
577                        attrs,
578                        body
579                )
580        }
581
582        /**
583         * render a term select element
584         * @param Map attrs
585         */
[246]586        def termSelect = {attrs ->
[209]587                // fetch all terms
588                attrs.from = Term.findAll()     // for now, all terms as we cannot identify terms as being treatment terms...
589
590                // got a name?
591                if (!attrs.name) {
592                        attrs.name = 'term'
593                }
594
595                out << select(attrs)
596        }
597
[246]598        /**
599         * Protocol form element
600         * @param Map attributes
601         * @param Closure help content
602         */
603        def protocolElement = {attrs, body ->
604                // render protocol element
605                baseElement.call(
606                        'protocolSelect',
607                        attrs,
608                        body
609                )
610        }
611
612        /**
613         * render a protocol select element
614         * @param Map attrs
615         */
616        def protocolSelect = {attrs ->
617                // fetch all protocold
618                attrs.from = Protocol.findAll() // for now, all protocols
619
620                // got a name?
621                if (!attrs.name) {
622                        attrs.name = 'protocol'
623                }
624
625                out << select(attrs)
626        }
627
628        def show = {attrs ->
[213]629                // is object parameter set?
630                def o = attrs.object
631
632                println o.getProperties();
633                o.getProperties().each {
634                        println it
635                }
636
637                out << "!! test version of 'show' tag !!"
638        }
639
[209]640        /**
[157]641         * render table headers for all subjectFields in a template
642         * @param Map attributes
643         */
[246]644        def templateColumnHeaders = {attrs ->
[157]645                def template = attrs.remove('template')
646
647                // output table headers for template fields
[238]648                template.fields.each() {
[157]649                        out << '<div class="' + attrs.get('class') + '">' + it + '</div>'
[145]650                }
651        }
652
[157]653        /**
654         * render table input elements for all subjectFields in a template
655         * @param Map attributes
656         */
[246]657        def templateColumns = {attrs, body ->
658                def subject = attrs.remove('subject')
659                def subjectId = attrs.remove('id')
660                def template = attrs.remove('template')
661                def intFields = subject.templateIntegerFields
662                def stringFields = subject.templateStringFields
663                def floatFields = subject.templateFloatFields
664                def termFields = subject.templateTermFields
[157]665
666                // output columns for these subjectFields
[238]667                template.fields.each() {
[257]668                        def fieldValue = subject.getFieldValue(it.name)
669
[180]670                        // output div
[157]671                        out << '<div class="' + attrs.get('class') + '">'
672
[257]673                        // handle field types
[250]674                        switch (it.type.toString()) {
675                                case ['STRING', 'TEXT', 'INTEGER', 'FLOAT', 'DOUBLE']:
676                                        out << textField(
[296]677                                                name: attrs.name + '_' + it.escapedName(),
[257]678                                                value: fieldValue
[250]679                                        )
680                                        break
[157]681                                case 'STRINGLIST':
682                                        // render stringlist subjectfield
[159]683                                        if (!it.listEntries.isEmpty()) {
684                                                out << select(
[296]685                                                        name: attrs.name + '_' + it.escapedName(),
[180]686                                                        from: it.listEntries,
[257]687                                                        value: fieldValue
[246]688                                                )
[159]689                                        } else {
[213]690                                                out << '<span class="warning">no values!!</span>'
[159]691                                        }
[250]692                                        break
[257]693                                case 'DATE':
694                                        // transform value?
695                                        if (fieldValue instanceof Date) {
696                                                if (fieldValue.getHours() == 0 && fieldValue.getMinutes() == 0) {
697                                                        // transform date instance to formatted string (dd/mm/yyyy)
698                                                        fieldValue = String.format('%td/%<tm/%<tY', fieldValue)
699                                                } else {
700                                                        // transform to date + time
701                                                        fieldValue = String.format('%td/%<tm/%<tY %<tH:%<tM', fieldValue)
702                                                }
703                                        }
704
705                                        // output a date field (not the 'rel' which makes the
706                                        // javascript front-end bind the jquery-ui datepicker)
707                                        out << textField(
[296]708                                                name: attrs.name + '_' + it.escapedName(),
[257]709                                                value: fieldValue,
710                                                rel: 'date'
711                                        )
712                                        break
713                                case 'ONTOLOGYTERM':
[260]714                                        // @see http://www.bioontology.org/wiki/index.php/NCBO_Widgets#Term-selection_field_on_a_form
[262]715                                        // @see ontology-chooser.js, table-editor.js
[260]716                                        //out << it.getClass()
717                                        out << textField(
[296]718                                                name: attrs.name + '_' + it.escapedName(),
[260]719                                                value: fieldValue,
720                                                rel: 'ontology-all-name',
721                                                size: 100
722                                        )
[262]723                                        out << hiddenField(
[296]724                                                name: attrs.name + '_' + it.escapedName() + '-concept_id'
[262]725                                        )
726                                        out << hiddenField(
[296]727                                                name: attrs.name + '_' + it.escapedName() + '-ontology_id'
[262]728                                        )
729                                        out << hiddenField(
[296]730                                                name: attrs.name + '_' + it.escapedName() + '-full_id'
[262]731                                        )
[257]732                                        break
[157]733                                default:
734                                        // unsupported field type
[246]735                                        out << '<span class="warning">!' + it.type + '</span>'
[257]736                                        break
[157]737                        }
[238]738
[145]739                        out << '</div>'
740                }
741        }
[246]742
743        /**
744         * render form elements based on an entity's template
745         * @param Map attributes
746         * @param String body
747         */
748        def templateElements = {attrs ->
749                def entity = (attrs.get('entity'))
750                def template = (entity && entity instanceof TemplateEntity) ? entity.template : null
751
752                // got a template?
753                if (template) {
754                        // render template fields
755                        template.fields.each() {
[296]756                                def fieldValue = entity.getFieldValue(it.name)
757
[250]758                                switch (it.type.toString()) {
759                                        case ['STRING', 'TEXT', 'INTEGER', 'FLOAT', 'DOUBLE']:
760                                                out << textFieldElement(
761                                                        description: it.name,
[296]762                                                        name: it.escapedName(),
763                                                        value: fieldValue
[250]764                                                )
765                                                break
[246]766                                        case 'STRINGLIST':
767                                                if (!it.listEntries.isEmpty()) {
768                                                        out << selectElement(
769                                                                description: it.name,
[296]770                                                                name: it.escapedName(),
[246]771                                                                from: it.listEntries,
[296]772                                                                value: fieldValue
[246]773                                                        )
774                                                } else {
775                                                        out << '<span class="warning">no values!!</span>'
776                                                }
777                                                break
[262]778                                        case 'ONTOLOGYTERM':
779                                                // @see http://www.bioontology.org/wiki/index.php/NCBO_Widgets#Term-selection_field_on_a_form
780                                                // @see ontology-chooser.js
781                                                out << textFieldElement(
[296]782                                                        name: it.escapedName(),
[262]783                                                        value: fieldValue,
784                                                        rel: 'ontology-all-name',
785                                                        size: 100
786                                                )
787                                                out << hiddenField(
[296]788                                                        name: it.name + '-concept_id',
789                                                        value: fieldValue
[262]790                                                )
791                                                out << hiddenField(
[296]792                                                        name: it.escapedName() + '-ontology_id',
793                                                        value: fieldValue
[262]794                                                )
795                                                out << hiddenField(
[296]796                                                        name: it.escapedName() + '-full_id',
797                                                        value: fieldValue
[262]798                                                )
799                                                break
[246]800                                        case 'DATE':
801                                                out << dateElement(
802                                                        description: it.name,
[296]803                                                        name: it.escapedName(),
804                                                        value: fieldValue
[246]805                                                )
806                                                break
807                                        default:
808                                                out << "unkown field type '" + it.type + "'<br/>"
809                                                break
810                                }
811                        }
812                }
813        }
[86]814}
Note: See TracBrowser for help on using the repository browser.