source: trunk/grails-app/controllers/dbnp/studycapturing/WizardController.groovy @ 520

Last change on this file since 520 was 520, checked in by duh, 11 years ago
  • in revision #519 and #518 both wizard.js and wizard.css were updated, but no minified version was generated so the feature will not work in production. Added minified versions...
  • Property svn:keywords set to Date Author Rev
File size: 22.7 KB
Line 
1package dbnp.studycapturing
2
3import dbnp.data.*
4
5// Grails convertors is imported in order to create JSON objects
6import grails.converters.*
7
8
9/**
10 * Wizard Controler
11 *
12 * The wizard controller handles the handeling of pages and data flow
13 * through the study capturing wizard.
14 *
15 * @author Jeroen Wesbeek
16 * @since 20100107
17 * @package studycapturing
18 *
19 * Revision information:
20 * $Rev: 520 $
21 * $Author: duh $
22 * $Date: 2010-06-03 10:59:25 +0000 (do, 03 jun 2010) $
23 */
24class WizardController {
25        /**
26         * index method, redirect to the webflow
27         * @void
28         */
29        def index = {
30                /**
31                 * Do you believe it in your head?
32                 * I can go with the flow
33                 * Don't say it doesn't matter (with the flow) matter anymore
34                 * I can go with the flow (I can go)
35                 * Do you believe it in your head?
36                 */
37                redirect(action: 'pages')
38        }
39
40        /**
41         * WebFlow definition
42         * @see http://grails.org/WebFlow
43         * @void
44         */
45        def pagesFlow = {
46                // start the flow
47                onStart {
48                        // define flow variables
49                        flow.page = 0
50                        flow.pages = [
51                                //[title: 'Templates'],                 // templates
52                                [title: 'Start'],                               // load or create a study
53                                [title: 'Study'],                               // study
54                                [title: 'Subjects'],                    // subjects
55                                [title: 'Events'],                              // events and event grouping
56                                [title: 'Groups'],                              // groups
57                                [title: 'Samples'],                             // samples
58                                [title: 'Confirmation'],                // confirmation page
59                                [title: 'Done']                                 // finish page
60                        ]
61                        success()
62                }
63
64                // render the main wizard page which immediately
65                // triggers the 'next' action (hence, the main
66                // page dynamically renders the study template
67                // and makes the flow jump to the study logic)
68                mainPage {
69                        render(view: "/wizard/index")
70                        onRender {
71                                flow.page = 1
72                                success()
73                        }
74                        on("next").to "start"
75                }
76
77                // create or modify a study
78                start {
79                        render(view: "_start")
80                        onRender {
81                                flow.page = 1
82                                success()
83                        }
84                        on("next").to "study"
85                        on("modify").to "modify"
86                }
87
88                // load a study to modify
89                modify {
90                        render(view: "_modify")
91                        onRender {
92                                flow.page = 1
93                                flash.cancel = true
94                                success()
95                        }
96                        on("cancel") {
97                                flow.study = null
98
99                                success()
100                        }.to "start"
101                        on("next") {
102                                // TODO: loading a study is not yet implemented
103                                //       create a error stating this feature is
104                                //       not yet implemented
105                                flash.errors = [:]
106                                this.appendErrorMap(
107                                        ['study': 'Loading a study and modifying it has not yet been implemented. Please press \'cancel\' to go back to the initial page...'],
108                                        flash.errors
109                                )
110
111                                error()
112                        }.to "modify"
113                }
114
115                // render and handle the study page
116                // TODO: make sure both template as well as logic will
117                //       handle Study templates as well!!!
118                study {
119                        render(view: "_study")
120                        onRender {
121                                flow.page = 2
122                                success()
123                        }
124                        on("refresh") {
125                                flash.values = params
126
127                                // handle study data
128                                this.handleStudy(flow, flash, params)
129
130                                // remove errors as we don't want any warnings now
131                                flash.errors = [:]
132
133                                success()
134                        }.to "study"
135                        on("switchTemplate") {
136                                flash.values = params
137
138                                // handle study data
139                                this.handleStudy(flow, flash, params)
140
141                                // remove errors as we don't want any warnings now
142                                flash.errors = [:]
143
144                                success()
145                        }.to "study"
146                        on("previous") {
147                                flash.errors = [:]
148
149                                // handle the study
150                                this.handleStudy(flow, flash, params)
151
152                                // reset errors
153                                flash.errors = [:]
154
155                                success()
156                        }.to "start"
157                        on("next") {
158                                flash.errors = [:]
159
160                                if (this.handleStudy(flow, flash, params)) {
161                                        success()
162                                } else {
163                                        error()
164                                }
165                        }.to "subjects"
166                }
167
168                // render and handle subjects page
169                subjects {
170                        render(view: "_subjects")
171                        onRender {
172                                flow.page = 3
173
174                                if (!flow.subjects) {
175                                        flow.subjects = [:]
176                                        flow.subjectTemplates = [:]
177                                }
178                                success()
179                        }
180                        on("refresh") {
181                                flash.values = params
182                                success()
183                        }.to "subjects"
184                        on("add") {
185                                // handle subjects
186                                this.handleSubjects(flow, flash, params)
187
188                                flash.errors = [:]
189                                flash.values = params
190                                def speciesTerm = Term.findByName(params.species);
191                                def subjectTemplateName = params.get('template');
192                                def subjectTemplate = Template.findByName(subjectTemplateName);
193
194                                // add this subject template to the subject template array
195                                if (!flow.subjectTemplates[ subjectTemplateName ]) {
196                                        flow.subjectTemplates[ subjectTemplateName ] = [
197                                                name: subjectTemplateName,
198                                                template: subjectTemplate,
199                                                subjects: [:]
200                                        ]
201                                }
202
203                                // add x subjects of species y
204                                (params.addNumber as int).times {
205                                        def increment = (flow.subjects.size()) ? (flow.subjects.keySet().max() + 1) : 0
206                                        def subject = new Subject(
207                                                name: 'Subject ' + (increment + 1),
208                                                species: speciesTerm,
209                                                template: subjectTemplate
210                                        )
211
212                                        // instantiate a new Subject
213                                        flow.subjects[ increment ] = subject
214
215                                        // and remember the subject id with the template
216                                        def subjectsSize = (flow.subjectTemplates[ subjectTemplateName ].subjects.size()) ? (flow.subjectTemplates[ subjectTemplateName ].subjects.keySet().max() + 1) : 0
217                                        flow.subjectTemplates[ subjectTemplateName ].subjects[ subjectsSize ] = increment
218                                }
219
220                                success()
221                        }.to "subjects"
222                        on("next") {
223                                flash.errors = [:]
224
225                                // check if we have at least one subject
226                                // and check form data
227                                if (flow.subjects.size() < 1) {
228                                        // append error map
229                                        this.appendErrorMap(['subjects': 'You need at least to create one subject for your study'], flash.errors)
230                                        error()
231                                } else if (!this.handleSubjects(flow, flash, params)) {
232                                        error()
233                                } else {
234                                        success()
235                                }
236                        }.to "events"
237                        on("delete") {
238                                // handle subjects
239                                this.handleSubjects(flow, flash, params)
240
241                                flash.errors = [:]
242                                def delete = params.get('do') as int;
243
244                                // remove subject
245                                if (flow.subjects[ delete ] && flow.subjects[ delete ] instanceof Subject) {
246                                        // remove subject from templates
247                                        flow.subjectTemplates.each() { templateName, templateData ->
248                                                templateData.subjects.remove( delete )
249                                        }
250
251                                        // remove subject altogether
252                                        flow.subjects.remove( delete )
253                                }
254                        }.to "subjects"
255                        on("previous") {
256                                flash.errors = [:]
257
258                                // handle form data
259                                if (!this.handleSubjects(flow, flash, params)) {
260                                        error()
261                                } else {
262                                        success()
263                                }
264                        }.to "study"
265                }
266
267                // render events page
268                events {
269                        render(view: "_events")
270                        onRender {
271                                flow.page = 4
272
273                                if (!flow.event) {
274                                        flow.event                      = new Event()
275                                        flow.events                     = []
276                                        flow.eventGroups        = []
277                                        flow.eventGroups[0]     = new EventGroup(name: 'Group 1')       // 1 group by default
278                                        flow.eventTemplates     = [:]
279                                } else if (!flash.values) {
280                                        // set flash.values.templateType based on the event instance
281                                        flash.values = [:]
282                                        flash.values.templateType = (flow.event instanceof Event) ? 'event' : 'sample'
283                                }
284                                success()
285                        }
286                        on("switchTemplate") {
287                                flash.values = params
288
289                                // handle study data
290                                this.handleEvents(flow, flash, params)
291
292                                // remove errors as we don't want any warnings now
293                                flash.errors = [:]
294                        }.to "events"
295                        on("add") {
296                                flash.values                    = params
297                                def eventTemplateName   = (params.get('eventType') == 'event') ? params.get('eventTemplate') : params.get('sampleTemplate')
298                                def eventTemplate               = Template.findByName(eventTemplateName)
299
300                                // handle study data
301                                this.handleEvents(flow, flash, params)
302
303                                // validate event object
304                                if (flow.event.validate()) {
305                                        // add this event template to the event template array
306                                        if (!flow.eventTemplates[ eventTemplateName ]) {
307                                                flow.eventTemplates[ eventTemplateName ] = [
308                                                        name: eventTemplateName,
309                                                        template: eventTemplate,
310                                                        events: []
311                                                ]
312                                        }
313
314                                        // it validated! Duplicate the event object...
315                                        def newEvent    = flow.event
316                                        def increment   = flow.events.size()
317
318                                        // ...store it in the events map in the flow scope...
319                                        flow.events[ increment ] = newEvent
320
321                                        // ...and 'reset' the event object in the flow scope
322                                        flow.event = new Event(template: newEvent.template)
323                                       
324                                        // remember the event id with the template
325                                        def eventSize = flow.eventTemplates[ eventTemplateName ]['events'].size()
326                                        flow.eventTemplates[ eventTemplateName ]['events'][ eventSize ] = increment
327
328                                        success()
329                                } else {
330                                        // it does not validate, show error feedback
331                                        flash.errors = [:]
332                                        this.appendErrors(flow.event, flash.errors)
333                                        error()
334                                }
335                        }.to "events"
336                        on("deleteEvent") {
337                                flash.values = params
338                                def delete = params.get('do') as int;
339
340                                // handle event groupings
341                                this.handleEventGrouping(flow, flash, params)
342
343                                // remove event
344                                if (flow.events[ delete ] && flow.events[ delete ] instanceof Event) {
345                                        flow.events.remove(delete)
346                                }
347
348                                success()
349                        }.to "events"
350                        on("addEventGroup") {
351                                flash.values = params
352                               
353                                // handle study data
354                                this.handleEvents(flow, flash, params)
355
356                                // handle event groupings
357                                this.handleEventGrouping(flow, flash, params)
358
359                                def increment = flow.eventGroups.size()
360                                def groupName = "Group " + (increment + 1)
361
362                                // check if group name exists
363                                def nameExists = true
364                                def u = 0
365
366                                // make sure a unique name is generated
367                                while (nameExists) {
368                                        u++
369                                        def count = 0
370                                       
371                                        flow.eventGroups.each() {
372                                                if (it.name == groupName) {
373                                                        groupName = "Group " + (increment + 1) + "," + u
374                                                } else {
375                                                        count++
376                                                }
377                                        }
378
379                                        nameExists = !(count == flow.eventGroups.size())
380                                }
381
382                                flow.eventGroups[increment] = new EventGroup( name: groupName )
383
384                                success()
385                        }.to "events"
386                        on("deleteEventGroup") {
387                                flash.values = params
388                                def delete = params.get('do') as int;
389
390                                // handle event groupings
391                                this.handleEventGrouping(flow, flash, params)
392
393                                // remove the group with this specific id
394                                if (flow.eventGroups[delete] && flow.eventGroups[delete] instanceof EventGroup) {
395                                        // remove this eventGroup
396                                        flow.eventGroups.remove(delete)
397                                }
398
399                                success()
400                        }.to "events"
401                        on("previous") {
402                                // handle event groupings
403                                this.handleEventGrouping(flow, flash, params)
404                        }.to "subjects"
405                        on("next") {
406                                flash.values = params
407                                flash.errors = [:]
408
409                                // handle study data
410                                if (flow.events.size() < 1) {
411                                        // append error map
412                                        this.appendErrorMap(['events': 'You need at least to create one event for your study'], flash.errors)
413                                        error()                                         
414                                } else if (this.handleEvents(flow, flash, params)) {
415                                        success()
416                                } else {
417                                        error()
418                                }
419                        }.to "groups"
420                }
421
422                // groups page
423                groups {
424                        render(view: "_groups")
425                        onRender {
426                                flow.page = 5
427                                success()
428                        }
429                        on("previous") {
430                                this.handleSubjectGrouping(flow, flash, params)
431                                success()
432                        }.to "events"
433                        on("next") {
434                                this.handleSubjectGrouping(flow, flash, params)
435                                success()
436                        }.to "samples"
437                }
438
439                // samples page
440                samples {
441                        render(view: "_samples")
442                        onRender {
443                                flow.page = 6
444                                flow.bla = "samples"
445
446                                // iterate through subjects
447                                flow.subjects.each() { subject ->
448                                        println subject.value.name
449
450                                        // iterate through events
451                                        flow.events.each() { event ->
452                                                println "bla"
453                                                if (event instanceof SamplingEvent) {
454                                                        //println event.getFieldValue('name')
455                                                        println event.startTime
456                                                        println event.endTime
457                                                }
458
459                                        }
460                                }
461
462                                success()
463                        }
464                        on("previous") {
465                                success()
466                        }.to "groups"
467                        on("next") {
468                                success()
469                        }.to "confirm"
470                }
471
472                // confirmation
473                confirm {
474                        render(view: "_confirmation")
475                        onRender {
476                                flow.page = 7
477                        }
478                        on("toStudy").to "study"
479                        on("toSubjects").to "subjects"
480                        on("toEvents").to "events"
481                        on("toGroups").to "groups"
482                        on("previous").to "samples"
483                        on("next").to "waitForSave"
484                }
485
486                waitForSave {
487                        render(view: "_wait")
488                        onRender {
489                                flow.page = 8
490                        }
491                        on("next").to "save"
492                }
493
494                // store all study data
495                save {
496                        action {
497                                println "saving..."
498                                flash.errors = [:]
499
500                                // persist data to the database
501                                try {
502                                        println ".saving wizard data..."
503
504                                        // add events to study
505                                        println ".add events to study"
506                                        flow.events.each() { event ->
507                                                if (event instanceof SamplingEvent) {
508                                                        flow.study.addToSamplingEvents(event)
509                                                } else {
510                                                        flow.study.addToEvents(event)
511                                                }
512                                        }
513
514                                        // add subjects to study
515                                        println ".add subjects to study"
516                                        flow.subjects.each() { subjectId, subject ->
517                                                flow.study.addToSubjects(subject)
518                                        }
519
520                                        // add eventGroups to study
521                                        println ".add eventGroups to study"
522                                        flow.eventGroups.each() { eventGroup ->
523                                                flow.study.addToEventGroups(eventGroup)
524                                        }
525
526                                        // save study
527                                        println ".saving study"
528                                        if (!flow.study.save(flush:true)) {
529                                                this.appendErrors(flow.study, flash.errors)
530                                                throw new Exception('error saving study')
531                                        }
532                                        println ".saved study "+flow.study+" (id: "+flow.study.id+")"
533
534                                        success()
535                                } catch (Exception e) {
536                                        // rollback
537                                        this.appendErrorMap(['exception': e.toString() + ', see log for stacktrace' ], flash.errors)
538
539                                        // stacktrace in flash scope
540                                        flash.debug = e.getStackTrace()
541
542                                        error()
543                                }
544                        }
545                        on("error").to "error"
546                        on(Exception).to "error"
547                        on("success").to "done"
548                }
549
550                // error storing data
551                error {
552                        render(view: "_error")
553                        onRender {
554                                flow.page = 7
555                        }
556                        on("next").to "waitForSave"
557                        on("previous").to "samples"
558                }
559
560                // render page three
561                done {
562                        render(view: "_done")
563                        onRender {
564                                flow.page = 8
565                        }
566                        on("previous") {
567                                // TODO
568                        }.to "confirm"
569                }
570        }
571
572        /**
573         * re-usable code for handling study form data in a web flow
574         * @param Map LocalAttributeMap (the flow scope)
575         * @param Map localAttributeMap (the flash scope)
576         * @param Map GrailsParameterMap (the flow parameters = form data)
577         * @returns boolean
578         */
579        def handleStudy(flow, flash, params) {
580                // create study instance if we have none
581                if (!flow.study) flow.study = new Study();
582
583                // create date instance from date string?
584                // @see WizardTagLibrary::dateElement{...}
585                if (params.get('startDate')) {
586                        params.startDate = new Date().parse("d/M/yyyy", params.get('startDate').toString())
587                } else {
588                        params.remove('startDate')
589                }
590
591                // if a template is selected, get template instance
592                def template = params.remove('template')
593                if (template instanceof String && template.size() > 0) {
594                        flow.study.template = Template.findByName(template)
595                } else if (template instanceof Template) {
596                        flow.study.template = template
597                }
598
599                // iterate through fields
600                if (flow.study.template) {
601                        flow.study.giveFields().each() {
602                                flow.study.setFieldValue(it.name, params.get(it.escapedName()))
603                        }
604                }
605
606                // handle Publications
607                handlePublications(flow, flash, params)
608
609                // validate study
610                if (flow.study.validate()) {
611                        return true
612                } else {
613                        // validation failed, feedback errors
614                        flash.errors = [:]
615                        this.appendErrors(flow.study, flash.errors)
616                        return false
617                }
618        }
619
620        /**
621         * re-usable code for handling publications form data in a web flow
622         * @param Map LocalAttributeMap (the flow scope)
623         * @param Map localAttributeMap (the flash scope)
624         * @param Map GrailsParameterMap (the flow parameters = form data)
625         * @returns boolean
626         */
627        def handlePublications(flow, flash, params) {
628                // create study instance if we have none
629                if (!flow.study) flow.study = new Study();
630                if (!flow.study.publications ) flow.study.publications = [];
631
632                // Check the ids of the pubblications that should be attached
633                // to this study. If they are already attached, keep 'm. If
634                // studies are attached that are not in the selected (i.e. the
635                // user deleted them), remove them
636                def publicationIDs = params.get( 'publication_ids' );
637                if( publicationIDs ) {
638                    // Find the individual IDs and make integers
639                    publicationIDs = publicationIDs.split(',').collect { Integer.parseInt( it, 10 ) };
640
641                    // First remove the publication that are not present in the array
642                    flow.study.publications.removeAll { publication -> !publicationIDs.find { id -> id == publication.id } }
643
644                    // Add those publications not yet present in the database
645                    publicationIDs.each { id ->
646                        if( !flow.study.publications.find { publication -> id == publication.id } ) {
647                            def publication = Publication.get( id );
648                            if( publication ) {
649                                flow.study.addToPublications( publication );
650                            } else {
651                                println( 'Publication with ID ' + id + ' not found in database.' );
652                            }
653                        }
654                    }
655
656                } else {
657                    println( 'No publications selected.')
658                    flow.study.publications.clear();
659                }
660
661        }
662
663
664        /**
665         * re-usable code for handling subject form data in a web flow
666         * @param Map LocalAttributeMap (the flow scope)
667         * @param Map localAttributeMap (the flash scope)
668         * @param Map GrailsParameterMap (the flow parameters = form data)
669         * @returns boolean
670         */
671        def handleSubjects(flow, flash, params) {
672                def names = [:];
673                def errors = false;
674                def id = 0;
675
676                // iterate through subject templates
677                flow.subjectTemplates.each() { subjectTemplate ->
678                        // iterate through subjects
679                        subjectTemplate.getValue().subjects.each() { subjectIncrement, subjectId ->
680                                // iterate through fields (= template fields and domain properties)
681                                flow.subjects[ subjectId ].giveFields().each() { subjectField ->
682                                        // set the field
683                                        flow.subjects[ subjectId ].setFieldValue(
684                                                subjectField.name,
685                                                params.get( 'subject_' + subjectId + '_' + subjectField.escapedName() )
686                                        )
687                                }
688
689                                // validate subject
690                                if (!flow.subjects[ subjectId ].validate()) {
691                                        errors = true
692                                        this.appendErrors(flow.subjects[ subjectId ], flash.errors, 'subject_' + subjectId + '_')
693                                }
694                        }
695                }
696
697                return !errors
698        }
699
700        /**
701         * re-usable code for handling event form data in a web flow
702         * @param Map LocalAttributeMap (the flow scope)
703         * @param Map localAttributeMap (the flash scope)
704         * @param Map GrailsParameterMap (the flow parameters = form data)
705         * @returns boolean
706         */
707        def handleEvents(flow, flash, params) {
708                def errors = false
709                def template = null
710
711                // handle the type of event
712                if (params.eventType == 'event') {
713                        flow.event = new Event();
714                        template = params.remove('eventTemplate')
715                } else if (params.eventType == 'sample') {
716                        flow.event = new SamplingEvent();
717                        template = params.remove('sampleTemplate')
718                }
719
720                // if a template is selected, get template instance
721                if (template instanceof String && template.size() > 0) {
722                        params.template = Template.findByName(template)
723                } else if (template instanceof Template) {
724                        params.template = template
725                } else {
726                        params.template = null
727                }
728
729                // set template
730                if (params.template) flow.event.template = params.template
731
732                // update event instance with parameters
733                flow.event.giveFields().each() { eventField ->
734                        flow.event.setFieldValue(eventField.name, params[ eventField.escapedName() ])   
735                }
736
737                // handle event objects
738                flow.eventTemplates.each() { eventTemplate ->
739                        // iterate through events
740                        eventTemplate.getValue().events.each() { eventId ->
741                                // iterate through template fields
742                                flow.events[ eventId ].giveFields().each() { eventField ->
743                                        flow.events[ eventId ].setFieldValue(eventField.name, params.get( 'event_' + eventId + '_' + eventField.escapedName() ) )
744                                }
745
746                                // validate event
747                                if (!flow.events[ eventId ].validate()) {
748                                        errors = true
749                                        this.appendErrors(flow.events[ eventId ], flash.errors, 'event_' + eventId + '_')
750                                }
751                        }
752                }
753
754                // handle event grouping
755                handleEventGrouping(flow, flash, params)
756
757                return !errors
758        }
759
760        /**
761         * re-usable code for handling event grouping in a web flow
762         * @param Map LocalAttributeMap (the flow scope)
763         * @param Map localAttributeMap (the flash scope)
764         * @param Map GrailsParameterMap (the flow parameters = form data)
765         * @returns boolean
766         */
767        def handleEventGrouping(flow, flash, params) {
768                // walk through eventGroups
769                def g = 0
770                flow.eventGroups.each() { eventGroup ->
771                        def e = 0
772
773                        // reset events
774                        eventGroup.events = new HashSet()
775
776                        // iterate through events
777                        flow.events.each() {
778                                if (params.get('event_' + e + '_group_' + g) == 'on') {
779                                        eventGroup.addToEvents(it)
780                                }
781                                e++
782                        }
783                        g++
784                }
785        }
786
787        /**
788         * re-usable code for handling subject grouping in a web flow
789         * @param Map LocalAttributeMap (the flow scope)
790         * @param Map localAttributeMap (the flash scope)
791         * @param Map GrailsParameterMap (the flow parameters = form data)
792         * @returns boolean
793         */
794        def handleSubjectGrouping(flow, flash, params) {
795                // iterate through event groups
796                def g = 0
797                flow.eventGroups.each() { eventGroup ->
798                        // reset subjects
799                        eventGroup.subjects = new HashSet()
800
801                        // iterate through subjects
802                        flow.subjects.each() { subjectId, subject ->
803                                // is this combination set?
804                                if (params.get('subject_' + subjectId + '_group_' + g) != null) {
805                                        eventGroup.addToSubjects(subject)
806                                }
807                        }
808
809                        g++
810                }
811        }
812
813        /**
814         * return the object from a map of objects by searching for a name
815         * @param String name
816         * @param Map map of objects
817         * @return Object
818         */
819        def getObjectByName(name, map) {
820                def result = null
821                map.each() {
822                        if (it.name == name) {
823                                result = it
824                        }
825                }
826
827                return result
828        }
829
830        /**
831         * transform domain class validation errors into a human readable
832         * linked hash map
833         * @param object validated domain class
834         * @returns object  linkedHashMap
835         */
836        def getHumanReadableErrors(object) {
837                def errors = [:]
838                object.errors.getAllErrors().each() {
839                        def message = it.toString()
840
841                        //errors[it.getArguments()[0]] = it.getDefaultMessage()
842                        errors[it.getArguments()[0]] = message.substring(0, message.indexOf(';'))
843                }
844
845                return errors
846        }
847
848        /**
849         * append errors of a particular object to a map
850         * @param object
851         * @param map linkedHashMap
852         * @void
853         */
854        def appendErrors(object, map) {
855                this.appendErrorMap(this.getHumanReadableErrors(object), map)
856        }
857
858        def appendErrors(object, map, prepend) {
859                this.appendErrorMap(this.getHumanReadableErrors(object), map, prepend)
860        }
861
862        /**
863         * append errors of one map to another map
864         * @param map linkedHashMap
865         * @param map linkedHashMap
866         * @void
867         */
868        def appendErrorMap(map, mapToExtend) {
869                map.each() {key, value ->
870                        mapToExtend[key] = ['key': key, 'value': value, 'dynamic': false]
871                }
872        }
873
874        def appendErrorMap(map, mapToExtend, prepend) {
875                map.each() {key, value ->
876                        mapToExtend[prepend + key] = ['key': key, 'value': value, 'dynamic': true]
877                }
878        }
879
880        /**
881         * Parses a RelTime string and returns a nice human readable string
882         *
883         * @returns Human Readable string or a HTTP response code 400 on error
884         */
885        def ajaxParseRelTime = {
886                if (params.reltime == null) {
887                        response.status = 400;
888                        render('reltime parameter is expected');
889                }
890
891                try {
892                        def reltime = RelTime.parseRelTime(params.reltime);
893                        render reltime.toPrettyString();
894                } catch (IllegalArgumentException e) {
895                        response.status = 400;
896                        render(e.getMessage());
897                }
898        }
899}
Note: See TracBrowser for help on using the repository browser.