root/trunk/grails-app/taglib/dbnp/studycapturing/WizardTagLib.groovy @ 445

Revision 445, 22.0 KB (checked in by duh, 4 years ago)

- bugfix: ontology selects not displaying proper value

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