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

Last change on this file since 502 was 502, checked in by roberth, 13 years ago

RELTIME fields in the wizard now show the parsed text in blue when leaving the input field.

  • Property svn:keywords set to Date Author Rev
File size: 24.8 KB
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: 502 $
17 * $Author: roberth $
18 * $Date: 2010-05-31 11:53:03 +0000 (ma, 31 mei 2010) $
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(/<[^\"]*onclick=\"/, '')
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                //      - this JavaScript variable is used by baseElement to workaround an IE
197                //        specific issue (double submit on onchange events). The hell with IE!
198                //        @see baseElement
199                out << '<script type="text/javascript">var lastRequestTime = 0;</script>'
200                out << render(template: "/wizard/common/tabs")
201                out << '<div class="content">'
202                out << body()
203                out << '</div>'
204                out << render(template: "/wizard/common/navigation")
205                out << render(template: "/wizard/common/error")
206        }
207
208        /**
209         * generate a base form element
210         * @param String inputElement name
211         * @param Map attributes
212         * @param Closure help content
213         */
214        def baseElement = {inputElement, attrs, help ->
215println ".rendering [" + inputElement + "] with name [" + attrs.get('name') + "] and value [" + ((attrs.value) ? attrs.get('value').toString() : "-") + "]"
216                // work variables
217                def internetExplorer = (request.getHeader("User-Agent") =~ /MSIE/)
218                def description = attrs.remove('description')
219                def addExampleElement = attrs.remove('addExampleElement')
220                def addExample2Element = attrs.remove('addExample2Element')
221                def helpText = help().trim()
222
223                // got an ajax onchange action?
224                def ajaxOnChange = attrs.remove('ajaxOnChange')
225                if (ajaxOnChange) {
226                        if (!attrs.onChange) attrs.onChange = ''
227
228                        // add onChange AjaxSubmit javascript
229                        if (internetExplorer) {
230                                //              - somehow IE submits these onchanges twice which messes up some parts of the wizard
231                                //                (especially the events page). In order to bypass this issue I have introduced an
232                                //                if statement utilizing the 'before' and 'after' functionality of the submitToRemote
233                                //                function. This check expects lastRequestTime to be in the global Javascript scope,
234                                //                (@see pageContent) and calculates the time difference in miliseconds between two
235                                //                onChange executions. If this is more than 100 miliseconds the request is executed,
236                                //                otherwise it will be ignored... --> 20100527 - Jeroen Wesbeek
237                                attrs.onChange += ajaxSubmitJs(
238                                        [
239                                                before: "var execute=true;try { var currentTime=new Date().getTime();execute = ((currentTime-lastRequestTime) > 100);lastRequestTime=currentTime;  } catch (e) {};if (execute) { 1",
240                                                after: "}",
241                                                functionName: ajaxOnChange,
242                                                url: attrs.get('url'),
243                                                update: attrs.get('update'),
244                                                afterSuccess: attrs.get('afterSuccess')
245                                        ],
246                                        ''
247                                )
248                        } else {
249                                // this another W3C browser that actually behaves as expected... damn you IE, DAMN YOU!
250                                attrs.onChange += ajaxSubmitJs(
251                                        [
252                                                functionName: ajaxOnChange,
253                                                url: attrs.get('url'),
254                                                update: attrs.get('update'),
255                                                afterSuccess: attrs.get('afterSuccess')
256                                        ],
257                                        ''
258                                )
259                        }
260                }
261
262                // execute inputElement call
263                def renderedElement = "$inputElement"(attrs)
264
265                // if false, then we skip this element
266                if (!renderedElement) return false
267
268                // render a form element
269                if (attrs.get('elementId')) {
270                out << '<div class="element" id="'+ attrs.remove('elementId') +'">'
271                } else {
272                        out << '<div class="element">'
273                }
274                out << ' <div class="description">'
275                out << description
276                out << ' </div>'
277                out << ' <div class="input">'
278                out << renderedElement
279                if (helpText.size() > 0) {
280                        out << '        <div class="helpIcon"></div>'
281                }
282
283                // add an disabled input box for feedback purposes
284                // @see dateElement(...)
285                if (addExampleElement) {
286                        def exampleAttrs = new LinkedHashMap()
287                        exampleAttrs.name = attrs.get('name') + 'Example'
288                        exampleAttrs.class = 'isExample'
289                        exampleAttrs.disabled = 'disabled'
290                        exampleAttrs.size = 30
291                        out << textField(exampleAttrs)
292                }
293
294                // add an disabled input box for feedback purposes
295                // @see dateElement(...)
296                if (addExample2Element) {
297                        def exampleAttrs = new LinkedHashMap()
298                        exampleAttrs.name = attrs.get('name') + 'Example2'
299                        exampleAttrs.class = 'isExample'
300                        exampleAttrs.disabled = 'disabled'
301                        exampleAttrs.size = 30
302                        out << textField(exampleAttrs)
303                }
304
305                out << ' </div>'
306
307                // add help content if it is available
308                if (helpText.size() > 0) {
309                        out << '  <div class="helpContent">'
310                        out << '    ' + helpText
311                        out << '  </div>'
312                }
313
314                out << '</div>'
315        }
316
317        /**
318         * render an ajaxButtonElement
319         * @param Map attrs
320         * @param Closure body  (help text)
321         */
322        def ajaxButtonElement = { attrs, body ->
323                baseElement.call(
324                        'ajaxButton',
325                        attrs,
326                        body
327                )
328        }
329
330        /**
331         * render a textFieldElement
332         * @param Map attrs
333         * @param Closure body  (help text)
334         */
335        def textFieldElement = {attrs, body ->
336                // set default size, or scale to max length if it is less than the default size
337                if (!attrs.get("size")) {
338                        if (attrs.get("maxlength")) {
339                                attrs.size = ((attrs.get("maxlength") as int) > defaultTextFieldSize) ? defaultTextFieldSize : attrs.get("maxlength")
340                        } else {
341                                attrs.size = defaultTextFieldSize
342                        }
343                }
344
345                // render template element
346                baseElement.call(
347                        'textField',
348                        attrs,
349                        body
350                )
351        }
352
353        /**
354         * render a textAreaElement
355         * @param Map attrs
356         * @param Closure body  (help text)
357         */
358        def textAreaElement = {attrs, body ->
359                // set default size, or scale to max length if it is less than the default size
360
361                // render template element
362                baseElement.call(
363                        'textArea',
364                        attrs,
365                        body
366                )
367        }
368
369
370        /**
371         * render a select form element
372         * @param Map attrs
373         * @param Closure body  (help text)
374         */
375        def selectElement = {attrs, body ->
376                baseElement.call(
377                        'select',
378                        attrs,
379                        body
380                )
381        }
382
383        /**
384         * render a checkBox form element
385         * @param Map attrs
386         * @param Closure body  (help text)
387         */
388        def checkBoxElement = {attrs, body ->
389                baseElement.call(
390                        'checkBox',
391                        attrs,
392                        body
393                )
394        }
395
396        /**
397         * render a set of radio form elements
398         * @param Map attrs
399         * @param Closure body  (help text)
400         */
401        def radioElement = { attrs, body ->
402                baseElement.call(
403                        'radioList',
404                        attrs,
405                        body
406                )
407        }
408
409        /**
410         * render a set of radio elements
411         * @param Map attrs
412         * @param Closure body  (help text)
413         */
414        def radioList = { attrs ->
415                def checked = true
416
417                attrs.elements.each {
418                        out << radio(
419                                name: attrs.name,
420                                value: it,
421                                checked: (attrs.value == it || (!attrs.value && checked))
422                        )
423                        out << it
424                        checked = false
425                }
426        }
427
428        /**
429         * render a dateElement
430         * NOTE: datepicker is attached through wizard.js!
431         * @param Map attrs
432         * @param Closure body  (help text)
433         */
434        def dateElement = {attrs, body ->
435                // transform value?
436                if (attrs.value instanceof Date) {
437                        // transform date instance to formatted string (dd/mm/yyyy)
438                        attrs.value = String.format('%td/%<tm/%<tY', attrs.value)
439                }
440
441                // add 'rel' field to identity the datefield using javascript
442                attrs.rel = 'date'
443
444                // set some textfield values
445                attrs.maxlength = (attrs.maxlength) ? attrs.maxlength : 10
446                attrs.addExampleElement = true
447
448                // render a normal text field
449                //out << textFieldElement(attrs,body)
450                textFieldElement.call(
451                        attrs,
452                        body
453                )
454        }
455
456        /**
457         * render a dateElement
458         * NOTE: datepicker is attached through wizard.js!
459         * @param Map attrs
460         * @param Closure body  (help text)
461         */
462        def timeElement = {attrs, body ->
463                // transform value?
464                if (attrs.value instanceof Date) {
465                        // transform date instance to formatted string (dd/mm/yyyy)
466                        attrs.value = String.format('%td/%<tm/%<tY %<tH:%<tM', attrs.value)
467                }
468
469                // add 'rel' field to identity the field using javascript
470                attrs.rel = 'datetime'
471
472                attrs.addExampleElement = true
473                attrs.addExample2Element = true
474                attrs.maxlength = 16
475
476                // render a normal text field
477                //out << textFieldElement(attrs,body)
478                textFieldElement.call(
479                        attrs,
480                        body
481                )
482        }
483
484        /**
485         * Button form element
486         * @param Map attributes
487         * @param Closure help content
488         */
489        def buttonElement = {attrs, body ->
490                // render template element
491                baseElement.call(
492                        'ajaxButton',
493                        attrs,
494                        body
495                )
496        }
497
498
499        /**
500         * Term form element
501         * @param Map attributes
502         * @param Closure help content
503         */
504        def termElement = { attrs, body ->
505                // render term element
506                baseElement.call(
507                        'termSelect',
508                        attrs,
509                        body
510                )
511        }
512
513        /**
514         * Term select element
515         * @param Map attributes
516         */
517        def termSelect = { attrs ->
518                def from = []
519
520                // got ontologies?
521                if (attrs.ontologies) {
522                        // are the ontologies a string?
523                        if (attrs.ontologies instanceof String) {
524                                attrs.ontologies.split(/\,/).each() { ncboId ->
525                                        // trim the id
526                                        ncboId.trim()
527
528                                        // fetch all terms for this ontology
529                                        def ontology = Ontology.findAllByNcboId(ncboId)
530
531                                        // does this ontology exist?
532                                        if (ontology) {
533                                                ontology.each() {
534                                                        Term.findAllByOntology(it).each() {
535                                                                // key = ncboId:concept-id
536                                                                from[ from.size() ] = it.name
537                                                        }
538                                                }
539                                        }
540                                }
541                        } else if (attrs.ontologies instanceof Set) {
542                                // are they a set instead?
543                                def ontologyList = ""
544
545                                // iterate through set
546                                attrs.ontologies.each() { ontology ->
547                                        ontologyList += ontology.ncboId + ","
548
549                                        Term.findAllByOntology(ontology).each() {
550                                                from[ from.size() ] = it.name
551                                        }
552
553                                        // strip trailing comma
554                                        attrs.ontologies = ontologyList[0..-2]
555                                }
556                        }
557
558                        // sort alphabetically
559                        from.sort()
560                       
561                        // define 'from'
562                        attrs.from = from
563
564                        // add 'rel' attribute
565                        attrs.rel = 'term'
566
567                        out << select(attrs)
568                } else {
569                        out << "<b>ontologies missing!</b>"
570                }
571        }
572
573        /**
574         * Ontology form element
575         * @param Map attributes
576         * @param Closure help content
577         */
578        def ontologyElement = { attrs, body ->
579                // @see http://www.bioontology.org/wiki/index.php/NCBO_Widgets#Term-selection_field_on_a_form
580                // @see ontology-chooser.js, table-editor.js
581                baseElement.call(
582                        'textField',
583                        [
584                            name: attrs.name,
585                                value: attrs.value,
586                                description: attrs.description,
587                                rel: 'ontology-' + ((attrs.ontology) ? attrs.ontology : 'all'),
588                                size: 25
589                        ],
590                        body
591                )
592                out << hiddenField(
593                        name: attrs.name + '-concept_id'
594                )
595                out << hiddenField(
596                        name: attrs.name + '-ontology_id'
597                )
598                out << hiddenField(
599                        name: attrs.name + '-full_id'
600                )
601        }
602
603        /**
604         * Study form element
605         * @param Map attributes
606         * @param Closure help content
607         */
608        def studyElement = { attrs, body ->
609                // render study element
610                baseElement.call(
611                        'studySelect',
612                        attrs,
613                        body
614                )
615        }
616
617        /**
618         * render a study select element
619         * @param Map attrs
620         */
621        def studySelect = { attrs ->
622                // for now, just fetch all studies
623                attrs.from = Study.findAll()
624
625                // got a name?
626                if (!attrs.name) {
627                        attrs.name = "study"
628                }
629
630                // got result?
631                if (attrs.from.size() > 0) {
632                        out << select(attrs)
633                } else {
634                        // no, return false to make sure this element
635                        // is not rendered in the template
636                        return false
637                }
638        }
639
640        /**
641         * Template form element
642         * @param Map attributes
643         * @param Closure help content
644         */
645        def templateElement = {attrs, body ->
646                // add a rel element if it does not exist
647                if (!attrs.rel) {
648                        attrs.rel = 'template'
649                }
650               
651                // render template element
652                baseElement.call(
653                        'templateSelect',
654                        attrs,
655                        body
656                )
657        }
658
659        /**
660         * render a template select element
661         * @param Map attrs
662         */
663        def templateSelect = {attrs ->
664                def entity = attrs.remove('entity')
665
666                // add the entity class name to the element
667                // do we have crypto information available?
668                if (grailsApplication.config.crypto) {
669                        // generate a Blowfish encrypted and Base64 encoded string.
670                        attrs['entity'] = Blowfish.encryptBase64(
671                                entity.toString().replaceAll(/^class /, ''),
672                                grailsApplication.config.crypto.shared.secret
673                        )
674                } else {
675                        // base64 only; this is INSECURE! As this class
676                        // is instantiated elsewehere. Possibly exploitable!
677                        attrs['entity'] = entity.toString().replaceAll(/^class /, '').bytes.encodeBase64()
678                }
679
680                // fetch templates
681                if (attrs.remove('addDummy')) {
682                        attrs.from = ['']
683                        if (entity && entity instanceof Class) {
684                                Template.findAllByEntity(entity).each() {
685                                        attrs.from[attrs.from.size()] = it
686                                }
687                        }
688                } else {
689                        attrs.from = (entity) ? Template.findAllByEntity(entity) : Template.findAll()
690                }
691
692                // got a name?
693                if (!attrs.name) {
694                        attrs.name = 'template'
695                }
696
697                // got result?
698                if (attrs.from.size() > 0) {
699                        // transform all values into strings
700                        def from = []
701                        attrs.from.each { from[ from.size() ] = it.toString() }
702
703                        // sort alphabetically
704                        from.sort()
705
706                        // set attributes
707                        attrs.from = from
708                        attrs.value = (attrs.value) ? attrs.value.toString() : ''
709
710                        // output select element
711                        out << select(attrs)
712                } else {
713                        // no, return false to make sure this element
714                        // is not rendered in the template
715                        return false
716                }
717        }
718
719        /**
720         * Protocol form element
721         * @param Map attributes
722         * @param Closure help content
723         */
724        def protocolElement = {attrs, body ->
725                // render protocol element
726                baseElement.call(
727                        'protocolSelect',
728                        attrs,
729                        body
730                )
731        }
732
733        /**
734         * render a protocol select element
735         * @param Map attrs
736         */
737        def protocolSelect = {attrs ->
738                // fetch all protocold
739                attrs.from = Protocol.findAll() // for now, all protocols
740
741                // got a name?
742                if (!attrs.name) {
743                        attrs.name = 'protocol'
744                }
745
746                out << select(attrs)
747        }
748
749        def show = {attrs ->
750                // is object parameter set?
751                def o = attrs.object
752
753                println o.getProperties();
754                o.getProperties().each {
755                        println it
756                }
757
758                out << "!! test version of 'show' tag !!"
759        }
760
761        /**
762         * render table headers for all subjectFields in a template
763         * @param Map attributes
764         */
765        def templateColumnHeaders = { attrs ->
766                def entity              = (attrs.get('entity'))
767                def template    = (entity && entity instanceof TemplateEntity) ? entity.template : null
768
769                // got a template?
770                if (template) {
771                        // render template fields
772                        entity.giveFields().each() {
773                                def ucName              = it.name[0].toUpperCase() + it.name.substring(1)
774
775                                out << '<div class="' + attrs.get('class') + '">' + ucName + (it.unit ? " (${it.unit})" : '')
776                                if (it.comment) {
777                                        out << '<div class="helpIcon"></div>'
778                                        out << '<div class="helpContent">' + it.comment + '</div>'
779                                }
780                                out << '</div>'
781                        }
782                }
783        }
784
785        def templateColumns = { attrs ->
786                // render template fields as columns
787                attrs.renderType = 'column'
788                out << renderTemplateFields(attrs)
789        }
790
791        def templateElements = { attrs ->
792                // render template fields as form elements
793                attrs.renderType = 'element'
794                out << renderTemplateFields(attrs)
795        }
796
797        /**
798         * render form elements based on an entity's template
799         * @param Map attributes
800         * @param String body
801         */
802        def renderTemplateFields = { attrs ->
803                def renderType  = attrs.remove('renderType')
804                def entity              = (attrs.get('entity'))
805                def prependName = (attrs.get('name')) ? attrs.remove('name')+'_' : ''
806                def template    = (entity && entity instanceof TemplateEntity) ? entity.template : null
807                def inputElement= null
808
809                // got a template?
810                if (template) {
811                        // render template fields
812                        entity.giveFields().each() {
813                                def fieldValue  = entity.getFieldValue(it.name)
814                                def helpText    = (it.comment && renderType == 'element') ? it.comment : ''
815                                def ucName              = it.name[0].toUpperCase() + it.name.substring(1)
816
817                                // output column opening element?
818                                if (renderType == 'column') {
819                                        out << '<div class="' + attrs.get('class') + '">'
820                                }
821
822                                switch (it.type.toString()) {
823                                        case ['STRING', 'INTEGER', 'FLOAT', 'DOUBLE']:
824                                                inputElement = (renderType == 'element') ? 'textFieldElement' : 'textField'
825                                                out << "$inputElement"(
826                                                        description: ucName,
827                                                        name: prependName + it.escapedName(),
828                                                        value: fieldValue
829                                                ){helpText}
830                                                break
831                                        case 'TEXT':
832                                                inputElement = (renderType == 'element') ? 'textAreaElement' : 'textField'
833                                                out << "$inputElement"(
834                                                        description: ucName,
835                                                        name: prependName + it.escapedName(),
836                                                        value: fieldValue
837                                                ){helpText}
838                                                break
839                                        case 'STRINGLIST':
840                                                inputElement = (renderType == 'element') ? 'selectElement' : 'select'
841                                                if (!it.listEntries.isEmpty()) {
842                                                        out << "$inputElement"(
843                                                                description: ucName,
844                                                                name: prependName + it.escapedName(),
845                                                                from: it.listEntries,
846                                                                value: fieldValue
847                                                        ){helpText}
848                                                } else {
849                                                        out << '<span class="warning">no values!!</span>'
850                                                }
851                                                break
852                                        case 'ONTOLOGYTERM':
853                                                // @see http://www.bioontology.org/wiki/index.php/NCBO_Widgets#Term-selection_field_on_a_form
854                                                // @see ontology-chooser.js
855                                                inputElement = (renderType == 'element') ? 'termElement' : 'termSelect'
856
857                                                if (it.ontologies) {
858                                                        out << "$inputElement"(
859                                                                description     : ucName,
860                                                                name            : prependName + it.escapedName(),
861                                                                value           : fieldValue.toString(),
862                                                                ontologies      : it.ontologies
863                                                        ){helpText}
864                                                } else {
865                                                        out << "$inputElement"(
866                                                                description     : ucName,
867                                                                name            : prependName + it.escapedName(),
868                                                                value           : fieldValue.toString()
869                                                        ){helpText}
870                                                }
871                                                break
872                                        case 'ONTOLOGYTERM-old':
873                                                // @see http://www.bioontology.org/wiki/index.php/NCBO_Widgets#Term-selection_field_on_a_form
874                                                // @see ontology-chooser.js
875                                                inputElement = (renderType == 'element') ? 'textFieldElement' : 'textField'
876                                                out << "$inputElement"(
877                                                        name: prependName + it.escapedName(),
878                                                        value: fieldValue,
879                                                        rel: 'ontology-all',
880                                                        size: 100
881                                                )
882                                                out << hiddenField(
883                                                        name: prependName + it.name + '-concept_id',
884                                                        value: fieldValue
885                                                )
886                                                out << hiddenField(
887                                                        name: prependName + it.escapedName() + '-ontology_id',
888                                                        value: fieldValue
889                                                )
890                                                out << hiddenField(
891                                                        name: prependName + it.escapedName() + '-full_id',
892                                                        value: fieldValue
893                                                )
894                                                break
895                                        case 'DATE':
896                                                inputElement = (renderType == 'element') ? 'dateElement' : 'textField'
897
898                                                // transform value?
899                                                if (fieldValue instanceof Date) {
900                                                        if (fieldValue.getHours() == 0 && fieldValue.getMinutes() == 0) {
901                                                                // transform date instance to formatted string (dd/mm/yyyy)
902                                                                fieldValue = String.format('%td/%<tm/%<tY', fieldValue)
903                                                        } else {
904                                                                // transform to date + time
905                                                                fieldValue = String.format('%td/%<tm/%<tY %<tH:%<tM', fieldValue)
906                                                        }
907                                                }
908
909                                                // render element
910                                                out << "$inputElement"(
911                                                        description: ucName,
912                                                        name: prependName + it.escapedName(),
913                                                        value: fieldValue,
914                                                        rel: 'date'
915                                                ){helpText}
916                                                break
917                                        case ['RELTIME']:
918                                                inputElement = (renderType == 'element') ? 'textFieldElement' : 'textField'
919                                                out << "$inputElement"(
920                                                        description: ucName,
921                                                        name: prependName + it.escapedName(),
922                                                        value: new RelTime( fieldValue ).toString(),
923                                                        addExampleElement: true,
924                                                        onBlur: 'showExampleReltime(this)'
925                                                ){helpText}
926                                                break
927                                        default:
928                                                // unsupported field type
929                                                out << '<span class="warning">!' + it.type + '</span>'
930                                                break
931                                }
932
933                                // output column closing element?
934                                if (renderType == 'column') {
935                                        out << '</div>'
936                                }
937                        }
938                }
939        }
940}
Note: See TracBrowser for help on using the repository browser.