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

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