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

Last change on this file since 1456 was 1456, checked in by business@…, 9 years ago

moved gdt package to org.dbnp, moved tests for RelTime?, TemplateEntity?, Template etc. to gdt plugin

  • Property svn:keywords set to Rev Author Date
File size: 33.3 KB
Line 
1package dbnp.studycapturing
2
3import dbnp.authentication.SecUser
4import cr.co.arquetipos.crypto.Blowfish
5import nl.grails.plugins.ajaxflow.AjaxflowTagLib
6
7/**
8 * Wizard tag library
9 *
10 * @author Jeroen Wesbeek
11 * @since 20100113
12 * @package wizard
13 *
14 * Revision information:
15 * $Rev: 1456 $
16 * $Author: business@keesvanbochove.nl $
17 * $Date: 2011-01-31 12:27:30 +0000 (ma, 31 jan 2011) $
18 */
19class WizardTagLib extends AjaxflowTagLib {
20        def AuthenticationService
21       
22        // define the tag namespace (e.g.: <wizard:action ... />
23        static namespace = "wizard"
24
25        // define default text field width
26        static defaultTextFieldSize = 25;
27
28        /**
29         * generate a base form element
30         * @param String inputElement name
31         * @param Map attributes
32         * @param Closure help content
33         */
34        def baseElement = { inputElement, attrs, help ->
35                log.info ".rendering [" + inputElement + "] with name [" + attrs.get('name') + "] and value [" + ((attrs.value) ? attrs.get('value').toString() : "-") + "]"
36
37                // work variables
38                def description = attrs.remove('description')
39                def addExampleElement = attrs.remove('addExampleElement')
40                def addExample2Element = attrs.remove('addExample2Element')
41                def helpText = help().trim()
42
43                // execute inputElement call
44                def renderedElement = "$inputElement"(attrs)
45
46                // if false, then we skip this element
47                if (!renderedElement) return false
48
49                // render a form element
50                out << '<div class="element'+ ((attrs.get('required')) ? ' required' : '') +'"'+ ((attrs.get('elementId')) ? 'id="'+attrs.remove('elementId')+'"': '') + '>'
51                out << ' <div class="description">'
52                out << ((description) ? description.replaceAll(/[a-z][A-Z][a-z]/) { it[0] + ' ' + it[1..2] }.replaceAll(/\w+/) { it[0].toUpperCase() + ((it.size() > 1) ? it[1..-1] : '') } : '')
53                out << ' </div>'
54                out << ' <div class="input">'
55                out << renderedElement
56                out << ((helpText.size() > 0) ? '       <div class="helpIcon"></div>' : '')
57
58                // add an disabled input box for feedback purposes
59                // @see dateElement(...)
60                if (addExampleElement) {
61                        def exampleAttrs = new LinkedHashMap()
62                        exampleAttrs.name = attrs.get('name') + 'Example'
63                        exampleAttrs.class = 'isExample'
64                        exampleAttrs.disabled = 'disabled'
65                        exampleAttrs.size = 30
66                        out << textField(exampleAttrs)
67                }
68
69                // add an disabled input box for feedback purposes
70                // @see dateElement(...)
71                if (addExample2Element) {
72                        def exampleAttrs = new LinkedHashMap()
73                        exampleAttrs.name = attrs.get('name') + 'Example2'
74                        exampleAttrs.class = 'isExample'
75                        exampleAttrs.disabled = 'disabled'
76                        exampleAttrs.size = 30
77                        out << textField(exampleAttrs)
78                }
79
80                out << ' </div>'
81
82                // add help content if it is available
83                if (helpText.size() > 0) {
84                        out << '  <div class="helpContent">'
85                        out << '    ' + helpText
86                        out << '  </div>'
87                }
88
89                out << '</div>'
90        }
91
92        /**
93         * bind an ajax submit to an onChange event
94         * @param attrs
95         * @return attrs
96         */
97        private getAjaxOnChange = { attrs ->
98                // work variables
99                def internetExplorer = (request.getHeader("User-Agent") =~ /MSIE/)
100                def ajaxOnChange = attrs.remove('ajaxOnChange')
101
102                // is ajaxOnChange defined
103                if ( ajaxOnChange ) {
104                        if (!attrs.onChange) attrs.onChange = ''
105
106                        // add onChange AjaxSubmit javascript
107                        if (internetExplorer) {
108                                //              - somehow IE submits these onchanges twice which messes up some parts of the wizard
109                                //                (especially the events page). In order to bypass this issue I have introduced an
110                                //                if statement utilizing the 'before' and 'after' functionality of the submitToRemote
111                                //                function. This check expects lastRequestTime to be in the global Javascript scope,
112                                //                (@see pageContent) and calculates the time difference in miliseconds between two
113                                //                onChange executions. If this is more than 100 miliseconds the request is executed,
114                                //                otherwise it will be ignored... --> 20100527 - Jeroen Wesbeek
115                                attrs.onChange += ajaxSubmitJs(
116                                        [
117                                                before: "var execute=true;try { var currentTime=new Date().getTime();execute = ((currentTime-lastRequestTime) > 100);lastRequestTime=currentTime;  } catch (e) {};if (execute) { 1",
118                                                after: "}",
119                                                functionName: ajaxOnChange,
120                                                url: attrs.get('url'),
121                                                update: attrs.get('update'),
122                                                afterSuccess: attrs.get('afterSuccess')
123                                        ],
124                                        ''
125                                )
126                        } else {
127                                // this another W3C browser that actually behaves as expected... damn you IE, DAMN YOU!
128                                attrs.onChange += ajaxSubmitJs(
129                                        [
130                                                functionName: ajaxOnChange,
131                                                url: attrs.get('url'),
132                                                update: attrs.get('update'),
133                                                afterSuccess: attrs.get('afterSuccess')
134                                        ],
135                                        ''
136                                )
137                        }
138                }
139
140                return attrs
141        }
142
143        /**
144         * render an ajaxButtonElement
145         * @param Map attrs
146         * @param Closure body  (help text)
147         */
148        def ajaxButtonElement = { attrs, body ->
149                baseElement.call(
150                        'ajaxButton',
151                        attrs,
152                        body
153                )
154        }
155
156        /**
157         * render a textFieldElement
158         * @param Map attrs
159         * @param Closure body  (help text)
160         */
161        def textFieldElement = { attrs, body ->
162                // set default size, or scale to max length if it is less than the default size
163                if (!attrs.get("size")) {
164                        if (attrs.get("maxlength")) {
165                                attrs.size = ((attrs.get("maxlength") as int) > defaultTextFieldSize) ? defaultTextFieldSize : attrs.get("maxlength")
166                        } else {
167                                attrs.size = defaultTextFieldSize
168                        }
169                }
170
171                // render template element
172                baseElement.call(
173                        'textField',
174                        attrs,
175                        body
176                )
177        }
178
179        /**
180         * render a textAreaElement
181         * @param Map attrs
182         * @param Closure body  (help text)
183         */
184        def textAreaElement = { attrs, body ->
185                // set default size, or scale to max length if it is less than the default size
186
187                // render template element
188                baseElement.call(
189                        'textArea',
190                        attrs,
191                        body
192                )
193        }
194
195
196        /**
197         * render a select form element
198         * @param Map attrs
199         * @param Closure body  (help text)
200         */
201        def selectElement = { attrs, body ->
202                baseElement.call(
203                        'select',
204                        attrs,
205                        body
206                )
207        }
208
209        /**
210         * render a checkBox form element
211         * @param Map attrs
212         * @param Closure body  (help text)
213         */
214        def checkBoxElement = { attrs, body ->
215                baseElement.call(
216                        'checkBox',
217                        attrs,
218                        body
219                )
220        }
221
222        /**
223         * render a set of radio form elements
224         * @param Map attrs
225         * @param Closure body  (help text)
226         */
227        def radioElement = { attrs, body ->
228                baseElement.call(
229                        'radioList',
230                        attrs,
231                        body
232                )
233        }
234
235        /**
236         * render a set of radio elements
237         * @param Map attrs
238         * @param Closure body  (help text)
239         */
240        def radioList = { attrs ->
241                def checked = true
242
243                attrs.elements.each {
244                        out << radio(
245                                name: attrs.name,
246                                value: it,
247                                checked: (attrs.value == it || (!attrs.value && checked))
248                        )
249                        out << it
250                        checked = false
251                }
252        }
253
254        /**
255         * render a dateElement
256         * NOTE: datepicker is attached through wizard.js!
257         * @param Map attrs
258         * @param Closure body  (help text)
259         */
260        def dateElement = { attrs, body ->
261                // transform value?
262                if (attrs.value instanceof Date) {
263                        // transform date instance to formatted string (dd/mm/yyyy)
264                        attrs.value = String.format('%td/%<tm/%<tY', attrs.value)
265                }
266
267                // add 'rel' field to identity the datefield using javascript
268                attrs.rel = 'date'
269
270                // set some textfield values
271                attrs.maxlength = (attrs.maxlength) ? attrs.maxlength : 10
272                attrs.addExampleElement = true
273
274                // render a normal text field
275                //out << textFieldElement(attrs,body)
276                textFieldElement.call(
277                        attrs,
278                        body
279                )
280        }
281
282        /**
283         * render a dateElement
284         * NOTE: datepicker is attached through wizard.js!
285         * @param Map attrs
286         * @param Closure body  (help text)
287         */
288        def timeElement = { attrs, body ->
289                // transform value?
290                if (attrs.value instanceof Date) {
291                        // transform date instance to formatted string (dd/mm/yyyy)
292                        attrs.value = String.format('%td/%<tm/%<tY %<tH:%<tM', attrs.value)
293                }
294
295                // add 'rel' field to identity the field using javascript
296                attrs.rel = 'datetime'
297
298                attrs.addExampleElement = true
299                attrs.addExample2Element = true
300                attrs.maxlength = 16
301
302                // render a normal text field
303                //out << textFieldElement(attrs,body)
304                textFieldElement.call(
305                        attrs,
306                        body
307                )
308        }
309
310        /**
311         * Button form element
312         * @param Map attributes
313         * @param Closure help content
314         */
315        def buttonElement = { attrs, body ->
316                // render template element
317                baseElement.call(
318                        'ajaxButton',
319                        attrs,
320                        body
321                )
322        }
323
324
325        /**
326         * Term form element
327         * @param Map attributes
328         * @param Closure help content
329         */
330        def termElement = { attrs, body ->
331                // render term element
332                baseElement.call(
333                        'termSelect',
334                        attrs,
335                        body
336                )
337        }
338
339        /**
340         * Term select element
341         * @param Map attributes
342         */
343        // TODO: change termSelect to use Term accessions instead of preferred names, to make it possible to track back
344        // terms from multiple ontologies with possibly the same preferred name
345        def termSelect = { attrs ->
346                def from = []
347
348                // got ontologies?
349                if (attrs.ontologies) {
350                        // are the ontologies a string?
351                        if (attrs.ontologies instanceof String) {
352                                attrs.ontologies.split(/\,/).each() { ncboId ->
353                                        // trim the id
354                                        ncboId.trim()
355
356                                        // fetch all terms for this ontology
357                                        def ontology = Ontology.findAllByNcboId(ncboId)
358
359                                        // does this ontology exist?
360                                        if (ontology) {
361                                                ontology.each() {
362                                                        Term.findAllByOntology(it).each() {
363                                                                // key = ncboId:concept-id
364                                                                from[ from.size() ] = it.name
365                                                        }
366                                                }
367                                        }
368                                }
369                        } else if (attrs.ontologies instanceof Set) {
370                                // are they a set instead?
371                                def ontologyList = ""
372
373                                // iterate through set
374                                attrs.ontologies.each() { ontology ->
375                                        if (ontology) {
376                                                ontologyList += ontology.ncboId + ","
377
378                                                Term.findAllByOntology(ontology).each() {
379                                                        from[ from.size() ] = it.name
380                                                }
381
382                                                // strip trailing comma
383                                                attrs.ontologies = ontologyList[0..-2]
384                                        }
385                                }
386                        }
387
388                        // sort alphabetically
389                        from.sort()
390
391                        // add a dummy field?
392                        if (attrs.remove('addDummy')) {
393                                from.add(0,'')
394                        }
395
396                        // define 'from'
397                        attrs.from = from
398
399                        // add 'rel' attribute
400                        attrs.rel = 'term'
401
402                        // got an ajaxOnChange defined?
403                        attrs = getAjaxOnChange.call(
404                                attrs
405                        )
406
407                        out << select(attrs)
408                } else {
409                        out << "<b>ontologies missing!</b>"
410                }
411        }
412
413        /**
414         * Ontology form element
415         * @param Map attributes
416         * @param Closure help content
417         */
418        def ontologyElement = { attrs, body ->
419                // @see http://www.bioontology.org/wiki/index.php/NCBO_Widgets#Term-selection_field_on_a_form
420                // @see ontology-chooser.js, table-editor.js
421                baseElement.call(
422                        'textField',
423                        [
424                            name: attrs.name,
425                                value: attrs.value,
426                                description: attrs.description,
427                                rel: 'ontology-' + ((attrs.ontology) ? attrs.ontology : 'all'),
428                                size: 25
429                        ],
430                        body
431                )
432                out << hiddenField(
433                        name: attrs.name + '-concept_id'
434                )
435                out << hiddenField(
436                        name: attrs.name + '-ontology_id'
437                )
438                out << hiddenField(
439                        name: attrs.name + '-full_id'
440                )
441        }
442
443        /**
444         * Study form element
445         * @param Map attributes
446         * @param Closure help content
447         */
448        def studyElement = { attrs, body ->
449                // render study element
450                baseElement.call(
451                        'studySelect',
452                        attrs,
453                        body
454                )
455        }
456
457        /**
458         * render a study select element
459         * @param Map attrs
460         */
461        def studySelect = { attrs ->
462                // Find all studies the user has access to (max 100)
463                attrs.from = Study.giveWritableStudies(AuthenticationService.getLoggedInUser(), 100);
464
465                // got a name?
466                if (!attrs.name) {
467                        attrs.name = "study"
468                }
469
470                // got result?
471                if (attrs.from.size() > 0) {
472                        out << select(attrs)
473                } else {
474                        // no, return false to make sure this element
475                        // is not rendered in the template
476                        return false
477                }
478        }
479
480        /**
481         * Template form element
482         * @param Map attributes
483         * @param Closure help content
484         */
485        def templateElement = { attrs, body ->
486                // render template element
487                baseElement.call(
488                        'templateSelect',
489                        attrs,
490                        body
491                )
492        }
493
494        /**
495         * render a template select element
496         * @param Map attrs
497         */
498        def templateSelect = { attrs ->
499                def entity = attrs.remove('entity')
500
501                // add the entity class name to the element
502                // do we have crypto information available?
503                if (grailsApplication.config.crypto) {
504                        // generate a Blowfish encrypted and Base64 encoded string.
505                        attrs['entity'] = URLEncoder.encode(
506                                Blowfish.encryptBase64(
507                                        entity.toString().replaceAll(/^class /, ''),
508                                        grailsApplication.config.crypto.shared.secret
509                                )
510                        )
511                } else {
512                        // base64 only; this is INSECURE! As this class
513                        // is instantiated elsewehere. Possibly exploitable!
514                        attrs['entity'] = URLEncoder.encode(entity.toString().replaceAll(/^class /, '').bytes.encodeBase64())
515                }
516               
517                // fetch templates
518                attrs.from = (entity) ? Template.findAllByEntity(entity) : Template.findAll()
519
520                // got a name?
521                if (!attrs.name) {
522                        attrs.name = 'template'
523                }
524
525                // add a rel element if it does not exist
526                if (!attrs.rel) {
527                        attrs.rel = 'template'
528                }
529
530                // got an ajaxOnChange defined?
531                attrs = getAjaxOnChange.call(
532                        attrs
533                )
534
535                // got result?
536                if (attrs.from.size() > 0 || attrs.get('addDummy')) {
537                        // transform all values into strings
538                        def from = []
539                        attrs.from.each { from[ from.size() ] = it.toString() }
540
541                        // sort alphabetically
542                        from.sort()
543
544                        // add a dummy field?
545                        if (attrs.remove('addDummy')) {
546                                from.add(0,'')
547                        }
548
549                        // set attributes
550                        attrs.from = from
551                        attrs.value = (attrs.value) ? attrs.value.toString() : ''
552
553                        // output select element
554                        out << select(attrs)
555                } else {
556                        // no, return false to make sure this element
557                        // is not rendered in the template
558                        return false
559                }
560        }
561
562
563        /**
564         * File form element
565         * @param Map attributes
566         * @param Closure help content
567         */
568        def fileFieldElement = { attrs, body ->
569                // render term element
570                baseElement.call(
571                        'fileField',
572                        attrs,
573                        body
574                )
575        }
576
577        /**
578         * file field.
579         * @param attributes
580         */
581        def fileField = { attrs ->
582                /*
583                out << '<input type="file" name="' + attrs.name + '"/>'
584                if( attrs.value ) {
585                        out << '<a href="' + resource(dir: '') + '/file/get/' + attrs.value + '" class="isExample">Now contains: ' + attrs.value + '</a>'
586                }
587                */
588
589                out << '<div id="upload_button_' + attrs.name + '" class="upload_button">Upload</div>';
590                out << '<input type="hidden" name="' + attrs.name + '" id="' + attrs.name + '" value="' + attrs.value + '">';
591                out << '<div id="' + attrs.name + 'Example" class="upload_info"></div>';
592                out << '<a id="' + attrs.name + 'Delete" class="upload_del" href="#" onClick="if( confirm( \'Are you sure to delete this file?\' ) ) { deleteFile( \'' + attrs.name + '\' ); } return false;"><img src="' + resource( dir: 'images/icons', file: 'delete.png', plugin: 'famfamfam' ) + '"></a>';
593                out << '<script type="text/javascript">';
594                out << '  $(document).ready( function() { ';
595                out << '    var filename = "' + attrs.value + '";';
596                out << '    fileUploadField( "' + attrs.name + '" );';
597                out << '    if( filename != "" ) {';
598                out << '      $("#' + attrs.name + 'Delete").show();';
599                out << '      $("#' + attrs.name + 'Example").html("Current file: " + createFileHTML( filename ) )';
600                out << '    }';
601                out << '  } );';
602                out << "</script>\n";
603        }
604
605        /**
606         * Protocol form element
607         * @param Map attributes
608         * @param Closure help content
609         */
610        def protocolElement = { attrs, body ->
611                // render protocol element
612                baseElement.call(
613                        'protocolSelect',
614                        attrs,
615                        body
616                )
617        }
618
619        /**
620         * render a protocol select element
621         * @param Map attrs
622         */
623        def protocolSelect = { attrs ->
624                // fetch all protocold
625                attrs.from = Protocol.findAll() // for now, all protocols
626
627                // got a name?
628                if (!attrs.name) {
629                        attrs.name = 'protocol'
630                }
631
632                out << select(attrs)
633        }
634
635        def show = { attrs ->
636                // is object parameter set?
637                def o = attrs.object
638
639                println o.getProperties();
640                o.getProperties().each {
641                        println it
642                }
643
644                out << "!! test version of 'show' tag !!"
645        }
646
647        /**
648         * render table headers for all subjectFields in a template
649         * @param Map attributes
650         */
651        def templateColumnHeaders = { attrs ->
652                def entity              = (attrs.get('entity'))
653                def template    = (entity && entity instanceof TemplateEntity) ? entity.template : null
654                def columnWidths= (attrs.get('columnWidths')) ? attrs.remove('columnWidths') : []
655
656                // got a template?
657                if (template) {
658                        // render template fields
659                        entity.giveFields().each() {
660                                // Format the column name by:
661                                // - separating combined names (SampleName --> Sample Name)
662                                // - capitalizing every seperate word
663                                def ucName = it.name.replaceAll(/[a-z][A-Z][a-z]/) {
664                                        it[0] + ' ' + it[1..2]
665                                }.replaceAll(/\w+/) {
666                                        it[0].toUpperCase() + ((it.size() > 1) ? it[1..-1] : '')
667                                }
668
669                                // strip spaces
670                                def ucNameSpaceless = ucName.replaceAll(/ /) { '' }
671
672                                // do we have to use a specific width for this column?
673                                if (columnWidths[ucName]) {
674                                        out << '<div class="' + attrs.get('class') + '" style="width:' + columnWidths[ucNameSpaceless] + 'px;" rel="resized">' + ucName + (it.unit ? " (${it.unit})" : '')
675                                } else {
676                                        out << '<div class="' + attrs.get('class') + '">' + ucName + (it.unit ? " (${it.unit})" : '')
677                                }
678                                if (it.comment) {
679                                        out << '<div class="helpIcon"></div>'
680                                        out << '<div class="helpContent">' + it.comment + '</div>'
681                                }
682                                out << '</div>'
683                        }
684                }
685        }
686
687        def templateColumns = { attrs ->
688                // render template fields as columns
689                attrs.renderType = 'column'
690                out << renderTemplateFields(attrs)
691        }
692
693        def templateElements = { attrs ->
694                // render template fields as form elements
695                attrs.renderType = 'element'
696                out << renderTemplateFields(attrs)
697        }
698
699        /**
700         * render form elements based on an entity's template
701         * @param Map attributes
702         * @param String body
703         */
704        def renderTemplateFields = { attrs ->
705                def renderType  = attrs.remove('renderType')
706                def entity              = (attrs.get('entity'))
707                def prependName = (attrs.get('name')) ? attrs.remove('name')+'_' : ''
708                def template    = (entity && entity instanceof TemplateEntity) ? entity.template : null
709                def inputElement= null
710                def addDummy    = (attrs.get('addDummy')) ? true : false
711
712                // got a template?
713                if (template) {
714                        // render template fields
715                        entity.giveFields().each() {
716                                def fieldValue  = entity.getFieldValue(it.name)
717                                def helpText    = (it.comment && renderType == 'element') ? it.comment : ''
718                                def ucName              = it.name[0].toUpperCase() + it.name.substring(1)
719
720                                // output column opening element?
721                                if (renderType == 'column') {
722                                        out << '<div class="' + attrs.get('class') + '">'
723                                }
724
725                                switch (it.type.toString()) {
726                                        case ['STRING', 'DOUBLE', 'LONG']:
727                                                inputElement = (renderType == 'element') ? 'textFieldElement' : 'textField'
728                                                out << "$inputElement"(
729                                                        description     : ucName,
730                                                        name            : prependName + it.escapedName(),
731                                                        value           : fieldValue,
732                                                        required        : it.isRequired()
733                                                ){helpText}
734                                                break
735                                        case 'TEXT':
736                                                inputElement = (renderType == 'element') ? 'textAreaElement' : 'textField'
737                                                out << "$inputElement"(
738                                                        description     : ucName,
739                                                        name            : prependName + it.escapedName(),
740                                                        value           : fieldValue,
741                                                        required        : it.isRequired()
742                                                ){helpText}
743                                                break
744                                        case 'STRINGLIST':
745                                                inputElement = (renderType == 'element') ? 'selectElement' : 'select'
746                                                if (!it.listEntries.isEmpty()) {
747                                                        out << "$inputElement"(
748                                                                description     : ucName,
749                                                                name            : prependName + it.escapedName(),
750                                                                from            : it.listEntries,
751                                                                value           : fieldValue,
752                                                                required        : it.isRequired()
753                                                        ){helpText}
754                                                } else {
755                                                        out << '<span class="warning">no values!!</span>'
756                                                }
757                                                break
758                                        case 'ONTOLOGYTERM':
759                                                // @see http://www.bioontology.org/wiki/index.php/NCBO_Widgets#Term-selection_field_on_a_form
760                                                // @see ontology-chooser.js
761                                                inputElement = (renderType == 'element') ? 'termElement' : 'termSelect'
762
763                                                // override addDummy to always add the dummy...
764                                                addDummy = true
765
766                                                if (it.ontologies) {
767                                                        out << "$inputElement"(
768                                                                description     : ucName,
769                                                                name            : prependName + it.escapedName(),
770                                                                value           : fieldValue.toString(),
771                                                                ontologies      : it.ontologies,
772                                                                addDummy        : addDummy,
773                                                                required        : it.isRequired()
774                                                        ){helpText}
775                                                } else {
776                                                        out << "$inputElement"(
777                                                                description     : ucName,
778                                                                name            : prependName + it.escapedName(),
779                                                                value           : fieldValue.toString(),
780                                                                addDummy        : addDummy,
781                                                                required        : it.isRequired()
782                                                        ){helpText}
783                                                }
784                                                break
785                                        case 'ONTOLOGYTERM-old':
786                                                // @see http://www.bioontology.org/wiki/index.php/NCBO_Widgets#Term-selection_field_on_a_form
787                                                // @see ontology-chooser.js
788                                                inputElement = (renderType == 'element') ? 'textFieldElement' : 'textField'
789                                                out << "$inputElement"(
790                                                        name    : prependName + it.escapedName(),
791                                                        value   : fieldValue,
792                                                        rel             : 'ontology-all',
793                                                        size    : 100,
794                                                        required: it.isRequired()
795                                                )
796                                                out << hiddenField(
797                                                        name: prependName + it.name + '-concept_id',
798                                                        value: fieldValue
799                                                )
800                                                out << hiddenField(
801                                                        name: prependName + it.escapedName() + '-ontology_id',
802                                                        value: fieldValue
803                                                )
804                                                out << hiddenField(
805                                                        name: prependName + it.escapedName() + '-full_id',
806                                                        value: fieldValue
807                                                )
808                                                break
809                                        case 'DATE':
810                                                inputElement = (renderType == 'element') ? 'dateElement' : 'textField'
811
812                                                // transform value?
813                                                if (fieldValue instanceof Date) {
814                                                        if (fieldValue.getHours() == 0 && fieldValue.getMinutes() == 0) {
815                                                                // transform date instance to formatted string (dd/mm/yyyy)
816                                                                fieldValue = String.format('%td/%<tm/%<tY', fieldValue)
817                                                        } else {
818                                                                // transform to date + time
819                                                                fieldValue = String.format('%td/%<tm/%<tY %<tH:%<tM', fieldValue)
820                                                        }
821                                                }
822
823                                                // render element
824                                                out << "$inputElement"(
825                                                        description     : ucName,
826                                                        name            : prependName + it.escapedName(),
827                                                        value           : fieldValue,
828                                                        rel                     : 'date',
829                                                        required        : it.isRequired()
830                                                ){helpText}
831                                                break
832                                        case ['RELTIME']:
833                                                inputElement = (renderType == 'element') ? 'textFieldElement' : 'textField'
834                                                out << "$inputElement"(
835                                                        description                     : ucName,
836                                                        name                            : prependName + it.escapedName(),
837                                                        value                           : new RelTime( fieldValue ).toString(),
838                            addExampleElement   : true,
839                            onBlur                              : 'showExampleReltime(this)',
840                                                        required                        : it.isRequired()
841                                                ){helpText}
842                                                break
843                                        case ['FILE']:
844                                                inputElement = (renderType == 'element') ? 'fileFieldElement' : 'fileField'
845                                                out << "$inputElement"(
846                                                        description                     : ucName,
847                                                        name                            : prependName + it.escapedName(),
848                                                        value                           : fieldValue ? fieldValue : "",
849                            addExampleElement   : true,
850                                                        required                        : it.isRequired()
851                                                ){helpText}
852                                                break
853                                        case ['BOOLEAN']:
854                                                inputElement = (renderType == 'element') ? 'checkBoxElement' : 'checkBox'
855                                                out << "$inputElement"(
856                                                        description     : ucName,
857                                                        name            : prependName + it.escapedName(),
858                                                        value           : fieldValue,
859                                                        required        : it.isRequired()
860                                                ){helpText}
861                                                break
862                                        case ['TEMPLATE']:
863                                                inputElement = (renderType == 'element') ? 'templateElement' : 'templateSelect'
864                                                out << "$inputElement"(
865                                                        description     : ucName,
866                                                        name            : prependName + it.escapedName(),
867                                                        addDummy        : true,
868                                                        entity          : it.entity,
869                                                        value           : fieldValue,
870                                                        required        : it.isRequired()
871                                                ){helpText}
872                                                break
873                                        case ['MODULE']:
874                                            def from = []
875                                                AssayModule.findAll().each { from[from.size()] = it.toString() }
876
877                                                inputElement = (renderType == 'element') ? 'selectElement' : 'select'
878                                                out << "$inputElement"(
879                                                        description     : ucName,
880                                                        name            : prependName + it.escapedName(),
881                                                        from            : from,
882                                                        value           : fieldValue.toString(),
883                                                        required        : it.isRequired()
884                                                ){helpText}
885                                        break
886                                                break
887                                        default:
888                                                // unsupported field type
889                                                out << '<span class="warning">!' + it.type + '</span>'
890                                                break
891                                }
892
893                                // output column closing element?
894                                if (renderType == 'column') {
895                                        out << '</div>'
896                                }
897                        }
898                }
899        }
900
901        def PublicationSelectElement = { attrs, body ->
902                attrs.description = 'Publications';
903                // render list with publications currently available
904                baseElement.call(
905                        '_publicationList',
906                        attrs,
907                        body
908                )
909
910                attrs.description = '';
911
912                // render 'Add publication button'
913                baseElement.call(
914                        '_publicationAddButton',
915                        attrs,
916                        body
917                )
918        }
919
920        /**
921         * Renders a input box for publications
922         */
923        def publicationSelect = { attrs, body ->
924                if (attrs.get('value') == null) {
925                        attrs.value = [];
926                }
927                if (attrs.get('description') == null) {
928                        attrs.description = '';
929                }
930                out << '<form id="' + attrs.name + '_form" onSubmit="return false;">';
931                out << textField(
932                        name: attrs.get("name"),
933                        value: '',
934                        rel: 'publication-pubmed',
935                        style: 'width: 400px;'
936                );
937                out << '</form>';
938                out << '<script type="text/javascript">';
939                out << '  var onSelect = function( chooserObject, inputElement, event, ui ) { selectPubMedAdd( chooserObject, inputElement, event, ui ); enableButton( ".' + attrs.name + '_publication_dialog", "Add", true ); };'
940                out << '  iField = $( "#' + attrs.get('name') + '" );';
941                out << '  new PublicationChooser().initAutocomplete( iField, { "select" : onSelect } );';
942                out << '</script>';
943        }
944
945        def _publicationList = { attrs, body ->
946                def display_none = 'none';
947                if (!attrs.get('value') || attrs.get('value').size() == 0) {
948                        display_none = 'inline';
949                }
950
951                // Add a unordered list
952                out << '<ul class="publication_list" id="' + attrs.name + '_list">';
953
954                out << '<li>';
955                out << '<span class="publication_none" id="' + attrs.name + '_none" style="display: ' + display_none + ';">';
956                out << 'No publications selected';
957                out << '</span>';
958                out << '</li>';
959
960                out << '</ul>';
961
962                // Add the publications using javascript
963                out << '<script type="text/javascript">'
964                if (attrs.get('value') && attrs.get('value').size() > 0) {
965                        def i = 0;
966                        attrs.get('value').each {
967                                out << 'showPublication( ';
968                                out << '  "' + attrs.name + '",';
969                                out << '  ' + it.id + ',';
970                                out << '  "' + it.title + '",';
971                                out << '  "' + it.authorsList + '",';
972                                out << '  ' + i++;
973                                out << ');';
974                        }
975                }
976                out << '</script>';
977
978                def ids;
979                if (attrs.get('value') && attrs.get('value').size() > 0) {
980                        ids = attrs.get('value').id.join(',')
981                } else {
982                        ids = '';
983                }
984                out << '<input type="hidden" name="' + attrs.name + '_ids" value="' + ids + '" id="' + attrs.name + '_ids">';
985        }
986
987        def _publicationAddButton = { attrs, body ->
988
989                // Output the dialog for the publications
990                out << '<div id="' + attrs.name + '_dialog">';
991                out << '<p>Search for a publication on pubmed. You can search on a part of the title, authors or pubmed ID. </p>';
992                out << publicationSelect(attrs, body);
993                out << '</div>';
994                out << '<script type="text/javascript">';
995                out << '  createPublicationDialog( "' + attrs.name + '" );'
996                out << '</script>';
997
998                out << '<input type="button" onClick="openPublicationDialog(\'' + attrs.name + '\' );" value="Add Publication">';
999        }
1000
1001        def ContactSelectElement = { attrs, body ->
1002
1003                attrs.description = 'Contacts';
1004                // render list with publications currently available
1005                baseElement.call(
1006                        '_contactList',
1007                        attrs,
1008                        body
1009                )
1010
1011                attrs.description = '';
1012
1013                // render 'publications list'
1014                out << '<div id="' + attrs.name + '_dialog" class="contacts_dialog" style="display: none;">'
1015                baseElement.call(
1016                        '_personSelect',
1017                        attrs,
1018                        body
1019                )
1020                baseElement.call(
1021                        '_roleSelect',
1022                        attrs,
1023                        body
1024                )
1025                baseElement.call(
1026                        '_contactAddButtonAddition',
1027                        attrs,
1028                        body
1029                )
1030                out << '</div>';
1031
1032                // render 'Add contact button'
1033                baseElement.call(
1034                        '_contactAddDialogButton',
1035                        attrs,
1036                        body
1037                )
1038        }
1039
1040        def _contactList = { attrs, body ->
1041                def display_none = 'none';
1042                if (!attrs.get('value') || attrs.get('value').size() == 0) {
1043                        display_none = 'inline';
1044                }
1045
1046                // Add a unordered list
1047                out << '<ul class="contact_list" id="' + attrs.name + '_list">';
1048
1049                out << '<li>';
1050                out << '<span class="contacts_none" id="' + attrs.name + '_none" style="display: ' + display_none + ';">';
1051                out << 'No contacts selected';
1052                out << '</span>';
1053                out << '</li>';
1054
1055                out << '</ul>';
1056
1057                // Add the contacts using javascript
1058                out << '<script type="text/javascript">'
1059                if (attrs.get('value') && attrs.get('value').size() > 0) {
1060                        def i = 0;
1061                        attrs.get('value').each {
1062                                out << 'showContact( ';
1063                                out << '  "' + attrs.name + '",';
1064                                out << '  "' + it.person.id + '-' + it.role.id + '",';
1065                                out << '  "' + it.person.lastName + ', ' + it.person.firstName + (it.person.prefix ? ' ' + it.person.prefix : '') + '",';
1066                                out << '  "' + it.role.name + '",';
1067                                out << '  ' + i++;
1068                                out << ');';
1069                        }
1070                }
1071                out << '</script>';
1072
1073                def ids = '';
1074                if (attrs.get('value') && attrs.get('value').size() > 0) {
1075                        ids = attrs.get('value').collect { it.person.id + '-' + it.role.id }
1076                        ids = ids.join(',');
1077                }
1078                out << '<input type="hidden" name="' + attrs.name + '_ids" value="' + ids + '" id="' + attrs.name + '_ids">';
1079        }
1080
1081        def _contactAddSelect = { attrs, body ->
1082                out << _personSelect(attrs) + _roleSelect(attrs);
1083        }
1084
1085        def _contactAddButtonAddition = { attrs, body ->
1086                out << '<input type="button" onClick="if( addContact ( \'' + attrs.name + '\' ) ) { $(\'#' + attrs.name + '_dialog\').hide(); $( \'#' + attrs.name + '_dialogButton\' ).show(); }" value="Add">';
1087                out << '<input type="button" onClick="$(\'#' + attrs.name + '_dialog\').hide(); $( \'#' + attrs.name + '_dialogButton\' ).show();" value="Close">';
1088        }
1089
1090        def _contactAddDialogButton = { attrs, body ->
1091                out << '<input type="button" onClick="$( \'#' + attrs.name + '_dialog\' ).show(); $(this).hide();" id="' + attrs.name + '_dialogButton" value="Add Contact">';
1092        }
1093        /**
1094         * Person select element
1095         * @param Map attributes
1096         */
1097        def _personSelect = { attrs ->
1098                def selectAttrs = new LinkedHashMap();
1099
1100                // define 'from'
1101                def persons = Person.findAll().sort({ a, b -> a.lastName == b.lastName ? (a.firstName <=> b.firstName) : (a.lastName <=> b.lastName) } as Comparator);
1102                selectAttrs.from = persons.collect { it.lastName + ', ' + it.firstName + (it.prefix ? ' ' + it.prefix : '') }
1103                selectAttrs.keys = persons.id;
1104
1105                // add 'rel' attribute
1106                selectAttrs.rel = 'person'
1107                selectAttrs.name = attrs.name + '_person';
1108
1109                // add a dummy field
1110                selectAttrs.from.add(0,'')
1111                selectAttrs.keys.add(0,'')
1112
1113                out << "Person: " + select(selectAttrs)
1114        }
1115
1116        /**
1117         * Role select element
1118         * @param Map attributes
1119         */
1120        def _roleSelect = { attrs ->
1121                def selectAttrs = new LinkedHashMap();
1122
1123                // define 'from'
1124                def roles = PersonRole.findAll();
1125                selectAttrs.from = roles.collect { it.name };
1126                selectAttrs.keys = roles.id;
1127
1128                // add 'rel' attribute
1129                selectAttrs.rel = 'role'
1130                selectAttrs.name = attrs.name + '_role';
1131
1132                // add a dummy field
1133                selectAttrs.from.add(0,'')
1134                selectAttrs.keys.add(0,'')
1135
1136                out << "Role: " + select(selectAttrs)
1137        }
1138
1139
1140        def UserSelectElement = { attrs, body ->
1141                // render list with publications currently available
1142                baseElement.call(
1143                        '_userList',
1144                        attrs,
1145                        body
1146                )
1147
1148                attrs.description = '';
1149
1150                // render 'Add user button'
1151                baseElement.call(
1152                        '_userAddButton',
1153                        attrs,
1154                        body
1155                )
1156        }
1157
1158        /**
1159         * Renders an input box for publications
1160         */
1161        def userSelect = { attrs, body ->
1162                if (attrs.get('value') == null) {
1163                        attrs.value = [];
1164                }
1165                if (attrs.get('description') == null) {
1166                        attrs.description = '';
1167                }
1168               
1169                out << '<form id="' + attrs.name + '_form" onSubmit="return false;">';
1170                out << select(
1171                        name: attrs.get("name"),
1172                        value: '',
1173                        from: SecUser.list(),
1174                        optionValue: 'username',
1175                        optionKey: 'id',
1176                        style: 'width: 400px;'
1177                );
1178                out << '</form>';
1179        }
1180
1181        def _userList = { attrs, body ->
1182                def display_none = 'none';
1183                if (!attrs.get('value') || attrs.get('value').size() == 0) {
1184                        display_none = 'inline';
1185                }
1186
1187                // Add a unordered list
1188                out << '<ul class="user_list" id="' + attrs.name + '_list">';
1189
1190                out << '<li>';
1191                out << '<span class="user_none" id="' + attrs.name + '_none" style="display: ' + display_none + ';">';
1192                out << '-';
1193                out << '</span>';
1194                out << '</li>';
1195
1196                out << '</ul>';
1197
1198                // Add the publications using javascript
1199                out << '<script type="text/javascript">'
1200                if (attrs.get('value') && attrs.get('value').size() > 0) {
1201                        def i = 0;
1202                        attrs.get('value').each {
1203                                out << 'showUser( ';
1204                                out << '  "' + attrs.name + '",';
1205                                out << '  ' + it.id + ',';
1206                                out << '  "' + it.username + '",';
1207                                out << '  ' + i++;
1208                                out << ');';
1209                        }
1210                }
1211                out << '</script>';
1212
1213                def ids;
1214                if (attrs.get('value') && attrs.get('value').size() > 0) {
1215                        ids = attrs.get('value').id.join(',')
1216                } else {
1217                        ids = '';
1218                }
1219                out << '<input type="hidden" name="' + attrs.name + '_ids" value="' + ids + '" id="' + attrs.name + '_ids">';
1220        }
1221
1222        def _userAddButton = { attrs, body ->
1223
1224                // Output the dialog for the publications
1225                out << '<div id="' + attrs.name + '_dialog">';
1226                out << '<p>Select a user from the database.</p>';
1227                out << userSelect(attrs, body);
1228                out << '</div>';
1229                out << '<script type="text/javascript">';
1230                out << '  createUserDialog( "' + attrs.name + '" );'
1231                out << '</script>';
1232
1233                out << '<input type="button" onClick="openUserDialog(\'' + attrs.name + '\' );" value="Add User">';
1234        }
1235
1236        def showTemplateField = { attrs, body ->
1237                def field = attrs.get( 'field' );
1238                def entity = attrs.get( 'entity' );
1239                def fieldName = '';
1240                def fieldType = '';
1241                def fieldUnit = '';
1242               
1243                if( entity ) {
1244                        if( field instanceof String ) {
1245                                fieldName = field;
1246                                fieldType = '';
1247                                fieldUnit = '';
1248                        } else if( field instanceof TemplateField ) {
1249                                fieldName = field.name
1250                                fieldType = field.type.toString();
1251                                fieldUnit = field.unit
1252                        } else {
1253                                return;
1254                        }
1255
1256                        def value = entity.getFieldValue( fieldName );
1257
1258                        // Show a link if the field is a FILE field
1259                        if( fieldType == 'FILE' && value != "" ) {
1260                            out << '<a href="' + g.createLink( controller: "file", action: "get",  id: value ) + '">' + value + '</a>';
1261                        } else {
1262                                out << value;
1263                        }
1264
1265                        // Show the unit (if a unit is present and a value was shown)
1266                        if( fieldUnit && value != null && value != "" )
1267                                out << " " + fieldUnit
1268
1269                }
1270        }
1271
1272}
Note: See TracBrowser for help on using the repository browser.