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

Last change on this file since 455 was 455, checked in by keesvb, 11 years ago

Reverting Subject optimization as it breaks the study create wizard on adding Subjects, added help texts to Bootstrap and icons to study create wizard, added new text to home, added help texts to study create wizard pages

  • Property svn:keywords set to Date Author Rev
File size: 22.3 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: 455 $
17 * $Author: keesvb $
18 * $Date: 2010-05-24 21:48:40 +0000 (ma, 24 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(/<[^\"]*\"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 + (it.unit ? " (${it.unit})" : '')
730                                if (it.comment) {
731                                        out << '<div class="helpIcon"></div>'
732                                        out << '<div class="helpContent">' + it.comment + '</div>'
733                                }
734                                out << '</div>'
735                        }
736                }
737        }
738
739        def templateColumns = { attrs ->
740                // render template fields as columns
741                attrs.renderType = 'column'
742                out << renderTemplateFields(attrs)
743        }
744
745        def templateElements = { attrs ->
746                // render template fields as form elements
747                attrs.renderType = 'element'
748                out << renderTemplateFields(attrs)
749        }
750
751        /**
752         * render form elements based on an entity's template
753         * @param Map attributes
754         * @param String body
755         */
756        def renderTemplateFields = { attrs ->
757                def renderType  = attrs.remove('renderType')
758                def entity              = (attrs.get('entity'))
759                def prependName = (attrs.get('name')) ? attrs.remove('name')+'_' : ''
760                def template    = (entity && entity instanceof TemplateEntity) ? entity.template : null
761                def inputElement= null
762
763                String helpText
764
765                // got a template?
766                if (template) {
767                        // render template fields
768                        entity.giveFields().each() {
769                                def fieldValue = entity.getFieldValue(it.name)
770                                helpText = (it.comment && renderType == 'element') ? it.comment : ''
771
772                                // output column opening element?
773                                if (renderType == 'column') {
774                                        out << '<div class="' + attrs.get('class') + '">'
775                                }
776
777                                switch (it.type.toString()) {
778                                        case ['STRING', 'TEXT', 'INTEGER', 'FLOAT', 'DOUBLE']:
779                                                inputElement = (renderType == 'element') ? 'textFieldElement' : 'textField'
780                                                out << "$inputElement"(
781                                                        description: it.name,
782                                                        name: prependName + it.escapedName(),
783                                                        value: fieldValue
784                                                ){helpText}
785                                                break
786                                        case 'STRINGLIST':
787                                                inputElement = (renderType == 'element') ? 'selectElement' : 'select'
788                                                if (!it.listEntries.isEmpty()) {
789                                                        out << "$inputElement"(
790                                                                description: it.name,
791                                                                name: prependName + it.escapedName(),
792                                                                from: it.listEntries,
793                                                                value: fieldValue
794                                                        ){helpText}
795                                                } else {
796                                                        out << '<span class="warning">no values!!</span>'
797                                                }
798                                                break
799                                        case 'ONTOLOGYTERM':
800                                                // @see http://www.bioontology.org/wiki/index.php/NCBO_Widgets#Term-selection_field_on_a_form
801                                                // @see ontology-chooser.js
802                                                inputElement = (renderType == 'element') ? 'termElement' : 'termSelect'
803
804                                                if (it.ontologies) {
805                                                        out << "$inputElement"(
806                                                                description     : it.name,
807                                                                name            : prependName + it.escapedName(),
808                                                                value           : fieldValue.toString(),
809                                                                ontologies      : it.ontologies
810                                                        ){helpText}
811                                                } else {
812                                                        out << "$inputElement"(
813                                                                description     : it.name,
814                                                                name            : prependName + it.escapedName(),
815                                                                value           : fieldValue.toString()
816                                                        ){helpText}
817                                                }
818                                                break
819                                        case 'ONTOLOGYTERM-old':
820                                                // @see http://www.bioontology.org/wiki/index.php/NCBO_Widgets#Term-selection_field_on_a_form
821                                                // @see ontology-chooser.js
822                                                inputElement = (renderType == 'element') ? 'textFieldElement' : 'textField'
823                                                out << "$inputElement"(
824                                                        name: prependName + it.escapedName(),
825                                                        value: fieldValue,
826                                                        rel: 'ontology-all',
827                                                        size: 100
828                                                )
829                                                out << hiddenField(
830                                                        name: prependName + it.name + '-concept_id',
831                                                        value: fieldValue
832                                                )
833                                                out << hiddenField(
834                                                        name: prependName + it.escapedName() + '-ontology_id',
835                                                        value: fieldValue
836                                                )
837                                                out << hiddenField(
838                                                        name: prependName + it.escapedName() + '-full_id',
839                                                        value: fieldValue
840                                                )
841                                                break
842                                        case 'DATE':
843                                                inputElement = (renderType == 'element') ? 'dateElement' : 'textField'
844
845                                                // transform value?
846                                                if (fieldValue instanceof Date) {
847                                                        if (fieldValue.getHours() == 0 && fieldValue.getMinutes() == 0) {
848                                                                // transform date instance to formatted string (dd/mm/yyyy)
849                                                                fieldValue = String.format('%td/%<tm/%<tY', fieldValue)
850                                                        } else {
851                                                                // transform to date + time
852                                                                fieldValue = String.format('%td/%<tm/%<tY %<tH:%<tM', fieldValue)
853                                                        }
854                                                }
855
856                                                // render element
857                                                out << "$inputElement"(
858                                                        description: it.name,
859                                                        name: prependName + it.escapedName(),
860                                                        value: fieldValue,
861                                                        rel: 'date'
862                                                ){helpText}
863                                                break
864                                        default:
865                                                // unsupported field type
866                                                out << '<span class="warning">!' + it.type + '</span>'
867                                                break
868                                }
869
870                                // Render comment, if any
871                                //if (it.comment) {
872                                //      out << {"$helpText"}
873                                //}
874
875                                // output column closing element?
876                                if (renderType == 'column') {
877                                        out << '</div>'
878                                }
879                        }
880                }
881        }
882}
Note: See TracBrowser for help on using the repository browser.