Changeset 213
- Timestamp:
- Feb 25, 2010, 4:18:22 PM (11 years ago)
- Location:
- trunk
- Files:
-
- 7 added
- 1 deleted
- 11 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/grails-app/controllers/dbnp/studycapturing/WizardController.groovy
r209 r213 51 51 [title: 'Subjects'], // subjects 52 52 [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 58 55 [title: 'Done'] // finish page 59 56 ] … … 212 209 // validation failed, feedback errors 213 210 flash.errors = new LinkedHashMap() 211 flash.values = params 214 212 this.appendErrors(eventDescription, flash.errors) 215 213 error() … … 221 219 // handle form data 222 220 if (!this.handleEventDescriptions(flow, flash, params)) { 221 flash.values = params 223 222 error() 224 223 } else { … … 233 232 if (flow.eventDescriptions.size() < 1) { 234 233 // append error map 234 flash.values = params 235 235 this.appendErrorMap(['eventDescriptions': 'You need at least to create one eventDescription for your study'], flash.errors) 236 236 error() 237 237 } else if (!this.handleEventDescriptions(flow, flash, params)) { 238 flash.values = params 238 239 error() 239 240 } else { … … 255 256 if (!flow.eventGroups) { 256 257 flow.eventGroups = [] 258 flow.eventGroups[0] = new EventGroup(name: 'Group 1') // 1 group by default 257 259 } 258 260 } … … 261 263 // @see WizardTagLibrary::timeElement{...} 262 264 if (params.get('startTime')) { 263 println params.get('startTime').toString()264 265 params.startTime = new Date().parse("d/M/yyyy HH:mm", params.get('startTime').toString()) 265 266 } … … 283 284 // validation failed, feedback errors 284 285 flash.errors = new LinkedHashMap() 286 flash.values = params 285 287 this.appendErrors(event, flash.errors) 286 288 … … 294 296 on("addEventGroup") { 295 297 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)) 297 299 }.to "events" 298 300 on("previous") { … … 300 302 }.to "eventDescriptions" 301 303 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") 309 319 onRender { 310 320 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 } 323 322 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 336 324 }.to "events" 337 325 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" 368 329 } 369 330 … … 372 333 render(view: "_done") 373 334 onRender { 374 flow.page = 10335 flow.page = 6 375 336 } 376 337 on("previous") { 377 338 // TODO 378 }.to " assays"339 }.to "confirm" 379 340 } 380 341 } … … 395 356 if (params.get('startDate')) { 396 357 params.startDate = new Date().parse("d/M/yyyy", params.get('startDate').toString()) 358 } else { 359 params.remove('startDate') 397 360 } 398 361 … … 428 391 */ 429 392 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 433 396 434 397 flow.eventDescriptions.each() { 435 it.name = params.get('eventDescription_' + id + '_name')398 it.name = params.get('eventDescription_' + id + '_name') 436 399 it.description = params.get('eventDescription_' + id + '_description') 437 400 it.classification = Term.findByName(params.get('eventDescription_' + id + '_classification')) … … 441 404 if (!it.validate()) { 442 405 errors = true 443 println id + ' :: ' + it.errors.getAllErrors() 444 this.appendErrors(it, flash.errors) 406 this.appendErrors(it, flash.errors, 'eventDescription_' + id + '_') 445 407 } 446 408 447 409 id++ 448 410 } 411 412 return !(errors) 449 413 } 450 414 … … 470 434 // remember name and check for duplicates 471 435 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] 473 437 } else { 474 438 // duplicate name found, set error flag … … 479 443 // yeah, also mention the first 480 444 // 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']+'_') 482 446 } 483 447 484 448 // 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+'_') 486 450 errors = true 487 451 } … … 529 493 if (!it.validate()) { 530 494 errors = true 531 println id + ' :: ' + it.errors.getAllErrors()532 495 this.appendErrors(it, flash.errors) 533 496 } … … 582 545 this.appendErrorMap(this.getHumanReadableErrors(object), map) 583 546 } 547 def appendErrors(object, map, prepend) { 548 this.appendErrorMap(this.getHumanReadableErrors(object), map, prepend) 549 } 584 550 585 551 /** … … 591 557 def appendErrorMap(map, mapToExtend) { 592 558 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] 594 565 } 595 566 } -
trunk/grails-app/taglib/dbnp/studycapturing/WizardTagLib.groovy
r209 r213 442 442 } 443 443 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 444 456 /** 445 457 * render table headers for all subjectFields in a template … … 483 495 ) 484 496 } else { 485 out << '<span class=" error">no values!!</span>'497 out << '<span class="warning">no values!!</span>' 486 498 } 487 499 break; … … 502 514 default: 503 515 // unsupported field type 504 out << '<span class=" error">!'+it.type+'</span>'516 out << '<span class="warning">!'+it.type+'</span>' 505 517 break; 506 518 } -
trunk/grails-app/views/wizard/common/_error.gsp
r105 r213 20 20 <p> 21 21 <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} → ${error.value}22 ${error.value['key']} → ${error.value['value']} 23 23 </p> 24 24 </g:each> 25 25 </div> 26 26 <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 27 36 // show error dialog 28 37 $(function() { -
trunk/grails-app/views/wizard/pages/_eventDescriptions.gsp
r209 r213 16 16 %> 17 17 <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}"> 19 26 The classification 20 27 </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}"> 22 29 The name of the event description you are creating 23 30 </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}"> 25 32 A short description summarizing your event description 26 33 </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}"> 28 35 Is this a sampling event description? 29 36 </wizard:checkBoxElement> -
trunk/grails-app/views/wizard/pages/_events.gsp
r209 r213 16 16 %> 17 17 <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}"> 19 29 The event description for this event 20 30 </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}"> 22 32 The start time of the study 23 33 </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}"> 25 35 The end time of the study 26 36 </wizard:timeElement> 27 37 <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}"> 29 39 <div class="table"> 30 40 <div class="header"> -
trunk/grails-app/views/wizard/pages/_study.gsp
r195 r213 16 16 %> 17 17 <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 18 23 <wizard:textFieldElement name="title" description="Title" error="title" value="${study?.title}"> 19 24 The title of the study you are creating -
trunk/grails-app/views/wizard/pages/_subjects.gsp
r209 r213 16 16 %> 17 17 <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 18 23 <wizard:ajaxButton name="add" value="Add" url="[controller:'wizard',action:'pages']" update="[success:'wizardPage',failure:'wizardError']" afterSuccess="onWizardPage()" /> 19 24 <input name="addNumber" size="4" maxlength="4" value="1"> -
trunk/grails-app/views/wizard/pages/_templates.gsp
r195 r213 16 16 %> 17 17 <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 18 23 <wizard:templateElement name="template" description="Template" value="${study?.template}"> 19 24 The meta data template to use for this study -
trunk/web-app/css/wizard.css
r209 r213 2 2 display: block; 3 3 padding-top: 10px; 4 } 5 6 .wizard .info { 7 display: block; 8 border: 1px solid #006DBA; 9 background-color: #EEE; 10 padding: 10px; 11 font-size: 10px; 12 margin: 10px 0px 10px 0px; 13 } 14 15 .wizard .info .title { 16 color:#006DBA; 17 font-size:14px; 18 font-weight:normal; 19 display: block; 20 margin-bottom: 5px; 21 padding-left: 20px; 22 background: url(../images/icons/famfamfam/information.png) no-repeat center left; 4 23 } 5 24 … … 70 89 } 71 90 72 .wizard .error {73 display: block;74 padding-top: 10px;75 }76 77 91 .wizard .element { 78 92 display: block; … … 88 102 .wizard .element .input { 89 103 display: inline; 104 } 105 106 .wizard .error { 107 background: url(../images/icons/famfamfam/exclamation.png) no-repeat 230px 4px; 90 108 } 91 109 … … 184 202 } 185 203 186 .wizard .table .row . error{204 .wizard .table .row .warning { 187 205 color: red; 188 206 font-size: 8px; … … 190 208 } 191 209 210 .wizard .table .row .error { 211 background-color: #ffb0b7; 212 } 213 192 214 .wizard .table input, .wizard .table select { 193 215 border: 1px solid #8e908f; … … 195 217 padding: 2px 4px; 196 218 background-color: transparent; 219 width: 100px; 220 } 221 .wizard .table .header input, .wizard .table .header select, .wizard .table .header button { 222 border: 1px solid #8e908f; 223 margin: 2px 0; 224 padding: 2px 4px; 225 background-color: #fff; 197 226 width: 100px; 198 227 } -
trunk/web-app/js/table-editor.js
r209 r213 18 18 columnIdentifier: null, 19 19 20 /** 21 * initialize object 22 * @param tableIdentifier 23 * @param rowIdentifier 24 * @param columnIdentifier 25 */ 20 26 init: function(tableIdentifier, rowIdentifier, columnIdentifier) { 21 27 // store parameters globally … … 35 41 }, 36 42 43 /** 44 * initialize table 45 * @param table 46 */ 37 47 initializeTable: function(table) { 38 48 var that = this; … … 49 59 }, 50 60 61 /** 62 * attach handlers to the input elements in a table row 63 * @param row 64 */ 51 65 attachColumnHandlers: function(row) { 52 66 var that = this; … … 55 69 var input = $(':input', $(this)); 56 70 // does this column contain an input field 57 console.log(input)58 71 if (input) { 59 72 var type = $(input).attr('type'); 60 console.log(input)61 console.log('type: '+type)62 73 63 74 switch (type) { … … 74 85 $(input).bind('change', function() { 75 86 that.updateSingleInputElements(input, columnNumber, 'select'); 76 }) 87 }); 88 break; 89 case 'checkbox': 90 // checkbox 91 var columnNumber = count; 92 $(input).bind('click', function() { 93 console.log(columnNumber+': update checkboxes with value '+input) 94 that.updateSingleInputElements(input, columnNumber, 'input'); 95 }); 77 96 break; 78 97 case 'hidden': … … 93 112 }, 94 113 114 /** 115 * update all input elements in a selected column 116 * @param element 117 * @param columnNumber 118 * @param elementSelector 119 */ 95 120 updateSingleInputElements: function(element, columnNumber, elementSelector) { 96 121 var that = this; … … 99 124 var r = c.parent(); 100 125 var t = r.parent(); 101 102 // get value(s) 103 // TODO for multiple selects... 104 var v = e.val(); 126 var v = this.getValue(e); 127 // TODO for multiples... 105 128 106 129 // select all input elements in the selected rows 107 130 $('.ui-selected', t).each(function() { 108 131 $(that.columnIdentifier + ':eq(' + columnNumber + ') ' + elementSelector, $(this)).each(function() { 109 if ($(this).val() != v) { 110 $(this).val(v); 111 // TODO support multiple selects 132 var me = $(this) 133 var myVal = that.getValue(me); 134 if (myVal != v) { 135 that.setValue(me,v); 112 136 } 113 137 }) 138 }) 139 }, 114 140 115 }) 141 /** 142 * get the value /status of an input field based on it's type 143 * @param input 144 */ 145 getValue: function(input) { 146 var i = $(input); 147 148 switch (i.attr('type')) { 149 case 'checkbox': 150 return i.attr('checked'); 151 break; 152 default: 153 return i.val(); 154 break; 155 } 156 }, 157 158 /** 159 * set the value / status of an input field based on it's type 160 * @param input 161 * @param value 162 */ 163 setValue: function(input,value) { 164 var i = $(input); 165 166 switch (i.attr('type')) { 167 case 'checkbox': 168 return i.attr('checked',value); 169 break; 170 default: 171 return i.val(value); 172 break; 173 } 116 174 } 117 175 } -
trunk/web-app/js/wizard.js
r209 r213 37 37 attachDateTimePickers(); 38 38 39 // SUBJECT PAGE39 // table handlers 40 40 attachTableEvents(); 41 41 resizeWizardTable(); 42 attach SubjectSlider();42 attachTableSlider(); 43 43 new TableEditor().init('div.table','div.row','div.column'); 44 45 // GROUPING PAGE46 new Grouping().init('div.subjects', 'div.subject', 'div.groups', 'div.group','div.add','div.remove');44 45 // accordeon(s) 46 $("#accordion").accordion(); 47 47 } 48 48 … … 189 189 // slide the contents of the table if the content of 190 190 // the table is wider than the table itself 191 function attach SubjectSlider() {191 function attachTableSlider() { 192 192 var slider = $("div#wizard").find('div.slider'); 193 193 var header = $("div#wizard").find('div.header');
Note: See TracChangeset
for help on using the changeset viewer.