Changeset 778


Ignore:
Timestamp:
Aug 5, 2010, 10:58:09 PM (10 years ago)
Author:
duh
Message:
  • big refactoring of the Study Capture Wizard until the grouping page, removing all internal maps and directory work on the study object to
    • simplify internal representation and handling
    • added static incremental identifiers to TemplateEntity?, EventGroup? and Template for use in dynamic web forms
  • TODO: fix the sample page
  • TODO: check cascaded deletes, confirm database content
Location:
trunk/grails-app
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/grails-app/controllers/dbnp/studycapturing/WizardController.groovy

    r769 r778  
    138138                                // clean the flow scope
    139139                                flow.remove('study')
    140                                 flow.remove('subjects')
    141                                 flow.remove('subjectTemplates')
    142                                 flow.remove('event')
    143                                 flow.remove('events')
    144                                 flow.remove('eventGroups')
    145                                 flow.remove('eventTemplates')
    146                                 flow.remove('samples')
    147                                 flow.remove('sampleTemplates')
    148140
    149141                                // set 'quicksave' variable to false
     
    172164                        }
    173165                        on("cancel") {
    174                                 flow.study = null
     166                                flow.remove('study')
    175167
    176168                                success()
     
    194186                        }
    195187                        on("refresh") {
    196                                 println ".refreshing...."
    197                                 flash.values = params
    198 
    199                                 // handle study data
    200                                 this.handleStudy(flow, flash, params)
     188                                // handle form data
     189                                studyPage(flow, flash, params)
    201190
    202191                                // force refresh of the template
    203                                 if (flow.study.template) {
     192                                if (flow.study.template && flow.study.template instanceof Template) {
    204193                                        flow.study.template.refresh()
    205194                                }
    206195
    207                                 // remove errors as we don't want any warnings now
    208                                 flash.errors = [:]
    209 
     196                                // reset errors
     197                                flash.errors = [:]
    210198                                success()
    211199                        }.to "study"
    212200            on("switchTemplate") {
    213                                 flash.values = params
    214 
    215                                 // handle study data
    216                                 this.handleStudy(flow, flash, params)
    217 
    218                                 // force refresh of the template
    219                                 if (flow.study.template) {
    220                                         flow.study.template.refresh()
    221                                 }
    222 
    223                                 // remove errors as we don't want any warnings now
    224                                 flash.errors = [:]
    225 
     201                                // handle form data
     202                                studyPage(flow, flash, params)
     203
     204                                // reset errors
     205                                flash.errors = [:]
    226206                                success()
    227207                        }.to "study"
    228208                        on("previous") {
    229                                 flash.errors = [:]
    230 
    231                                 // handle the study
    232                                 this.handleStudy(flow, flash, params)
     209                                // handle form data
     210                                studyPage(flow, flash, params)
    233211
    234212                                // reset errors
    235213                                flash.errors = [:]
    236 
    237214                                success()
    238215                        }.to "start"
    239216                        on("next") {
    240                                 flash.errors = [:]
    241 
    242                                 if (this.handleStudy(flow, flash, params)) {
    243                                         success()
    244                                 } else {
    245                                         error()
    246                                 }
     217                                studyPage(flow, flash, params) ? success() : error()
    247218                        }.to "subjects"
    248219                        on("quickSave") {
    249                                 flash.errors = [:]
    250 
    251                                 if (this.handleStudy(flow, flash, params)) {
    252                                         success()
    253                                 } else {
    254                                         error()
    255                                 }
     220                                studyPage(flow, flash, params) ? success() : error()
    256221                        }.to "waitForSave"
    257222                }
     
    263228                                flow.page = 3
    264229
    265                                 if (!flow.subjects) {
    266                                         flow.subjects = [:]
    267                                         flow.subjectTemplates = [:]
    268                                 }
    269 
    270                                 if (!flash.values) flash.values = [addNumber:1]
     230                                if (!flash.values || !flash.values.addNumber) flash.values = [addNumber:1]
    271231
    272232                                success()
    273233                        }
    274234                        on("refresh") {
     235                                // remember the params in the flash scope
    275236                                flash.values = params
    276237
    277238                                // refresh templates
    278                                 flow.subjectTemplates.each() {
    279                                         it.value.template.refresh()
     239                                flow.study.giveSubjectTemplates().each() {
     240                                        it.refresh()
    280241                                }
    281242
     
    283244                        }.to "subjects"
    284245                        on("add") {
    285                                 flash.errors = [:]
    286 
    287                                 // handle subjects
    288                                 this.handleSubjects(flow, flash, params)
    289 
    290                                 flash.errors = [:]
    291                                 flash.values = params
    292 
    293                                 def speciesTerm = Term.findByName(params.species)
    294                                 def subjectTemplateName = params.get('template')
    295                                 def subjectTemplate = Template.findByName(subjectTemplateName)
    296 
    297                                 // got a species and a subjectTemplate?
    298                                 if (speciesTerm && subjectTemplate) {
    299                                         // add this subject template to the subject template array
    300                                         if (!flow.subjectTemplates[subjectTemplateName]) {
    301                                                 flow.subjectTemplates[subjectTemplateName] = [
    302                                                         name: subjectTemplateName,
    303                                                         template: subjectTemplate,
    304                                                         subjects: [:]
    305                                                 ]
    306                                         }
    307 
    308                                         // add x subjects of species y
    309                                         (params.addNumber as int).times {
    310                                                 def increment = (flow.subjects.size()) ? (flow.subjects.keySet().max() + 1) : 0
    311                                                 def subject = new Subject(
    312                                                         name: 'Subject ' + (increment + 1),
    313                                                         species: speciesTerm,
    314                                                         template: subjectTemplate
    315                                                 )
    316 
    317                                                 // instantiate a new Subject
    318                                                 flow.subjects[increment] = subject
    319 
    320                                                 // add the subject to the study
    321                                                 flow.study.addToSubjects( subject )
    322 
    323                                                 // and remember the subject id with the template
    324                                                 def subjectsSize = (flow.subjectTemplates[subjectTemplateName].subjects.size()) ? (flow.subjectTemplates[subjectTemplateName].subjects.keySet().max() + 1) : 0
    325                                                 flow.subjectTemplates[subjectTemplateName].subjects[subjectsSize] = increment
    326                                         }
    327 
    328                                         success()
    329                                 } else {
    330                                         // add feedback
    331                                         if (!speciesTerm) this.appendErrorMap(['species': 'You need to select a species, or add one if it is not yet present'], flash.errors)
    332                                         if (!subjectTemplate) this.appendErrorMap(['template': 'You need to select a template, or add one if it is not yet present'], flash.errors)
    333 
    334                                         error()
    335                                 }
     246                                // handle form data
     247                                addSubjects(flow, flash, params) ? success() : error()
    336248                        }.to "subjects"
    337249                        on("delete") {
    338                                 // handle subjects
    339                                 this.handleSubjects(flow, flash, params)
    340 
    341                                 flash.errors = [:]
    342                                 def delete = params.get('do') as int
     250                                // handle form data
     251                                subjectPage(flow, flash, params)
     252
     253                                // reset errors
     254                                flash.errors = [:]
    343255
    344256                                // remove subject
    345                                 if (flow.subjects[ delete ] && flow.subjects[ delete ] instanceof Subject) {
    346                                         // from study as well
    347                                         flow.study.removeFromSubjects( flow.subjects[ delete ] )
    348 
    349                                         // remove subject from templates
    350                                         flow.subjectTemplates.each() { templateName, templateData ->
    351                                                 templateData.subjects.values().remove( delete )
    352                                         }
    353 
    354                                         // remove templates that contain no subject
    355                                         flow.subjectTemplates.find{!it.value.subjects.size()}.each{ flow.subjectTemplates.remove( it.key ) }
    356 
    357                                         // remove subject altogether
    358                                         flow.subjects.remove( delete )
     257                                def subjectToRemove = flow.study.subjects.find { it.identifier == (params.get('do') as int) }
     258                                if (subjectToRemove) {
     259                                        flow.study.deleteSubject( subjectToRemove )
    359260                                }
    360261                        }.to "subjects"
    361262                        on("previous") {
    362                                 flash.errors = [:]
    363 
    364                                 // handle form data
    365                                 if (!this.handleSubjects(flow, flash, params)) {
    366                                         error()
    367                                 } else {
    368                                         success()
    369                                 }
     263                                // handle form data
     264                                subjectPage(flow, flash, params)
     265
     266                                // reset errors
     267                                flash.errors = [:]
     268                                success()
    370269                        }.to "study"
    371270                        on("next") {
    372                                 flash.errors = [:]
    373 
    374                                 // check form data
    375                                 if (!this.handleSubjects(flow, flash, params)) {
    376                                         error()
    377                                 } else {
    378                                         success()
    379                                 }
     271                                // handle form data
     272                                subjectPage(flow, flash, params) ? success() : error()
    380273                        }.to "events"
    381274                        on("quickSave") {                               
    382                                 flash.errors = [:]
    383 
    384                                 // check form data
    385                                 if (!this.handleSubjects(flow, flash, params)) {
    386                                         error()
    387                                 } else {
    388                                         success()
    389                                 }
     275                                // handle form data
     276                                subjectPage(flow, flash, params) ? success() : error()
    390277                        }.to "waitForSave"
    391278                }
     
    397284                                flow.page = 4
    398285
    399                                 if (!flow.event) {
    400                                         flow.event                      = new Event()
    401                                         flow.events                     = [:]
    402                                         flow.eventGroups        = [ new EventGroup(name: 'Group 1') ]
    403                                         flow.eventTemplates     = [:]
    404 
    405                                         // add initial eventGroup to study
    406                                         flow.study.addToEventGroups( flow.eventGroups[ 0 ] )
    407                                 } else if (!flash.values) {
    408                                         // set flash.values.templateType based on the event instance
    409                                         flash.values = [:]
    410                                         flash.values.templateType = (flow.event instanceof Event) ? 'event' : 'sample'
    411                                 }
     286                                // add initial eventGroup to study
     287                                if (!flow.study.eventGroups?.size()) {
     288                                        flow.study.addToEventGroups(
     289                                                new EventGroup(name: 'Group 1')
     290                                        )
     291                                }
     292
    412293                                success()
    413294                        }
    414295                        on("clear") {
    415                                 flow.remove('event')
     296                                // remove all events
     297                                (flow.study.events + flow.study.samplingEvents).each() { event ->
     298                                        if (event instanceof SamplingEvent) {
     299                                                flow.study.deleteSamplingEvent( event )
     300                                        } else {
     301                                                flow.study.deleteEvent( event )
     302                                        }
     303                                }
     304
    416305                                success()
    417306                        }.to "events"
    418307                        on("switchTemplate") {
    419                                 flash.values = params
    420 
    421                                 // handle study data
    422                                 this.handleEvents(flow, flash, params)
    423 
    424                                 // refresh event templates
    425                                 flow.eventTemplates.each() {
    426                                         it.value.template.refresh()
    427                                 }
    428 
    429                                 // refresh flow template
    430                                 if (flow.event.template) flow.event.template.refresh()
    431 
    432                                 // remove errors as we don't want any warnings now
    433                                 flash.errors = [:]
     308                                // handle form data
     309                                eventPage(flow, flash, params)
     310
     311                                // get template
     312                                def type        = params.get('eventType')
     313                                def template= Template.findByName( params.get( type + 'Template' ) )
     314
     315                                // change template and/or instance?
     316                                if (!flow.event || (flow.event instanceof Event && type == "sample") || (flow.event instanceof SamplingEvent && type == "event")) {
     317                                        // create new instance
     318                                        flow.event = (type == "event") ? new Event(template: template, parent: flow.study) : new SamplingEvent(template: template, parent: flow.study)
     319                                } else {
     320                                        flow.event.template = template
     321                                }
     322
     323                                // reset errors
     324                                flash.errors = [:]
     325                                success()
     326
    434327                        }.to "events"
    435328                        on("refresh") {
    436                                 flash.values = params
    437 
    438                                 // handle study data
    439                                 this.handleEvents(flow, flash, params)
     329                                // handle form data
     330                                eventPage(flow, flash, params)
    440331
    441332                                // refresh templates
    442                                 flow.eventTemplates.each() {
    443                                         it.value.template.refresh()
    444                                 }
    445 
    446                                 // refresh flow template
    447                                 if (flow.event.template) flow.event.template.refresh()
    448 
    449                                 // remove errors as we don't want any warnings now
    450                                 flash.errors = [:]
     333                                flow.study.giveEventTemplates().each() {
     334                                        it.refresh()
     335                                }
     336
     337                                // refresh event template
     338                                if (flow.event?.template) flow.event.template.refresh()
     339
     340                                // reset errors
     341                                flash.errors = [:]
     342                                success()
    451343                        }.to "events"
    452344                        on("add") {
    453                                 flash.values                    = params
    454                                 def eventTemplateName   = (params.get('eventType') == 'event') ? params.get('eventTemplate') : params.get('sampleTemplate')
    455                                 def eventTemplate               = Template.findByName(eventTemplateName)
    456 
    457                                 // handle study data
    458                                 this.handleEvents(flow, flash, params)
    459 
    460                                 // add event to study
    461                                 if (flow.event instanceof SamplingEvent) {
    462                                         flow.study.addToSamplingEvents( flow.event )
    463                                 } else {
    464                                         flow.study.addToEvents( flow.event )
    465                                 }
    466 
    467                                 // validate event object
     345                                // handle form data
     346                                eventPage(flow, flash, params)
     347
     348                                // reset errors
     349                                flash.errors = [:]
     350
     351                                // validate event
    468352                                if (flow.event.validate()) {
    469                                         // add this event template to the event template array
    470                                         if (!flow.eventTemplates[ eventTemplateName ]) {
    471                                                 flow.eventTemplates[ eventTemplateName ] = [
    472                                                         name: eventTemplateName,
    473                                                         template: eventTemplate,
    474                                                         events: []
    475                                                 ]
     353                                        // validates properly
     354                                        if (flow.event instanceof SamplingEvent) {
     355                                                flow.study.addToSamplingEvents( flow.event )
     356                                        } else {
     357                                                flow.study.addToEvents( flow.event )
    476358                                        }
    477359
    478                                         // ...store it in the events map in the flow scope...
    479                                         def increment   = flow.events.size()
    480                                         flow.events[ increment ] = flow.event
    481 
    482                                         // ...add it to the study...
    483                                         /*
    484                                         if (newEvent instanceof SamplingEvent) {
    485                                                 flow.study.addToSamplingEvents( newEvent )
    486                                         } else {
    487                                                 flow.study.addToEvents( newEvent )
    488                                         }
    489                                         */
    490 
    491                                         // ...and 'reset' the event object in the flow scope
    492                                         flow.event = new Event(template: flow.event.template)
     360                                        // remove event from the flowscope
     361                                        flow.remove('event')
    493362                                       
    494                                         // remember the event id with the template
    495                                         def eventSize = flow.eventTemplates[ eventTemplateName ]['events'].size()
    496                                         flow.eventTemplates[ eventTemplateName ]['events'][ eventSize ] = increment
    497 
    498363                                        success()
    499364                                } else {
    500                                         // it does not validate, remove event from study
    501                                         if (flow.event instanceof SamplingEvent) {
    502                                                 flow.study.removeFromSamplingEvents(flow.event)
    503                                         } else {
    504                                                 flow.study.removeFromEvents(flow.event)
    505                                         }
    506                                        
    507                                         // show error feedback
    508                                         flash.errors = [:]
     365                                        // event does not validate
    509366                                        this.appendErrors(flow.event, flash.errors)
    510367                                        error()
     
    512369                        }.to "events"
    513370                        on("deleteEvent") {
    514                                 flash.values = params
    515                                 def delete = params.get('do') as int
    516 
    517                                 // handle event groupings
    518                                 this.handleEventGrouping(flow, flash, params)
    519 
    520                                 // remove event
    521                                 if (flow.events[ delete ] && flow.events[ delete ] instanceof Event) {
    522                                         // remove it from the study
    523                                         if ( flow.events[ delete ] instanceof SamplingEvent ) {
    524                                                 flow.study.removeFromSamplingEvents( flow.events[ delete ] )
    525                                         } else {
    526                                                 flow.study.removeFromEvents( flow.events[ delete ] )
    527                                         }
    528 
    529                                         // remove it from the map
    530                                         flow.events.remove(delete)
    531                                         flow.eventTemplates.each() { eventTemplate ->
    532                                                 eventTemplate.value.events = eventTemplate.value.events.minus(delete)
    533                                         }
    534 
    535                                         // find eventTemplates without events
    536                                 flow.eventTemplates.find { eventTemplate ->
    537                                                 eventTemplate.value.events.size() < 1
    538                                         }.each() {
    539                                                 // remove eventTemplate
    540                                                 flow.eventTemplates.remove( it.value.name )
    541                                         }
    542                                 }
    543 
    544                                 success()
     371                                // handle form data
     372                                eventPage(flow, flash, params)
     373
     374                                // reset errors
     375                                flash.errors = [:]
     376
     377                                // find matching (sampling) event
     378                                def event                       = flow.study.events.find { it.getIdentifier() == (params.get('do') as int) }
     379                                def samplingEvent       = flow.study.samplingEvents.find { it.getIdentifier() == (params.get('do') as int) }
     380
     381                                // perform delete
     382                                if (event) flow.study.deleteEvent( event )
     383                                if (samplingEvent) flow.study.deleteSamplingEvent( samplingEvent )
    545384                        }.to "events"
    546385                        on("addEventGroup") {
    547                                 flash.values = params
    548                                
    549                                 // handle study data
    550                                 this.handleEvents(flow, flash, params)
    551 
    552                                 // handle event groupings
    553                                 this.handleEventGrouping(flow, flash, params)
    554 
    555                                 def increment = flow.eventGroups.size()
    556                                 def groupName = "Group " + (increment + 1)
    557 
    558                                 // check if group name exists
    559                                 def nameExists = true
    560                                 def u = 0
    561 
    562                                 // make sure a unique name is generated
    563                                 while (nameExists) {
    564                                         u++
    565                                         def count = 0
    566                                        
    567                                         flow.eventGroups.each() {
    568                                                 if (it.name == groupName) {
    569                                                         groupName = "Group " + (increment + 1) + "," + u
    570                                                 } else {
    571                                                         count++
     386                                // handle form data
     387                                eventPage(flow, flash, params)
     388
     389                                // first find the current maximum default name "Subject xxxx"
     390                                def eventGroupNo = 0
     391                                def eventGroupMax = 0
     392                                flow.study.eventGroups.each() {
     393                                        it.name.trim().eachMatch(/(\d+)$/){
     394                                                eventGroupNo = it[1] as int
     395                                                if (eventGroupNo > eventGroupMax) {
     396                                                        eventGroupMax = eventGroupNo
    572397                                                }
    573398                                        }
    574 
    575                                         nameExists = !(count == flow.eventGroups.size())
    576                                 }
    577 
    578                                 // remember eventGroup
    579                                 flow.eventGroups[ increment ] = new EventGroup( name: groupName )
    580 
    581                                 // and add the group to the study
    582                                 flow.study.addToEventGroups( flow.eventGroups[ increment ] )
    583 
     399                                }
     400
     401                                // add a new eventGroup
     402                                flow.study.addToEventGroups(
     403                                        new EventGroup(
     404                                                name    : 'Group ' + (eventGroupMax+1),
     405                                                parent  : flow.study
     406                                        )
     407                                )
     408
     409                                // reset errors
     410                                flash.errors = [:]
    584411                                success()
    585412                        }.to "events"
    586413                        on("deleteEventGroup") {
    587                                 flash.values = params
    588                                 def delete = params.get('do') as int
    589 
    590                                 // handle event groupings
    591                                 this.handleEventGrouping(flow, flash, params)
    592 
    593                                 // remove the group with this specific id
    594                                 if (flow.eventGroups[delete] && flow.eventGroups[delete] instanceof EventGroup) {
    595                                         // remove the eventGroup from the study
    596                                         flow.study.removeFromEventGroups( flow.eventGroups[ delete ] )
    597 
    598                                         // remove this eventGroup
    599                                         flow.eventGroups.remove(delete)
    600                                 }
    601 
    602                                 success()
     414                                // handle form data
     415                                eventPage(flow, flash, params)
     416
     417                                // reset errors
     418                                flash.errors = [:]
     419
     420                                // remove eventGroup
     421                                def eventGroupToRemove = flow.study.eventGroups.find { it.getIdentifier() == (params.get('do') as int) }
     422                                if (eventGroupToRemove) {
     423                                        flow.study.deleteEventGroup( eventGroupToRemove )
     424                                }
    603425                        }.to "events"
    604426                        on("previous") {
    605                                 // handle event groupings
    606                                 this.handleEventGrouping(flow, flash, params)
     427                                // handle form data
     428                                eventPage(flow, flash, params)
     429
     430                                // reset errors
     431                                flash.errors = [:]
     432                                success()
    607433                        }.to "subjects"
    608434                        on("next") {
    609                                 flash.values = params
    610                                 flash.errors = [:]
    611 
    612                                 // handle study data
    613                                 /* turned off by request of Kees / Leny / Jildau
    614                                 if (!flow.eventTemplates.find { eventTemplate -> eventTemplate.value.template.entity == SamplingEvent }) {
    615                                         // append error map
    616                                         this.appendErrorMap(['events': 'You need to create at least one sampling event for your study'], flash.errors)
    617                                         error()                                         
    618                                 } else
    619                                 */
    620                                 if (this.handleEvents(flow, flash, params)) {
    621                                         success()
    622                                 } else {
    623                                         error()
    624                                 }
     435                                // handle form data
     436                                eventPage(flow, flash, params) ? success() : error()
    625437                        }.to "groups"
    626438                        on("quickSave") {
    627                                 flash.values = params
    628                                 flash.errors = [:]
    629 
    630                                 // handle study data
    631                                 /* turned off by request of Kees / Leny / Jildau
    632                                 if (!flow.eventTemplates.find { eventTemplate -> eventTemplate.value.template.entity == SamplingEvent }) {
    633                                         // append error map
    634                                         this.appendErrorMap(['events': 'You need to create at least one sampling event for your study'], flash.errors)
    635                                         error()
    636                                 } else
    637                                 */
    638                                 if (this.handleEvents(flow, flash, params)) {
    639                                         success()
    640                                 } else {
    641                                         error()
    642                                 }
     439                                // handle form data
     440                                eventPage(flow, flash, params) ? success() : error()
    643441                        }.to "waitForSave"
    644442                }
     
    652450                        }
    653451                        on("previous") {
    654                                 this.handleSubjectGrouping(flow, flash, params)
    655                                 success()
     452                                // handle form data
     453                                groupPage(flow, flash, params) ? success() : error()
    656454                        }.to "events"
    657455                        on("next") {
    658                                 this.handleSubjectGrouping(flow, flash, params)
    659                                 flash.check = true
    660                                 success()
    661                         }.to "samples"
     456                                // handle form data
     457                                groupPage(flow, flash, params) ? success() : error()
     458                        }.to "waitForSave"
    662459                        on("quickSave") {
    663                                 this.handleSubjectGrouping(flow, flash, params)
    664                                 success()
     460                                // handle form data
     461                                groupPage(flow, flash, params) ? success() : error()
    665462                        }.to "waitForSave"
    666463                }
     
    694491                        onRender {
    695492                                flow.page = 6
    696 
     493                                /*
    697494                                // iterate through eventGroups
    698495                                if (!flow.samples) {
     
    739536
    740537                                success()
     538                                */
    741539                        }
    742540                        on("switchTemplate") {
     
    854652                                // persist data to the database
    855653                                try {
    856                                         // user modifying?
    857                                         if (flow.quickSave && grails.util.GrailsUtil.environment == 'production') {
    858                                                 // yes, not allowed on production as this results in data inconsistency
    859                                                 println ".saving is not allowed in study edit wizard"
    860                                                 throw new Exception("Saving is not allowed in the edit study wizard because this leads to data inconsistency in the database!")
    861                                         }
    862 
    863654                                        // save study
    864655                                        println ".saving study"
     
    921712                        flow.study = (params.studyid) ? Study.findById( params.studyid ) : Study.findByTitle( params.study )
    922713
    923                         // recreate subjects
    924                         flow.subjects = [:]
    925                         flow.subjectTemplates = [:]
    926                         flow.study.subjects.each() { subject ->
    927                                 def subjectIncrement = flow.subjects.size()
    928                                 flow.subjects[subjectIncrement] = subject
    929 
    930                                 // add subject template?
    931                                 if (!flow.subjectTemplates[subject.template.name]) {
    932                                         flow.subjectTemplates[subject.template.name] = [
    933                                                 name: subject.template.name,
    934                                                 template: subject.template,
    935                                                 subjects: [:]
    936                                         ]
    937                                 }
    938 
    939                                 // reference subject in template
    940                                 flow.subjectTemplates[subject.template.name].subjects[flow.subjectTemplates[subject.template.name].subjects.size()] = subjectIncrement
    941                         }
    942 
    943                         // recreate events
    944                         flow.events = [:]
    945                         flow.eventGroups = []
    946                         flow.eventTemplates = [:]
    947                         flow.study.events.each() { event ->
    948                                 def eventIncrement = flow.events.size()
    949                                 flow.events[eventIncrement] = event
    950 
    951                                 // add event template?
    952                                 if (!flow.eventTemplates[event.template.name]) {
    953                                         flow.eventTemplates[event.template.name] = [
    954                                                 name: event.template.name,
    955                                                 template: event.template,
    956                                                 events: new ArrayList()
    957                                         ]
    958                                 }
    959 
    960                                 // reference event in template
    961                                 flow.eventTemplates[event.template.name].events[flow.eventTemplates[event.template.name].events.size()] = eventIncrement
    962 
    963                                 // set dummy event
    964                                 flow.event = event
    965                         }
    966 
    967                         // recreate sample events
    968                         flow.study.samplingEvents.each() { event ->
    969                                 def eventIncrement = flow.events.size()
    970                                 flow.events[eventIncrement] = event
    971 
    972                                 // add event template?
    973                                 if (!flow.eventTemplates[event.template.name]) {
    974                                         flow.eventTemplates[event.template.name] = [
    975                                                 name: event.template.name,
    976                                                 template: event.template,
    977                                                 events: new ArrayList()
    978                                         ]
    979                                 }
    980 
    981                                 // reference event in template
    982                                 flow.eventTemplates[event.template.name].events[flow.eventTemplates[event.template.name].events.size()] = eventIncrement
    983 
    984                                 // set dummy event
    985                                 flow.event = event
    986                         }
    987 
    988                         // recreate eventGroups
    989                         flow.study.eventGroups.each() { eventGroup ->
    990                                 flow.eventGroups[flow.eventGroups.size()] = eventGroup
    991                         }
    992 
    993714                        // set 'quicksave' variable
    994715                        flow.quickSave = true
     
    1002723                }
    1003724        }
    1004 
    1005         /**
    1006          * re-usable code for handling study form data in a web flow
    1007          * @param Map LocalAttributeMap (the flow scope)
    1008          * @param Map localAttributeMap (the flash scope)
    1009          * @param Map GrailsParameterMap (the flow parameters = form data)
    1010          * @returns boolean
    1011          */
    1012         def handleStudy(flow, flash, params) {
    1013                 // create study instance if we have none
    1014                 if (!flow.study) flow.study = new Study()
    1015 
    1016                 // create date instance from date string?
    1017                 // @see WizardTagLibrary::dateElement{...}
    1018                 if (params.get('startDate')) {
    1019                         params.startDate = new Date().parse("d/M/yyyy", params.get('startDate').toString())
    1020                 } else {
    1021                         params.remove('startDate')
    1022                 }
    1023 
    1024                 // if a template is selected, get template instance
    1025                 def template = params.remove('template')
    1026                 if (template instanceof String && template.size() > 0) {
    1027                         flow.study.template = Template.findByName(template)
    1028                 } else if (template instanceof Template) {
    1029                         flow.study.template = template
    1030                 }
    1031 
    1032                 // iterate through fields
    1033                 if (flow.study.template) {
    1034                         flow.study.giveFields().each() {
    1035                                 flow.study.setFieldValue(it.name, params.get(it.escapedName()))
    1036                         }
    1037                 }
    1038 
    1039                 // handle Publications and Contacts
    1040                 handlePublications(flow, flash, params)
    1041                 handleContacts(flow, flash, params)
    1042 
    1043                 // validate study
    1044                 if (flow.study.validate()) {
    1045                         return true
    1046                 } else {
    1047                         // validation failed, feedback errors
    1048                         flash.errors = [:]
    1049                         this.appendErrors(flow.study, flash.errors)
    1050                         return false
    1051                 }
    1052         }
    1053 
    1054         /**
    1055          * re-usable code for handling publications form data in a web flow
    1056          * @param Map LocalAttributeMap (the flow scope)
    1057          * @param Map localAttributeMap (the flash scope)
    1058          * @param Map GrailsParameterMap (the flow parameters = form data)
    1059          * @returns boolean
    1060          */
    1061         def handlePublications(flow, flash, params) {
    1062                 // create study instance if we have none
    1063                 if (!flow.study) flow.study = new Study()
    1064                 if (!flow.study.publications) flow.study.publications = []
    1065 
    1066                 // Check the ids of the pubblications that should be attached
    1067                 // to this study. If they are already attached, keep 'm. If
    1068                 // studies are attached that are not in the selected (i.e. the
    1069                 // user deleted them), remove them
    1070                 def publicationIDs = params.get('publication_ids')
    1071                 if (publicationIDs) {
    1072                         // Find the individual IDs and make integers
    1073                         publicationIDs = publicationIDs.split(',').collect { Integer.parseInt(it, 10) }
    1074 
    1075                         // First remove the publication that are not present in the array
    1076                         flow.study.publications.removeAll { publication -> !publicationIDs.find { id -> id == publication.id } }
    1077 
    1078                         // Add those publications not yet present in the database
    1079                         publicationIDs.each { id ->
    1080                                 if (!flow.study.publications.find { publication -> id == publication.id }) {
    1081                                         def publication = Publication.get(id)
    1082                                         if (publication) {
    1083                                                 flow.study.addToPublications(publication)
    1084                                         } else {
    1085                                                 println('.publication with ID ' + id + ' not found in database.')
    1086                                         }
    1087                                 }
    1088                         }
    1089 
    1090                 } else {
    1091                         println('.no publications selected.')
    1092                         flow.study.publications.clear()
    1093                 }
    1094 
    1095         }
    1096 
    1097         /**
    1098          * re-usable code for handling contacts form data in a web flow
    1099          * @param Map LocalAttributeMap (the flow scope)
    1100          * @param Map localAttributeMap (the flash scope)
    1101          * @param Map GrailsParameterMap (the flow parameters = form data)
    1102          * @return boolean
    1103          */
    1104         def handleContacts(flow, flash, params) {
    1105                 // create study instance if we have none
    1106                 if (!flow.study) flow.study = new Study()
    1107                 if (!flow.study.persons) flow.study.persons = []
    1108 
    1109                 // Check the ids of the contacts that should be attached
    1110                 // to this study. If they are already attached, keep 'm. If
    1111                 // studies are attached that are not in the selected (i.e. the
    1112                 // user deleted them), remove them
    1113 
    1114                 // Contacts are saved as [person_id]-[role_id]
    1115                 def contactIDs = params.get('contacts_ids')
    1116                 if (contactIDs) {
    1117                         // Find the individual IDs and make integers
    1118                         contactIDs = contactIDs.split(',').collect {
    1119                                 def parts = it.split('-')
    1120                                 return [person: Integer.parseInt(parts[0]), role: Integer.parseInt(parts[1])]
    1121                         }
    1122 
    1123                         // First remove the contacts that are not present in the array
    1124                         flow.study.persons.removeAll {
    1125                                 studyperson -> !contactIDs.find { ids -> (ids.person == studyperson.person.id) && (ids.role == studyperson.role.id) }
    1126                         }
    1127 
    1128                         // Add those contacts not yet present in the database
    1129                         contactIDs.each { ids ->
    1130                                 if (!flow.study.persons.find { studyperson -> (ids.person == studyperson.person.id) && (ids.role == studyperson.role.id) }) {
    1131                                         def person = Person.get(ids.person)
    1132                                         def role = PersonRole.get(ids.role)
    1133                                         if (person && role) {
    1134                                                 // Find a studyperson object with these parameters
    1135                                                 def studyPerson = StudyPerson.findAll().find { studyperson -> studyperson.person.id == person.id && studyperson.role.id == role.id }
    1136 
    1137                                                 // If if does not yet exist, save the example
    1138                                                 if (!studyPerson) {
    1139                                                         studyPerson = new StudyPerson(
    1140                                                                 person: person,
    1141                                                                 role: role
    1142                                                         )
    1143                                                         studyPerson.save(flush: true)
    1144                                                 }
    1145 
    1146                                                 flow.study.addToPersons(studyPerson)
    1147                                         } else {
    1148                                                 println('.person ' + ids.person + ' or Role ' + ids.role + ' not found in database.')
    1149                                         }
    1150                                 }
    1151                         }
    1152                 } else {
    1153                         println('.no persons selected.')
    1154                         flow.study.persons.clear()
    1155                 }
    1156 
    1157         }
    1158 
    1159         /**
    1160          * re-usable code for handling subject form data in a web flow
    1161          * @param Map LocalAttributeMap (the flow scope)
    1162          * @param Map localAttributeMap (the flash scope)
    1163          * @param Map GrailsParameterMap (the flow parameters = form data)
    1164          * @return boolean
    1165          */
    1166         def handleSubjects(flow, flash, params) {
    1167                 def names = [:]
    1168                 def errors = false
    1169                 def id = 0
    1170 
    1171                 // iterate through subject templates
    1172                 flow.subjectTemplates.each() { subjectTemplate ->
    1173                         // iterate through subjects
    1174                         subjectTemplate.value.subjects.each() { subjectIncrement, subjectId ->
    1175                                 // iterate through fields (= template fields and domain properties)
    1176                                 flow.subjects[ subjectId ].giveFields().each() { subjectField ->
    1177                                         // set the field
    1178                                         flow.subjects[ subjectId ].setFieldValue(
    1179                                                 subjectField.name,
    1180                                                 params.get( 'subject_' + subjectId + '_' + subjectField.escapedName() )
    1181                                         )
    1182                                 }
    1183 
    1184                                 // validate subject
    1185                                 if (!flow.subjects[ subjectId ].validate()) {
    1186                                         errors = true
    1187                                         this.appendErrors(flow.subjects[ subjectId ], flash.errors, 'subject_' + subjectId + '_')
    1188                                 }
    1189                         }
    1190                 }
    1191 
    1192                 return !errors
    1193         }
    1194 
    1195         /**
    1196          * re-usable code for handling event form data in a web flow
    1197          * @param Map LocalAttributeMap (the flow scope)
    1198          * @param Map localAttributeMap (the flash scope)
    1199          * @param Map GrailsParameterMap (the flow parameters = form data)
    1200          * @return boolean
    1201          */
    1202         def handleEvents(flow, flash, params) {
    1203                 def errors = false
    1204                 def template = null
    1205 
    1206                 // handle the type of event
    1207                 if (params.eventType == 'event') {
    1208                         flow.event = new Event()
    1209                         template = params.remove('eventTemplate')
    1210                 } else if (params.eventType == 'sample') {
    1211                         flow.event = new SamplingEvent()
    1212                         template = params.remove('sampleTemplate')
    1213                 }
    1214 
    1215                 // if a template is selected, get template instance
    1216                 if (template instanceof String && template.size() > 0) {
    1217                         params.template = Template.findByName(template)
    1218                 } else if (template instanceof Template) {
    1219                         params.template = template
    1220                 } else {
    1221                         params.template = null
    1222                 }
    1223 
    1224                 // set template
    1225                 if (params.template) flow.event.template = params.template
    1226 
    1227                 // update event instance with parameters
    1228                 flow.event.giveFields().each() { eventField ->
    1229                         flow.event.setFieldValue(eventField.name, params[ eventField.escapedName() ])   
    1230                 }
    1231 
    1232                 // handle event objects
    1233                 flow.eventTemplates.each() { eventTemplate ->
    1234                         // iterate through events
    1235                         eventTemplate.getValue().events.each() { eventId ->
    1236                                 // iterate through template fields
    1237                                 flow.events[ eventId ].giveFields().each() { eventField ->
    1238                                         if ( params.containsKey( 'event_' + eventId + '_' + eventField.escapedName() ) ) {
    1239                                                 flow.events[ eventId ].setFieldValue(eventField.name, params.get( 'event_' + eventId + '_' + eventField.escapedName() ) )
    1240                                         }
    1241                                 }
    1242 
    1243                                 // validate event
    1244                                 if (!flow.events[ eventId ].validate()) {
    1245                                         errors = true
    1246                                         this.appendErrors(flow.events[ eventId ], flash.errors, 'event_' + eventId + '_')
    1247                                 }
    1248                         }
    1249                 }
    1250 
    1251                 // handle event grouping
    1252                 handleEventGrouping(flow, flash, params)
    1253 
    1254                 return !errors
    1255         }
    1256 
    1257         /**
    1258          * re-usable code for handling event grouping in a web flow
    1259          * @param Map LocalAttributeMap (the flow scope)
    1260          * @param Map localAttributeMap (the flash scope)
    1261          * @param Map GrailsParameterMap (the flow parameters = form data)
    1262          * @return boolean
    1263          */
    1264         def handleEventGrouping(flow, flash, params) {
    1265                 // walk through eventGroups
    1266                 def g = 0
    1267                 flow.eventGroups.each() { eventGroup ->
    1268                         def e = 0
    1269 
    1270                         // reset events
    1271                         eventGroup.events = new HashSet()
    1272 
    1273                         // iterate through events
    1274                         flow.events.each() {
    1275                                 if (params.get('event_' + e + '_group_' + g) == 'on') {
    1276                                         // add event to eventgroup
    1277                                         if (it.value instanceof SamplingEvent) {
    1278                                                 eventGroup.addToSamplingEvents(it.value)
    1279                                         } else {
    1280                                                 eventGroup.addToEvents(it.value)
    1281                                         }
    1282                                 }
    1283                                 e++
    1284                         }
    1285                         g++
    1286                 }
    1287         }
    1288 
    1289         /**
    1290          * re-usable code for handling subject grouping in a web flow
    1291          * @param Map LocalAttributeMap (the flow scope)
    1292          * @param Map localAttributeMap (the flash scope)
    1293          * @param Map GrailsParameterMap (the flow parameters = form data)
    1294          * @return boolean
    1295          */
    1296         def handleSubjectGrouping(flow, flash, params) {
    1297                 // iterate through event groups
    1298                 def g = 0
    1299                 flow.eventGroups.each() { eventGroup ->
    1300                         // reset subjects
    1301                         eventGroup.subjects = new HashSet()
    1302 
    1303                         // iterate through subjects
    1304                         flow.subjects.each() { subjectId, subject ->
    1305                                 // is this combination set?
    1306                                 if (params.get('subject_' + subjectId + '_group_' + g) != null) {
    1307                                         eventGroup.addToSubjects(subject)
    1308                                 }
    1309                         }
    1310 
    1311                         g++
    1312                 }
    1313         }
    1314 
    1315725
    1316726        /**
     
    1525935                );
    1526936        }
     937
     938
     939        /****** REFACTORED METHODS OVER HERE! ******/
     940
     941        /**
     942         * Handle the wizard study page
     943         *
     944         * @param Map LocalAttributeMap (the flow scope)
     945         * @param Map localAttributeMap (the flash scope)
     946         * @param Map GrailsParameterMap (the flow parameters = form data)
     947         * @returns boolean
     948         */
     949        def studyPage(flow, flash, params) {
     950                // remember the params in the flash scope
     951                flash.values = params
     952               
     953                // instantiate study of it is not yet present
     954                if (!flow.study) flow.study = new Study()
     955
     956                // did the study template change?
     957                if (params.get('template').size() && flow.study.template?.name != params.get('template')) {
     958                        println ".change study template!"
     959
     960                        // yes, was the template already set?
     961                        if (flow.study.template instanceof Template) {
     962                                // yes, first make sure all values are unset?
     963                                println "!!! check the database fields if data of a previous template remains in the database or is deleted by GORM!"
     964                        }
     965
     966                        // set the template
     967                        flow.study.template = Template.findByName(params.remove('template'))
     968                }
     969
     970                // does the study have a template set?
     971                if (flow.study.template && flow.study.template instanceof Template) {
     972                        // yes, iterate through template fields
     973                        flow.study.giveFields().each() {
     974                                // and set their values
     975                                flow.study.setFieldValue(it.name, params.get(it.escapedName()))
     976                        }
     977                }
     978
     979                // handle publications
     980                handlePublications(flow, flash, params)
     981
     982                // handle contacts
     983                handleContacts(flow, flash, params)
     984
     985                // validate the study
     986                if (flow.study.validate()) {
     987                        // instance is okay
     988                        return true
     989                } else {
     990                        // validation failed
     991                        flash.errors = [:]
     992                        this.appendErrors(flow.study, flash.errors)
     993                        return false
     994                }
     995        }
     996
     997        /**
     998         * re-usable code for handling publications form data in a web flow
     999         * @param Map LocalAttributeMap (the flow scope)
     1000         * @param Map localAttributeMap (the flash scope)
     1001         * @param Map GrailsParameterMap (the flow parameters = form data)
     1002         * @returns boolean
     1003         */
     1004        def handlePublications(flow, flash, params) {
     1005                if (!flow.study.publications) flow.study.publications = []
     1006
     1007                // Check the ids of the pubblications that should be attached
     1008                // to this study. If they are already attached, keep 'm. If
     1009                // studies are attached that are not in the selected (i.e. the
     1010                // user deleted them), remove them
     1011                def publicationIDs = params.get('publication_ids')
     1012                if (publicationIDs) {
     1013                        // Find the individual IDs and make integers
     1014                        publicationIDs = publicationIDs.split(',').collect { Integer.parseInt(it, 10) }
     1015
     1016                        // First remove the publication that are not present in the array
     1017                        flow.study.publications.removeAll { publication -> !publicationIDs.find { id -> id == publication.id } }
     1018
     1019                        // Add those publications not yet present in the database
     1020                        publicationIDs.each { id ->
     1021                                if (!flow.study.publications.find { publication -> id == publication.id }) {
     1022                                        def publication = Publication.get(id)
     1023                                        if (publication) {
     1024                                                flow.study.addToPublications(publication)
     1025                                        } else {
     1026                                                println('.publication with ID ' + id + ' not found in database.')
     1027                                        }
     1028                                }
     1029                        }
     1030
     1031                } else {
     1032                        println('.no publications selected.')
     1033                        flow.study.publications.clear()
     1034                }
     1035
     1036        }
     1037
     1038        /**
     1039         * re-usable code for handling contacts form data in a web flow
     1040         * @param Map LocalAttributeMap (the flow scope)
     1041         * @param Map localAttributeMap (the flash scope)
     1042         * @param Map GrailsParameterMap (the flow parameters = form data)
     1043         * @return boolean
     1044         */
     1045        def handleContacts(flow, flash, params) {
     1046                if (!flow.study.persons) flow.study.persons = []
     1047
     1048                // Check the ids of the contacts that should be attached
     1049                // to this study. If they are already attached, keep 'm. If
     1050                // studies are attached that are not in the selected (i.e. the
     1051                // user deleted them), remove them
     1052
     1053                // Contacts are saved as [person_id]-[role_id]
     1054                def contactIDs = params.get('contacts_ids')
     1055                if (contactIDs) {
     1056                        // Find the individual IDs and make integers
     1057                        contactIDs = contactIDs.split(',').collect {
     1058                                def parts = it.split('-')
     1059                                return [person: Integer.parseInt(parts[0]), role: Integer.parseInt(parts[1])]
     1060                        }
     1061
     1062                        // First remove the contacts that are not present in the array
     1063                        flow.study.persons.removeAll {
     1064                                studyperson -> !contactIDs.find { ids -> (ids.person == studyperson.person.id) && (ids.role == studyperson.role.id) }
     1065                        }
     1066
     1067                        // Add those contacts not yet present in the database
     1068                        contactIDs.each { ids ->
     1069                                if (!flow.study.persons.find { studyperson -> (ids.person == studyperson.person.id) && (ids.role == studyperson.role.id) }) {
     1070                                        def person = Person.get(ids.person)
     1071                                        def role = PersonRole.get(ids.role)
     1072                                        if (person && role) {
     1073                                                // Find a studyperson object with these parameters
     1074                                                def studyPerson = StudyPerson.findAll().find { studyperson -> studyperson.person.id == person.id && studyperson.role.id == role.id }
     1075
     1076                                                // If if does not yet exist, save the example
     1077                                                if (!studyPerson) {
     1078                                                        studyPerson = new StudyPerson(
     1079                                                                person: person,
     1080                                                                role: role
     1081                                                        )
     1082                                                        studyPerson.save(flush: true)
     1083                                                }
     1084
     1085                                                flow.study.addToPersons(studyPerson)
     1086                                        } else {
     1087                                                println('.person ' + ids.person + ' or Role ' + ids.role + ' not found in database.')
     1088                                        }
     1089                                }
     1090                        }
     1091                } else {
     1092                        println('.no persons selected.')
     1093                        flow.study.persons.clear()
     1094                }
     1095
     1096        }
     1097
     1098        /**
     1099         * Handle the wizard subject page
     1100         *
     1101         * @param Map LocalAttributeMap (the flow scope)
     1102         * @param Map localAttributeMap (the flash scope)
     1103         * @param Map GrailsParameterMap (the flow parameters = form data)
     1104         * @returns boolean
     1105         */
     1106        def subjectPage(flow, flash, params) {
     1107                def errors = false
     1108                flash.errors = [:]
     1109
     1110                // remember the params in the flash scope
     1111                flash.values = params
     1112
     1113                // iterate through subjects
     1114                flow.study.subjects.each() { subject ->
     1115                        // iterate through (template and domain) fields
     1116                        subject.giveFields().each() { field ->
     1117                                // set field
     1118                                subject.setFieldValue(
     1119                                        field.name,
     1120                                        params.get('subject_' + subject.getIdentifier() + '_' + field.escapedName())
     1121                                )
     1122                        }
     1123
     1124                        // validate subject
     1125                        if (!subject.validate()) {
     1126                                errors = true
     1127                                this.appendErrors(subject, flash.errors, 'subject_' + subject.getIdentifier() + '_')
     1128                        }
     1129                }
     1130
     1131                return !errors
     1132        }
     1133
     1134        /**
     1135         * Add a number of subjects to a study
     1136         *
     1137         * required params entities:
     1138         * -addNumber (int)
     1139         * -species   (string)
     1140         * -template  (string)
     1141         *
     1142         * @param Map LocalAttributeMap (the flow scope)
     1143         * @param Map localAttributeMap (the flash scope)
     1144         * @param Map GrailsParameterMap (the flow parameters = form data)
     1145         * @returns boolean
     1146         */
     1147        def addSubjects(flow, flash, params) {
     1148                // remember the params in the flash scope
     1149                flash.values = params
     1150
     1151                // handle the subject page
     1152                subjectPage(flow, flash, params)
     1153
     1154                // (re)set error message
     1155                flash.errors = [:]
     1156
     1157                // set work variables
     1158                def errors              = false
     1159                def number              = params.get('addNumber') as int
     1160                def species             = Term.findByName(params.get('species'))
     1161                def template    = Template.findByName(params.get('template'))
     1162                def subjectNo   = 0
     1163                def subjectMax  = 0
     1164
     1165                // can we add subjects?
     1166                if (number > 0 && species && template) {
     1167                        // first find the current maximum default name "Subject xxxx"
     1168                        flow.study.subjects.each() {
     1169                                it.name.trim().eachMatch(/(\d+)$/){
     1170                                        subjectNo = it[1] as int
     1171                                        if (subjectNo > subjectMax) {
     1172                                                subjectMax = subjectNo
     1173                                        }
     1174                                }
     1175                        }
     1176
     1177                        // add subjects to study
     1178                        number.times {
     1179                                subjectMax++
     1180                               
     1181                                // create a subject instance
     1182                                def subject = new Subject(
     1183                                        name            : 'Subject ' + subjectMax,
     1184                                        species         : species,
     1185                                        template        : template,
     1186                                        parent          : flow.study
     1187                                )
     1188
     1189                                // validate subject
     1190                                if (subject.validate()) {
     1191                                        // add it to the study
     1192                                        flow.study.addToSubjects( subject )
     1193                                        println ".added subject "+subject
     1194                                } else {
     1195                                        // whoops?
     1196                                        this.appendErrors(subject, flash.errors)
     1197                                        errors = true
     1198                                }
     1199                        }
     1200                } else {
     1201                        // add feedback
     1202                        errors = true
     1203                        if (number < 1) this.appendErrorMap(['addNumber': 'Enter a positive number of subjects to add'], flash.errors)
     1204                        if (!species)   this.appendErrorMap(['species': 'You need to select a species, or add one if it is not yet present'], flash.errors)
     1205                        if (!template)  this.appendErrorMap(['template': 'You need to select a template, or add one if it is not yet present'], flash.errors)
     1206                }
     1207
     1208                return !errors
     1209        }
     1210
     1211        /**
     1212         * Handle the wizard event page
     1213         *
     1214         * @param Map LocalAttributeMap (the flow scope)
     1215         * @param Map localAttributeMap (the flash scope)
     1216         * @param Map GrailsParameterMap (the flow parameters = form data)
     1217         * @returns boolean
     1218         */
     1219        def eventPage(flow, flash, params) {
     1220                def errors = false
     1221                flash.errors = [:]
     1222
     1223                // remember the params in the flash scope
     1224                flash.values = params
     1225
     1226                // handle the 'add event' form
     1227                if (flow.event) {
     1228                        flow.event.giveFields().each() { field ->
     1229                                // set field
     1230                                flow.event.setFieldValue(
     1231                                        field.name,
     1232                                        params.get(field.escapedName())
     1233                                )
     1234                        }
     1235                }
     1236
     1237                // handle the eventGroup names and grouping
     1238                def name        = ""
     1239                def tempName= ""
     1240                flow.study.eventGroups.each() { eventGroup ->
     1241                        // iterate through templates
     1242                        flow.study.giveAllEventTemplates().each() { template ->
     1243                                tempName = params.get( 'eventGroup_' + eventGroup.getIdentifier() + '_' + template.getIdentifier() )
     1244
     1245                                // is the name different?
     1246                                if (tempName != eventGroup.name) {
     1247                                        name = tempName
     1248                                }
     1249                        }
     1250
     1251                        // should the name change?
     1252                        if (name) {
     1253                                // yes, change it
     1254                                eventGroup.name = name
     1255                                name = ""
     1256                        }
     1257
     1258                        // handle eventGrouping
     1259                        ( ((flow.study.events) ? flow.study.events : []) + ((flow.study.samplingEvents) ? flow.study.samplingEvents : []) ) .each() { event ->
     1260                                if (params.get( 'event_' + event.getIdentifier() + '_group_' + eventGroup.getIdentifier() )) {
     1261                                        // add to eventGroup
     1262                                        if (event instanceof SamplingEvent) {
     1263                                                eventGroup.addToSamplingEvents(event)
     1264                                        } else {
     1265                                                eventGroup.addToEvents(event)
     1266                                        }
     1267                                } else {
     1268                                        // remove from eventGroup
     1269                                        if (event instanceof SamplingEvent) {
     1270                                                eventGroup.removeFromSamplingEvents(event)
     1271                                        } else {
     1272                                                eventGroup.removeFromEvents(event)
     1273                                        }
     1274                                }
     1275                        }
     1276                }
     1277
     1278                // handle the (sampling) events
     1279                ( ((flow.study.events) ? flow.study.events : []) + ((flow.study.samplingEvents) ? flow.study.samplingEvents : []) ) .each() { event ->
     1280                        event.giveFields().each() { field ->
     1281                                event.setFieldValue(
     1282                                        field.name,
     1283                                        params.get( 'event_' + event.getIdentifier() + '_' + field.escapedName())
     1284                                )
     1285                        }
     1286
     1287                        // validate event
     1288                        if (!event.validate()) {
     1289                                errors = true
     1290                                this.appendErrors(event, flash.errors)
     1291                        }
     1292                }
     1293
     1294                // handle eventGroup names
     1295                flow.study.eventGroups.each() { eventGroup ->
     1296                       
     1297                }
     1298
     1299                return !errors
     1300        }
     1301
     1302        /**
     1303         * Handle the wizard group page
     1304         *
     1305         * @param Map LocalAttributeMap (the flow scope)
     1306         * @param Map localAttributeMap (the flash scope)
     1307         * @param Map GrailsParameterMap (the flow parameters = form data)
     1308         * @returns boolean
     1309         */
     1310        def groupPage(flow, flash, params) {
     1311                def errors = false
     1312                flash.errors = [:]
     1313
     1314                // remember the params in the flash scope
     1315                flash.values = params
     1316
     1317                // iterate through groups
     1318                flow.study.eventGroups.each() { eventGroup ->
     1319                        // iterate through subjects
     1320                        flow.study.subjects.each() { subject ->
     1321                                if (params.get('subject_' + subject.getIdentifier() + '_group_' + eventGroup.getIdentifier() )) {
     1322                                        // add to eventGroup
     1323                                        eventGroup.addToSubjects(subject)
     1324                                } else {
     1325                                        // remove from eventGroup
     1326                                        eventGroup.removeFromSubjects(subject)
     1327                                }
     1328                        }
     1329                }
     1330        }
     1331
     1332        /**
     1333         * Handle the wizard samples page
     1334         *
     1335         * @param Map LocalAttributeMap (the flow scope)
     1336         * @param Map localAttributeMap (the flash scope)
     1337         * @param Map GrailsParameterMap (the flow parameters = form data)
     1338         * @returns boolean
     1339         */
     1340        def samplePage(flow, flash, params) {
     1341                def errors = false
     1342                flash.errors = [:]
     1343
     1344                // remember the params in the flash scope
     1345                flash.values = params
     1346
     1347                return !errors
     1348        }
    15271349}
  • trunk/grails-app/domain/dbnp/studycapturing/EventGroup.groovy

    r754 r778  
    1010 */
    1111class EventGroup implements Serializable {
    12 
    13         static belongsTo = [parent : Study]
    14 
    1512        String name
    1613
     14        // keep an internal identifier for use in dynamic forms
     15        private int identifier = 0
     16        static int iterator = 0
     17
     18        static transients = [ "identifier", "iterator" ]
     19        static belongsTo = [parent : Study]
    1720        static hasMany = [
    1821                subjects: Subject,
     
    2326        static constraints = {
    2427        }
     28
     29        /**
     30         * Class constructor increments that static iterator
     31         * and sets the object's identifier (used in dynamic webforms)
     32         * @void
     33         */
     34        public EventGroup() {
     35                if (!identifier) identifier = iterator++
     36        }
     37
     38        /**
     39         * Return the identifier
     40         * @return int
     41         */
     42        final public int getIdentifier() {
     43                return identifier
     44        }
    2545}
  • trunk/grails-app/domain/dbnp/studycapturing/Study.groovy

    r774 r778  
    100100        }
    101101
     102
     103        /**
     104         * Return all subjects for a specific template
     105         * @param Template
     106         * @return ArrayList
     107         */
     108        def ArrayList<Subject> giveSubjectsForTemplate(Template template) {
     109                subjects.findAll { it.template.equals(template) }
     110        }
     111
    102112        /**
    103113         * Return the unique Event and SamplingEvent templates that are used in this study
     
    107117                // gives trouble when asking .size() to the result
    108118                // So we also use giveTemplates here
    109                 TemplateEntity.giveTemplates(events + samplingEvents)
     119                TemplateEntity.giveTemplates( ((events) ? events : []) + ((samplingEvents) ? samplingEvents : []) )
     120        }
     121
     122
     123        /**
     124         * Return all events and samplingEvenets for a specific template
     125         * @param Template
     126         * @return ArrayList
     127         */
     128        def ArrayList giveEventsForTemplate(Template template) {
     129                def events = events.findAll { it.template.equals(template) }
     130                def samplingEvents = samplingEvents.findAll { it.template.equals(template) }
     131
     132                return (events) ? events : samplingEvents
    110133        }
    111134
     
    138161
    139162
    140          /**
    141         * Delete a specific subject from this study, including all its relations
    142         * @param subject The subject to be deleted
    143         * @return A String which contains a (user-readable) message describing the changes to the database
    144         */
     163        /**
     164         * Delete a specific subject from this study, including all its relations
     165         * @param subject The subject to be deleted
     166         * @return A String which contains a (user-readable) message describing the changes to the database
     167         */
    145168        String deleteSubject(Subject subject) {
    146 
    147169                String msg = "Subject ${subject.name} was deleted"
    148170
     
    171193                return msg
    172194        }
     195
     196        /**
     197         * Delete an event from the study, including all its relations
     198         * @param Event
     199         * @return String
     200         */
     201        String deleteEvent(Event event) {
     202                String msg = "Event ${event} was deleted"
     203
     204                // remove event from the study
     205                this.removeFromEvents(event)
     206
     207                // remove event from eventGroups
     208                this.eventGroups.each() { eventGroup ->
     209                        eventGroup.removeFromEvents(event)
     210                }
     211
     212                return msg
     213        }
     214
     215        /**
     216         * Delete a samplingEvent from the study, including all its relations
     217         * @param SamplingEvent
     218         * @return String
     219         */
     220        String deleteSamplingEvent(SamplingEvent samplingEvent) {
     221                String msg = "SamplingEvent ${samplingEvent} was deleted"
     222
     223                // remove event from eventGroups
     224                this.eventGroups.each() { eventGroup ->
     225                        eventGroup.removeFromSamplingEvents(samplingEvent)
     226                }
     227
     228                // remove event from the study
     229                this.removeFromSamplingEvents(samplingEvent)
     230
     231                return msg
     232        }
     233        /**
     234         * Delete an eventGroup from the study, including all its relations
     235         * @param EventGroup
     236         * @return String
     237         */
     238        String deleteEventGroup(EventGroup eventGroup) {
     239                String msg = "EventGroup ${eventGroup} was deleted"
     240
     241                // remove the eventGroup from the study
     242                this.removeFromEventGroups(eventGroup)
     243
     244                return msg
     245        }
    173246}
  • trunk/grails-app/domain/dbnp/studycapturing/Template.groovy

    r754 r778  
    3333        /** The template fields which are the members of this template. This is a List to preserve the field order */
    3434        List fields
     35
     36        // keep an internal identifier for use in dynamic forms
     37        private int identifier = 0
     38        static int iterator = 0
     39
     40        // set transients
     41        static transients = [ "identifier", "iterator" ]
     42
    3543        static hasMany = [fields: TemplateField]
    3644
     
    7078                // which can co-exist with the same name. See also TemplateField
    7179                //      name(unique:['entity'])
     80        }
     81
     82        /**
     83         * Class constructor increments that static iterator
     84         * and sets the object's identifier (used in dynamic webforms)
     85         * @void
     86         */
     87        public Template() {
     88                if (!identifier) identifier = iterator++
     89                println ".instantiating [" + this.getClass() + "] ("+ identifier + ")"
     90        }
     91
     92        /**
     93         * Return the identifier
     94         * @return int
     95         */
     96        final public int getIdentifier() {
     97                return identifier
    7298        }
    7399
  • trunk/grails-app/domain/dbnp/studycapturing/TemplateEntity.groovy

    r754 r778  
    1818 */
    1919abstract class TemplateEntity implements Serializable {
    20 
    2120        /** The actual template of this TemplateEntity instance */
    2221        Template template
     
    3837        Map templateTermFields = [:]
    3938
     39        // keep an internal identifier for use in dynamic forms
     40        private int identifier = 0
     41        static int iterator = 0
     42
     43        // set transients
     44        static transients = [ "identifier", "iterator" ]
     45
     46        // define relationships
    4047        static hasMany = [
    4148                templateStringFields: String,
     
    5461
    5562        static mapping = {
    56 
    5763                // Specify that each TemplateEntity-subclassing entity should have its own tables to store TemplateField values.
    5864                // This results in a lot of tables, but performance is presumably better because in most queries, only values of
     
    324330                        return (!error)
    325331                })
     332        }
     333
     334        /**
     335         * Class constructor increments that static iterator
     336         * and sets the object's identifier (used in dynamic webforms)
     337         * @void
     338         */
     339        public TemplateEntity() {
     340                if (!identifier) identifier = iterator++
     341        }
     342
     343        /**
     344         * Return the identifier
     345         * @return int
     346         */
     347        final public int getIdentifier() {
     348                return identifier
    326349        }
    327350
     
    593616                        // it is unset if it is.
    594617                        if (value || value == 0 || ( field.type == TemplateFieldType.BOOLEAN && value == false)) {
    595                                 println ".setting [" + ((super) ? super.class : '??') + "] template field: [" + fieldName + "] ([" + value.toString() + "] of type [" + value.class + "])"
     618                                println ".setting [" + ((super) ? super.class : '??') + "] ("+getIdentifier()+") template field: [" + fieldName + "] ([" + value.toString() + "] of type [" + value.class + "])"
    596619
    597620                                // set value
    598621                                store[fieldName] = value
    599622                        } else if (store[fieldName]) {
    600                                 println ".unsetting [" + ((super) ? super.class : '??') + "] template field: [" + fieldName + "]"
     623                                println ".unsetting [" + ((super) ? super.class : '??') + "] ("+getIdentifier()+") template field: [" + fieldName + "]"
    601624
    602625                                // remove the item from the Map (if present)
  • trunk/grails-app/views/wizard/pages/_events.gsp

    r637 r778  
    7070        </script>
    7171
    72         <g:if test="${events}">
    73         <g:each var="eventTemplate" in="${eventTemplates}">
    74                 <g:set var="showHeader" value="${true}" />
    75                 <h1>${eventTemplate.value.name}</h1>
    76         <div class="table">
    77                 <g:each var="eventId" in="${eventTemplate.value.events}">
    78                         <g:if test="${showHeader}">
    79                         <g:set var="showHeader" value="${false}" />
    80                         <div class="header">
    81                                 <div class="firstColumn">#</div>
    82                                 <div class="firstColumn"></div>
    83                                 <g:if test="${eventGroups}"><g:each var="eventGroup" status="g" in="${eventGroups}">
    84                                 <div class="column">
    85                                         <g:textField name="eventGroup_${g}_name" value="${eventGroup.name}" />
    86                                         <wizard:ajaxButton name="deleteEventGroup" src="../images/icons/famfamfam/delete.png" alt="delete this eventgroup" class="famfamfam" value="-" url="[controller:'wizard',action:'pages']" update="[success:'wizardPage',failure:'wizardError']" before="\$(\'input[name=do]\').val(${g});" afterSuccess="onWizardPage()" />
     72        <g:if test="${study.events || study.samplingEvents}">
     73                <g:each var="template" in="${study.giveAllEventTemplates()}">
     74                        <g:set var="showHeader" value="${true}" />
     75                        <h1>${template}</h1>
     76                        <div class="table">
     77                        <g:each var="event" in="${study.giveEventsForTemplate(template)}">
     78                                <g:if test="${showHeader}">
     79                                <g:set var="showHeader" value="${false}" />
     80                                <div class="header">
     81                                        <div class="firstColumn">#</div>
     82                                        <div class="firstColumn"></div>
     83                                        <g:if test="${study.eventGroups}"><g:each var="eventGroup" in="${study.eventGroups}">
     84                                        <div class="column">
     85                                                <g:textField name="eventGroup_${eventGroup.getIdentifier()}_${template.getIdentifier()}" value="${eventGroup.name}" />
     86                                                <wizard:ajaxButton name="deleteEventGroup" src="../images/icons/famfamfam/delete.png" alt="delete this eventgroup" class="famfamfam" value="-" url="[controller:'wizard',action:'pages']" update="[success:'wizardPage',failure:'wizardError']" before="\$(\'input[name=do]\').val(${eventGroup.getIdentifier()});" afterSuccess="onWizardPage()" />
     87                                        </div>
     88                                        </g:each></g:if>
     89                                        <div class="firstColumn">
     90                                                <wizard:ajaxButton name="addEventGroup" src="../images/icons/famfamfam/add.png" alt="add a new eventgroup" class="famfamfam" value="+" url="[controller:'wizard',action:'pages']" update="[success:'wizardPage',failure:'wizardError']" afterSuccess="onWizardPage()" />
     91                                        </div>
     92                                  <wizard:templateColumnHeaders class="column" entity="${event}" />
    8793                                </div>
    88                                 </g:each></g:if>
    89                                 <div class="firstColumn">
    90                                         <wizard:ajaxButton name="addEventGroup" src="../images/icons/famfamfam/add.png" alt="add a new eventgroup" class="famfamfam" value="+" url="[controller:'wizard',action:'pages']" update="[success:'wizardPage',failure:'wizardError']" afterSuccess="onWizardPage()" />
     94                                </g:if>
     95
     96                                <div class="row">
     97                                        <div class="firstColumn">${event.getIdentifier()}</div>
     98                                        <div class="firstColumn">
     99                                                <wizard:ajaxButton name="deleteEvent" src="../images/icons/famfamfam/delete.png" alt="delete this subject" class="famfamfam" value="-" url="[controller:'wizard',action:'pages']" update="[success:'wizardPage',failure:'wizardError']" before="\$(\'input[name=do]\').val(${event.getIdentifier()});" afterSuccess="onWizardPage()"/>
     100                                        </div>
     101                                        <g:if test="${study.eventGroups}"><g:each var="eventGroup" in="${study.eventGroups}">
     102                                        <div class="column">
     103                                                <g:if test="${eventGroup.events.find{ it == event } || eventGroup.samplingEvents.find{ it == event }}">
     104                                                        <input type="checkbox" name="event_${event.getIdentifier()}_group_${eventGroup.getIdentifier()}" checked="checked" />
     105                                                </g:if><g:else>
     106                                                        <input type="checkbox" name="event_${event.getIdentifier()}_group_${eventGroup.getIdentifier()}"/>
     107                                                </g:else>
     108                                        </div>
     109                                        </g:each></g:if>
     110                                        <div class="firstColumn"></div>
     111                                        <wizard:templateColumns class="column" entity="${event}" name="event_${event.getIdentifier()}" />
    91112                                </div>
    92                                 <wizard:templateColumnHeaders entity="${events[ eventId ]}" class="column"/>
     113
     114                        </g:each>
    93115                        </div>
    94                         </g:if>
    95                         <div class="row">
    96                                 <div class="firstColumn">${eventId + 1}</div>
    97                                 <div class="firstColumn">
    98                                         <wizard:ajaxButton name="deleteEvent" src="../images/icons/famfamfam/delete.png" alt="delete this subject" class="famfamfam" value="-" url="[controller:'wizard',action:'pages']" update="[success:'wizardPage',failure:'wizardError']" before="\$(\'input[name=do]\').val(${eventId});" afterSuccess="onWizardPage()"/>
    99                                 </div>
    100                                 <g:if test="${eventGroups}"><g:each var="eventGroup" status="j" in="${eventGroups}">
    101                                 <div class="column">
    102                                         <g:if test="${eventGroup.events.find{ it == events[ eventId ] } }">
    103                                                 <input type="checkbox" name="event_${eventId}_group_${j}" checked="checked" />
    104                                         </g:if><g:else>
    105                                                 <input type="checkbox" name="event_${eventId}_group_${j}"/>
    106                                         </g:else>
    107                                 </div>
    108                                 </g:each></g:if>
    109                                 <div class="firstColumn"></div>
    110                                 <wizard:templateColumns id="${eventId}" entity="${events[ eventId ]}" template="${events[ eventId ].template}" name="event_${eventId}" class="column" />
     116                        <div class="sliderContainer">
     117                                <div class="slider"></div>
    111118                        </div>
    112119                </g:each>
    113         </div>
    114         <div class="sliderContainer">
    115                 <div class="slider"></div>
    116         </div>
    117         </g:each>
    118 </g:if>
     120        </g:if>
    119121
    120122</wizard:pageContent>
  • trunk/grails-app/views/wizard/pages/_groups.gsp

    r529 r778  
    2727                        <div class="column">Template</div>
    2828                        <div class="column">Subjects</div>
    29                         <g:if test="${eventGroups}"><g:each var="eventGroup" status="g" in="${eventGroups}">
     29                        <g:if test="${study.eventGroups}"><g:each var="eventGroup" in="${study.eventGroups}">
    3030                                <div class="column">
    3131                                        ${eventGroup.name}
     
    4343                        </g:each></g:if>
    4444                </div>
    45                 <g:each var="sTemplate" in="${subjectTemplates}">
    46                         <g:set var="subjectTemplate" value="${sTemplate.getValue()}"/>
     45                <g:each var="template" in="${study.giveSubjectTemplates()}">
    4746                        <g:set var="showHeader" value="${true}"/>
    48                         <g:each var="sId" in="${subjectTemplate.subjects}">
    49                                 <g:set var="subjectId" value="${sId.getValue()}"/>
    50                                 <div class="row">
    51                                         <div class="column">
    52                                                 <g:if test="${showHeader}">
    53                                                         <g:set var="showHeader" value="${false}"/>
    54                                                         ${subjectTemplate.name}
    55                                                         <div class="helpIcon"></div>
    56                                                         <div class="helpContent">
    57                                                                 <h1>${subjectTemplate.name}</h1>
    58                                                                 <h2>Template Fields:</h2>
    59                                                                 <g:each var="field" status="f" in="${subjects[ subjectId ].giveFields()}">
    60                                                                         ${field.name[0].toUpperCase() + field.name.substring(1)}<br/>
    61                                                                 </g:each>
    62                                                         </div>
    63                                                 </g:if>
    64                                         </div>
    65                                         <div class="column">${subjects[subjectId].name}</div>
    66                                         <g:if test="${eventGroups}"><g:each var="eventGroup" status="g" in="${eventGroups}">
    67                                                 <div class="column">
    68                                                         <g:if test="${eventGroup.subjects.find{ it == subjects[ subjectId ] } }">
    69                                                                 <input type="checkbox" name="subject_${subjectId}_group_${g}" checked="checked"/>
    70                                                         </g:if><g:else>
    71                                                         <input type="checkbox" name="subject_${subjectId}_group_${g}"/>
    72                                                 </g:else>
     47                        <g:each var="subject" in="${study.giveSubjectsForTemplate(template)}">
     48                        <div class="row">
     49                                <div class="column">
     50                                        <g:if test="${showHeader}">
     51                                                <g:set var="showHeader" value="${false}"/>
     52                                                ${template.name}
     53                                                <div class="helpIcon"></div>
     54                                                <div class="helpContent">
     55                                                        <h1>${template.name}</h1>
     56                                                        <h2>Template Fields:</h2>
     57                                                        <g:each var="field" in="${subject.giveFields()}">
     58                                                                ${field.name[0].toUpperCase() + field.name.substring(1)}<br/>
     59                                                        </g:each>
    7360                                                </div>
    74                                         </g:each></g:if>
     61                                        </g:if>
    7562                                </div>
     63                                <div class="column">${subject.name}</div>
     64                                <g:if test="${study.eventGroups}"><g:each var="eventGroup" in="${study.eventGroups}">
     65                                <div class="column">
     66                                        <g:if test="${eventGroup.subjects.find{ it == subject } }">
     67                                                <input type="checkbox" name="subject_${subject.getIdentifier()}_group_${eventGroup.getIdentifier()}" checked="checked"/>
     68                                        </g:if><g:else>
     69                                                <input type="checkbox" name="subject_${subject.getIdentifier()}_group_${eventGroup.getIdentifier()}" />
     70                                        </g:else>
     71                                </div>
     72                                </g:each></g:if>
     73                        </div>
    7674                        </g:each>
    7775                </g:each>
  • trunk/grails-app/views/wizard/pages/_subjects.gsp

    r567 r778  
    3737        </wizard:ajaxButtonElement>
    3838
    39 <g:if test="${subjects}">
    40         <g:each var="sTemplate" in="${subjectTemplates}">
    41                 <g:set var="showHeader" value="${true}" />
    42                 <g:set var="subjectTemplate" value="${sTemplate.getValue()}" />
    43                 <h1>${subjectTemplate.name} template</h1>
    44                 <div class="table">
    45                 <g:each status="i" var="sId" in="${subjectTemplate.subjects}">
    46                   <g:set var="subjectId" value="${sId.getValue()}" />
    47                   <g:if test="${subjects[ subjectId ]}">
    48                         <g:if test="${showHeader}">
    49                         <g:set var="showHeader" value="${false}" />
    50                         <div class="header">
    51                                 <div class="firstColumn">#</div>
    52                                 <div class="firstColumn"></div>
    53                                 <wizard:templateColumnHeaders entity="${subjects[ subjectId ]}" class="column" />                               
     39        <g:if test="${study.subjects}">
     40                <g:each var="template" in="${study.giveSubjectTemplates()}">
     41                        <g:set var="showHeader" value="${true}" />
     42                        <h1>${template} template</h1>
     43                        <div class="table">
     44                        <g:each var="subject" status="s" in="${study.giveSubjectsForTemplate(template)}">
     45                                <g:if test="${showHeader}">
     46                                <g:set var="showHeader" value="${false}" />
     47                                <div class="header">
     48                                  <div class="firstColumn">#</div>
     49                                  <div class="firstColumn"></div>
     50                                  <wizard:templateColumnHeaders class="column" entity="${subject}" />
     51                                </div>
     52                                </g:if>
     53                                <div class="row">
     54                                        <div class="firstColumn">${subject.getIdentifier()}</div>
     55                                        <div class="firstColumn">
     56                                                <wizard:ajaxButton name="delete" src="../images/icons/famfamfam/delete.png" alt="delete this subject" class="famfamfam" value="-" url="[controller:'wizard',action:'pages']" update="[success:'wizardPage',failure:'wizardError']" before="\$(\'input[name=do]\').val(${subject.getIdentifier()});" afterSuccess="onWizardPage()" />
     57                                        </div>
     58                                        <wizard:templateColumns class="column" entity="${subject}" name="subject_${subject.getIdentifier()}" />
     59                                </div>
     60                        </g:each>
    5461                        </div>
    55                         </g:if>
    56                         <div class="row">
    57                                 <div class="firstColumn">${subjectId + 1}</div>
    58                                 <div class="firstColumn">
    59                                         <wizard:ajaxButton name="delete" src="../images/icons/famfamfam/delete.png" alt="delete this subject" class="famfamfam" value="-" url="[controller:'wizard',action:'pages']" update="[success:'wizardPage',failure:'wizardError']" before="\$(\'input[name=do]\').val(${subjectId});" afterSuccess="onWizardPage()" />
    60                                 </div>
    61                                 <wizard:templateColumns id="${subjectId}" entity="${subjects[ subjectId ]}" template="${subjects[ subjectId ].template}" name="subject_${subjectId}" class="column" subject="${subjects[ subjectId ]}" addDummy="true" />
     62                        <div class="sliderContainer">
     63                                <div class="slider" ></div>
    6264                        </div>
    63                   </g:if>
    6465                </g:each>
    65                 </div>
    66                 <div class="sliderContainer">
    67                         <div class="slider" ></div>
    68                 </div>
    69         </g:each>
    70 </g:if>
     66        </g:if>
    7167
    7268</wizard:pageContent>
Note: See TracChangeset for help on using the changeset viewer.