Changeset 213 for trunk/grails-app


Ignore:
Timestamp:
Feb 25, 2010, 4:18:22 PM (10 years ago)
Author:
duh
Message:
  • restructured wizard
  • added information boxes
  • improved error feedback (highlighted error fields)
  • added confirmation page
  • several smaller bugfixes and improvements
Location:
trunk/grails-app
Files:
2 added
8 edited

Legend:

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

    r209 r213  
    5151                                [title: 'Subjects'],                    // subjects
    5252                                [title: 'Event Descriptions'],  // event descriptions
    53                                 [title: 'Events'],                              // groups
    54                                 [title: '---'],                         // events
    55                                 [title: '---'],                         // samples
    56                                 [title: '---'],                 // protocols
    57                                 [title: '---'],                         // assays
     53                                [title: 'Events'],                              // events
     54                                [title: 'Confirmation'],        // confirmation page
    5855                                [title: 'Done']                                 // finish page
    5956                        ]
     
    212209                                        // validation failed, feedback errors
    213210                                        flash.errors = new LinkedHashMap()
     211                                        flash.values = params
    214212                                        this.appendErrors(eventDescription, flash.errors)
    215213                                        error()
     
    221219                                // handle form data
    222220                                if (!this.handleEventDescriptions(flow, flash, params)) {
     221                                        flash.values = params
    223222                                        error()
    224223                                } else {
     
    233232                                if (flow.eventDescriptions.size() < 1) {
    234233                                        // append error map
     234                                        flash.values = params
    235235                                        this.appendErrorMap(['eventDescriptions': 'You need at least to create one eventDescription for your study'], flash.errors)
    236236                                        error()
    237237                                } else if (!this.handleEventDescriptions(flow, flash, params)) {
     238                                        flash.values = params
    238239                                        error()
    239240                                } else {
     
    255256                                if (!flow.eventGroups) {
    256257                                        flow.eventGroups = []
     258                                        flow.eventGroups[0] = new EventGroup(name: 'Group 1')   // 1 group by default
    257259                                }
    258260                        }
     
    261263                                // @see WizardTagLibrary::timeElement{...}
    262264                                if (params.get('startTime')) {
    263                                         println params.get('startTime').toString()
    264265                                        params.startTime = new Date().parse("d/M/yyyy HH:mm", params.get('startTime').toString())
    265266                                }
     
    283284                                        // validation failed, feedback errors
    284285                                        flash.errors = new LinkedHashMap()
     286                                        flash.values = params
    285287                                        this.appendErrors(event, flash.errors)
    286288
     
    294296                        on("addEventGroup") {
    295297                                def increment = flow.eventGroups.size()
    296                                 flow.eventGroups[ increment ] = new EventGroup(name: "group "+(increment+1))
     298                                flow.eventGroups[ increment ] = new EventGroup(name: "Group "+(increment+1))
    297299                        }.to "events"
    298300                        on("previous") {
     
    300302                        }.to "eventDescriptions"
    301303                        on("next") {
    302                                 // TODO
    303                         }.to "events"
    304                 }
    305 
    306                 // render and handle group page
    307                 groups {
    308                         render(view: "_groups")
     304                                flash.errors = new LinkedHashMap()
     305
     306                                // check if we have at least one subject
     307                                // and check form data
     308                                if (flow.events.size() < 1) {
     309                                        // append error map
     310                                        flash.values = params
     311                                        this.appendErrorMap(['events': 'You need at least to create one event for your study'], flash.errors)
     312                                        error()
     313                                }
     314                        }.to "confirm"
     315                }
     316
     317                confirm {
     318                        render(view: "_confirmation")
    309319                        onRender {
    310320                                flow.page = 6
    311 
    312                                 if (!flow.groups) {
    313                                         flow.groups = []
    314                                 }
    315                         }
    316                         on("add") {
    317                                 def increment = flow.groups.size()
    318                                 flow.groups[increment] = new SubjectGroup(params)
    319                         }.to "groups"
    320                         on("next") {
    321                                 // TODO
    322                         }.to "groups"
     321                        }
    323322                        on("previous") {
    324                                 // TODO
    325                         }.to "subjects"
    326                 }
    327 
    328                 // render page three
    329                 samples {
    330                         render(view: "_samples")
    331                         onRender {
    332                                 flow.page = 7
    333                         }
    334                         on("previous") {
    335                                 // TODO
     323                                // do nothing
    336324                        }.to "events"
    337325                        on("next") {
    338                                 // TODO
    339                         }.to "protocols"
    340                 }
    341 
    342                 // render page three
    343                 protocols {
    344                         render(view: "_protocols")
    345                         onRender {
    346                                 flow.page = 8
    347                         }
    348                         on("previous") {
    349                                 // TODO
    350                         }.to "samples"
    351                         on("next") {
    352                                 // TODO
    353                         }.to "assays"
    354                 }
    355 
    356                 // render page three
    357                 assays {
    358                         render(view: "_assays")
    359                         onRender {
    360                                 flow.page = 9
    361                         }
    362                         on("previous") {
    363                                 // TODO
    364                         }.to "protocols"
    365                         on("next") {
    366                                 // TODO
    367                         }.to "done"
     326                                // store everything in the database!
     327                                success()
     328                        }.to "confirm"
    368329                }
    369330
     
    372333                        render(view: "_done")
    373334                        onRender {
    374                                 flow.page = 10
     335                                flow.page = 6
    375336                        }
    376337                        on("previous") {
    377338                                // TODO
    378                         }.to "assays"
     339                        }.to "confirm"
    379340                }
    380341        }
     
    395356                if (params.get('startDate')) {
    396357                        params.startDate = new Date().parse("d/M/yyyy", params.get('startDate').toString())
     358                } else {
     359                        params.remove('startDate')
    397360                }
    398361
     
    428391         */
    429392        def handleEventDescriptions(flow, flash, params) {
    430                 def names = new LinkedHashMap();
    431                 def errors = false;
    432                 def id = 0;
     393                def names = new LinkedHashMap()
     394                def errors = false
     395                def id = 0
    433396
    434397                flow.eventDescriptions.each() {
    435                         it.name                 = params.get('eventDescription_' + id + '_name')
     398                        it.name                         = params.get('eventDescription_' + id + '_name')
    436399                        it.description          = params.get('eventDescription_' + id + '_description')
    437400                        it.classification       = Term.findByName(params.get('eventDescription_' + id + '_classification'))
     
    441404                        if (!it.validate()) {
    442405                                errors = true
    443                                 println id + ' :: ' + it.errors.getAllErrors()
    444                                 this.appendErrors(it, flash.errors)
     406                                this.appendErrors(it, flash.errors, 'eventDescription_' + id + '_')
    445407                        }
    446408
    447409                        id++
    448410                }
     411
     412                return !(errors)
    449413        }
    450414
     
    470434                        // remember name and check for duplicates
    471435                        if (!names[it.name]) {
    472                                 names[it.name] = [count: 1, first: 'subject_' + id + '_name']
     436                                names[it.name] = [count: 1, first: 'subject_' + id + '_name', firstId: id]
    473437                        } else {
    474438                                // duplicate name found, set error flag
     
    479443                                        // yeah, also mention the first
    480444                                        // occurrence in the error message
    481                                         this.appendErrorMap([[names[it.name]['first']]: 'The subject name needs to be unique!'], flash.errors)
     445                                        this.appendErrorMap(name: 'The subject name needs to be unique!', flash.errors, 'subject_'+names[it.name]['firstId']+'_')
    482446                                }
    483447
    484448                                // add to error map
    485                                 this.appendErrorMap([['subject_' + id + '_name']: 'The subject name needs to be unique!'], flash.errors)
     449                                this.appendErrorMap([name: 'The subject name needs to be unique!'], flash.errors, 'subject_'+id+'_')
    486450                                errors = true
    487451                        }
     
    529493                        if (!it.validate()) {
    530494                                errors = true
    531                                 println id + ' :: ' + it.errors.getAllErrors()
    532495                                this.appendErrors(it, flash.errors)
    533496                        }
     
    582545                this.appendErrorMap(this.getHumanReadableErrors(object), map)
    583546        }
     547        def appendErrors(object, map, prepend) {
     548                this.appendErrorMap(this.getHumanReadableErrors(object), map, prepend)
     549        }
    584550
    585551        /**
     
    591557        def appendErrorMap(map, mapToExtend) {
    592558                map.each() {key, value ->
    593                         mapToExtend[key] = value
     559                        mapToExtend[key] = ['key': key, 'value': value, 'dynamic': false]
     560                }
     561        }
     562        def appendErrorMap(map, mapToExtend, prepend) {
     563                map.each() {key, value ->
     564                        mapToExtend[prepend + key] = ['key': key, 'value': value, 'dynamic': true]
    594565                }
    595566        }
  • trunk/grails-app/taglib/dbnp/studycapturing/WizardTagLib.groovy

    r209 r213  
    442442        }
    443443
     444        def show = { attrs ->
     445                // is object parameter set?
     446                def o = attrs.object
     447
     448                println o.getProperties();
     449                o.getProperties().each {
     450                        println it
     451                }
     452
     453                out << "!! test version of 'show' tag !!"
     454        }
     455
    444456        /**
    445457         * render table headers for all subjectFields in a template
     
    483495                                                )
    484496                                        } else {
    485                                                 out << '<span class="error">no values!!</span>'
     497                                                out << '<span class="warning">no values!!</span>'
    486498                                        }
    487499                                        break;
     
    502514                                default:
    503515                                        // unsupported field type
    504                                         out << '<span class="error">!'+it.type+'</span>'
     516                                        out << '<span class="warning">!'+it.type+'</span>'
    505517                                        break;
    506518                        }
  • trunk/grails-app/views/wizard/common/_error.gsp

    r105 r213  
    2020                        <p>
    2121                                <g:if test="${!e}"><span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 50px 0;"></span></g:if>
    22                                 ${error.key} &rarr; ${error.value}
     22                                ${error.value['key']} &rarr; ${error.value['value']}
    2323                        </p>
    2424                </g:each>
    2525        </div>
    2626        <script type="text/javascript">
     27                // mark error fields
     28                <g:each in="${errors}" var="error">
     29                <g:if test="${error.value['dynamic']}">
     30                $("input:[name='${error.key}']").addClass('error');
     31                </g:if><g:else>
     32                $("input:[name='${error.key}']").parent().parent().addClass('error');
     33                </g:else>
     34                </g:each>
     35
    2736                // show error dialog
    2837                $(function() {
  • trunk/grails-app/views/wizard/pages/_eventDescriptions.gsp

    r209 r213  
    1616%>
    1717<wizard:pageContent>
    18         <wizard:termElement name="classification" description="Classification" error="classification" value="${classification}">
     18        <span class="info">
     19                <span class="title">Describe all unique event types that occur in your study</span>
     20                These unique events are, for example, treatments, challenges and sampling events. Every event description
     21                should be unique. If your study, for example, samples both blood as well as tissue, then create two sample
     22                descriptions. One for 'sampling blood', and one for 'sampling tissue'.
     23        </span>
     24
     25        <wizard:termElement name="classification" description="Classification" error="classification" value="${values?.classification}">
    1926                The classification
    2027        </wizard:termElement>
    21         <wizard:textFieldElement name="name" description="Name" error="name" value="${name}">
     28        <wizard:textFieldElement name="name" description="Name" error="name" value="${values?.name}">
    2229                The name of the event description you are creating
    2330        </wizard:textFieldElement>
    24         <wizard:textFieldElement name="description" description="Description" error="description" value="${description}">
     31        <wizard:textFieldElement name="description" description="Description" error="description" value="${values?.description}">
    2532                A short description summarizing your event description
    2633        </wizard:textFieldElement>
    27         <wizard:checkBoxElement name="isSamplingEvent" description="Sampling event" error="isSamplingEvent" value="${isSamplingEvent}">
     34        <wizard:checkBoxElement name="isSamplingEvent" description="Sampling event" error="isSamplingEvent" value="${values?.isSamplingEvent}">
    2835                Is this a sampling event description?
    2936        </wizard:checkBoxElement>
  • trunk/grails-app/views/wizard/pages/_events.gsp

    r209 r213  
    1616%>
    1717<wizard:pageContent>
    18         <wizard:selectElement name="eventDescription" description="Event Description" error="eventDescription" from="${eventDescriptions}" value="${eventDescription}">
     18        <span class="info">
     19                <span class="title">Define all events and their duration that occur in your study</span>
     20                In the previous screen you defined the unique event types, in this screen you need to define
     21                all events of a specific event type that occur in time. Select the type of event, and the
     22                start and stop time of an event. As it is frequently the case that <i>sets</i> of events act
     23                upon (groups of) subjects, you can define event groups, and add events to a particular group.<br/>
     24                <i>Note that you can edit multiple events at once by selecting multpiple rows by either
     25                ctrl-clicking them or dragging a selection over them.</i>
     26        </span>
     27
     28        <wizard:selectElement name="eventDescription" description="Event Description" error="eventDescription" from="${eventDescriptions}" value="${values?.eventDescription}">
    1929                The event description for this event
    2030        </wizard:selectElement>
    21         <wizard:timeElement name="startTime" description="Start Time" error="startTime" value="${startTime}">
     31        <wizard:timeElement name="startTime" description="Start Time" error="startTime" value="${values?.startTime}">
    2232                The start time of the study
    2333        </wizard:timeElement>
    24         <wizard:timeElement name="endTime" description="End time" error="endTimee" value="${endTime}">
     34        <wizard:timeElement name="endTime" description="End time" error="endTimee" value="${values?.endTime}">
    2535                The end time of the study
    2636        </wizard:timeElement>
    2737        <wizard:buttonElement name="add" value="Add" url="[controller:'wizard',action:'pages']" update="[success:'wizardPage',failure:'wizardError']" afterSuccess="onWizardPage()"/>
    28 <g:if test="${events}">
     38<g:if test="${events}"> 
    2939        <div class="table">
    3040                <div class="header">
  • trunk/grails-app/views/wizard/pages/_study.gsp

    r195 r213  
    1616%>
    1717<wizard:pageContent>
     18        <span class="info">
     19                <span class="title">Define the basic properties of your study</span>
     20                Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce laoreet leo nec leo vehicula quis scelerisque elit pulvinar. Vivamus arcu dui, adipiscing eu vestibulum id, consectetur et erat. Aenean risus mauris, placerat et lacinia vulputate, commodo eget ligula. Pellentesque ornare blandit metus ac dictum. Donec scelerisque feugiat quam, a congue ipsum malesuada nec. Donec vulputate, diam eget porta rhoncus, est mauris ullamcorper turpis, vitae dictum risus justo quis justo. Aenean blandit feugiat accumsan. Donec porttitor bibendum elementum.
     21        </span>
     22       
    1823        <wizard:textFieldElement name="title" description="Title" error="title" value="${study?.title}">
    1924                The title of the study you are creating
  • trunk/grails-app/views/wizard/pages/_subjects.gsp

    r209 r213  
    1616%>
    1717<wizard:pageContent>
     18        <span class="info">
     19                <span class="title">Add subjects to your study</span>
     20                Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce laoreet leo nec leo vehicula quis scelerisque elit pulvinar. Vivamus arcu dui, adipiscing eu vestibulum id, consectetur et erat. Aenean risus mauris, placerat et lacinia vulputate, commodo eget ligula. Pellentesque ornare blandit metus ac dictum. Donec scelerisque feugiat quam, a congue ipsum malesuada nec. Donec vulputate, diam eget porta rhoncus, est mauris ullamcorper turpis, vitae dictum risus justo quis justo. Aenean blandit feugiat accumsan. Donec porttitor bibendum elementum.
     21        </span>
     22
    1823        <wizard:ajaxButton name="add" value="Add" url="[controller:'wizard',action:'pages']" update="[success:'wizardPage',failure:'wizardError']" afterSuccess="onWizardPage()" />
    1924        <input name="addNumber" size="4" maxlength="4" value="1">
  • trunk/grails-app/views/wizard/pages/_templates.gsp

    r195 r213  
    1616%>
    1717<wizard:pageContent>
     18        <span class="info">
     19                <span class="title">Select the template you would like to use</span>
     20                A template is a predefined set of values to store with all elements of your study.
     21        </span>
     22
    1823        <wizard:templateElement name="template" description="Template" value="${study?.template}">
    1924                The meta data template to use for this study
Note: See TracChangeset for help on using the changeset viewer.