source: trunk/grails-app/views/study/show.gsp @ 467

Last change on this file since 467 was 467, checked in by roberth, 9 years ago

Updated study view to show the events on a timeline.

  • Property svn:keywords set to Date Author Rev
File size: 26.9 KB
Line 
1
2<%@ page import="dbnp.studycapturing.Study" %>
3<html>
4  <head>
5    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
6    <meta name="layout" content="main" />
7    <g:set var="entityName" value="${message(code: 'study.label', default: 'Study')}" />
8    <title><g:message code="default.show.label" args="[entityName]" /></title>
9    <script type="text/javascript">
10      // Flag whether the timelines have been loaded
11      var timelineloaded = false;
12     
13      // Number of timelines that should be loaded
14      var numTimelines = ${studyList.size()};
15     
16      // This method is called on the event body.onLoad
17      $(function() {
18              $("#tabs").tabs({
19                show: function(event, ui) {
20                  // If the events tab is shown, the timeline should be redrawn
21                  if( ui.tab.hash == '#events' && !timelineloaded ) {
22                    loadTimeline( 'eventstimeline', 'eventtitles', 0 );
23                    timelineloaded = true;
24                  }
25                }
26              });
27      });
28    </script>
29    <link rel="stylesheet" type="text/css" href="${resource(dir: 'css', file: 'studies.css')}"/>
30
31    <!-- Include scripts for the SIMILE timeline. See http://simile-widgets.org/wiki/ -->
32    <script type="text/javascript">
33      Timeline_ajax_url="${resource(dir: 'js', file: 'timeline-simile/timeline_ajax/simile-ajax-api.js')}";
34      Timeline_urlPrefix='${resource(dir: 'js', file: 'timeline-simile/')}';
35      Timeline_parameters='bundle=true';
36    </script>
37    <script src="${resource(dir: 'js', file: 'timeline-simile/timeline-api.js')}" type="text/javascript"></script>
38    <script src="${resource(dir: 'js', file: 'timeline-simile/custom-timeline.js')}" type="text/javascript"></script>
39    <script src="${resource(dir: 'js', file: 'jquery-callback-1.2.js')}" type="text/javascript"></script>
40
41    <!-- Create the JSON objects for the timeline with events -->
42    <script type="text/javascript">
43         /*
44          * Creates timeline bands for displaying different timelines
45          *
46          * @returns array with BandInfo objects, as described on http://simile-widgets.org/wiki/Timeline_GettingStarted
47          */
48        function createTimelineBands( timelineNr ) {
49          var bandInfos = [];
50          var eventSources = [];
51          var overviewEventSource = new Timeline.DefaultEventSource();
52
53          // The way the timeline should look. See http://www.linuxjournal.com/article/9301
54          var theme = Timeline.ClassicTheme.create();
55          var emptyEtherPainter = new Timeline.EmptyEtherPainter( { theme: theme } )
56
57          // Now create the bands for all studies, and add them to one timeline
58          // Multiple timeline on one page do not seem to work
59          <g:set var="bandNr" value="${0}" />
60          <g:each in="${studyList}" var="study" status="timelineNr">
61              // The date that the timeline should start on
62              var dateStr = "<g:formatDate format="yyyy/MM/dd HH:mm:ss" date="${study.startDate}"/>";
63              firstDate = new Date ( dateStr );
64
65              //------------- Eventgroup overview ---------------
66
67              <g:set var="datesBandNr" value="${bandNr}" />
68              // Add an empty band to show the dates
69              bandInfos[${bandNr}] =
70                     Timeline.createBandInfo({
71                        width:          40,
72                        intervalUnit:   Timeline.DateTime.DAY,
73                        intervalPixels: 40,
74                        showEventText:  false,
75                        date:           firstDate,
76                        timeZone:       +1,
77                        layout:         'original',
78                        theme:          theme
79                     });
80              bandTitleInfo[ timelineNr ][ ${bandNr} ] = {
81                title: "${study.title}",
82                subjects: "",
83                className: "studytitle"
84              };
85
86              <g:set var="bandNr" value="${bandNr+1}" />
87
88              <g:each in="${study.eventGroups}" var="eventGroup" status="i">
89
90                //------------- Eventgroup ${bandNr} ---------------
91
92                // Create an eventsource for all events
93                eventSources[${bandNr}] = new Timeline.DefaultEventSource();
94
95                // Load events for this eventsource (using jquery)
96                var event_url = '${createLink(controller:'study', action:'events', id:eventGroup.id, params: [startDate: study.startDate])}';
97                $.getJSON(event_url, $.callback( _loadJSONEvents, [0, ${bandNr}, eventSources[${bandNr}], overviewEventSource, event_url] ) );
98
99                // Create a new timeline band
100                bandInfos[${bandNr}] =
101                       Timeline.createBandInfo({
102                           eventSource:    eventSources[${bandNr}],
103                           width:          30,
104                           intervalUnit:   Timeline.DateTime.DAY,
105                           intervalPixels: 40,
106                           date:           firstDate,
107                           timeZone:       +1,
108                           syncWith:       1,
109                           layout:         'original',
110                           theme:          theme
111                       });
112
113                // Make sure the date isn't printed by using the empty ether painter
114                bandInfos[${bandNr}].etherPainter = emptyEtherPainter;
115
116                // Add a title to the bandinfo
117                <% sortedGroupSubjects = eventGroup.subjects.sort( { a, b -> a.name <=> b.name } as Comparator )  %>
118                bandTitleInfo[ timelineNr ][ ${bandNr} ] = {
119                  title: "${eventGroup.name}",
120                  subjects: "${sortedGroupSubjects.name.join( ', ' )}"
121                };
122
123                <g:set var="bandNr" value="${bandNr+1}" />
124              </g:each>
125
126              // Synchronize all bands
127              <g:each in="${study.eventGroups}" var="eventGroup" status="i">
128                bandInfos[${i + datesBandNr +1}].syncWith = ${datesBandNr};
129              </g:each>
130
131          </g:each>
132
133          return bandInfos;
134        }
135     </script>
136</head>
137<body>
138
139  <div class="body" id="studies">
140    <h1><g:message code="default.show.label" args="[entityName]" /></h1>
141    <g:if test="${flash.message}">
142      <div class="message">${flash.message}</div>
143    </g:if>
144    <div class="dialog">
145      <div id="tabs">
146        <ul>
147          <li><a href="#study">Study Information</a></li>
148          <li><a href="#subjects">Subjects</a></li>
149          <li><a href="#events">Events</a></li>
150          <li><a href="#event-group">Event Groups</a></li>
151          <li><a href="#assays">Assays</a></li>
152          <li><a href="#persons">Persons</a></li>
153          <li><a href="#publications">Publications</a></li>
154        </ul>
155
156        <div id="study">
157          <table>
158            <!-- only show the head section if there are multiple studies -->
159            <g:if test="${multipleStudies}">
160              <thead>
161                <tr>
162                  <th></th>
163                  <g:each in="${studyList}" var="studyInstance">
164                    <th>${studyInstance.title}</th>
165                  </g:each>
166                </tr>
167              </thead>
168            </g:if>
169            <%
170              // Determine a union of the fields from all studies, in order
171              // to show a proper list. We want every field to appear just once,
172              // so the list is filtered for unique values
173              studyFields = studyList[0].giveDomainFields() + studyList*.giveTemplateFields().flatten().unique()
174            %>
175            <!-- Show all template and domain fields, if filled -->
176            <g:each in="${studyFields}" var="field">
177              <%
178                // If a value is not set for any of the selected studies, the
179                // field should not appear in the list
180                showField = true in studyList.collect { it.fieldExists( field.name ) && it.getFieldValue( field.name ) != null }.flatten()
181              %>
182              <g:if test="${showField}">
183                <tr>
184                  <td>${field}</td>
185                  <g:each in="${studyList}" var="studyInstance">
186                    <td>${studyInstance.getFieldValue(field.name)}</td>
187                  </g:each>
188                </tr>
189              </g:if>
190            </g:each>
191
192            <!-- Add some extra fields -->
193            <tr>
194              <td>Events</td>
195              <g:each in="${studyList}" var="studyInstance">
196                <td>
197                  <g:if test="${studyInstance.giveEventTemplates().size()==0}">
198                    -
199                  </g:if>
200                  <g:else>
201                   ${studyInstance.giveEventTemplates().name.join(", ")}
202                  </g:else>
203                </td>
204              </g:each>
205            </tr>
206            <tr>
207              <td>Sampling events</td>
208              <g:each in="${studyList}" var="studyInstance">
209                <td>
210                  <g:if test="${studyInstance.giveSamplingEventTemplates().size()==0}">
211                    -
212                  </g:if>
213                  <g:else>
214                   ${studyInstance.giveSamplingEventTemplates().name.join(", ")}
215                  </g:else>
216                </td>
217              </g:each>
218            </tr>
219            <tr>
220              <td>Readers</td>
221              <g:each in="${studyList}" var="studyInstance">
222                <td>
223                  <g:if test="${studyInstance.readers.size()==0}">
224                    -
225                  </g:if>
226                  <g:else>
227                    <g:each in="${studyInstance.readers}" var="r" status="i">
228                      <g:if test="${i > 0}">, </g:if>
229                      <g:link controller="user" action="show" id="${r.id}">${r?.encodeAsHTML()}</g:link>
230                    </g:each>
231                  </g:else>
232                </td>
233              </g:each>
234            </tr>
235            <tr>
236              <td>Editors</td>
237              <g:each in="${studyList}" var="studyInstance">
238                <td>
239                  <g:if test="${studyInstance.editors.size()==0}">
240                    -
241                  </g:if>
242                  <g:else>
243                    <g:each in="${studyInstance.editors}" var="r" status="i">
244                      <g:if test="${i > 0}">, </g:if>
245                      <g:link controller="user" action="show" id="${r.id}">${r?.encodeAsHTML()}</g:link>
246                    </g:each>
247                  </g:else>
248                </td>
249              </g:each>
250            </tr>
251
252          </table>
253        </div>
254
255        <div id="subjects">
256
257          <g:if test="${studyList*.subjects.flatten().size()==0}">
258            No subjects in the selected studies
259          </g:if>
260          <g:else>
261            <table>
262              <thead>
263                <tr>
264                  <g:if test="${multipleStudies}">
265                    <th></th>
266                  </g:if>
267                  <g:each in="${new dbnp.studycapturing.Subject().giveDomainFields()}" var="field">
268                    <th>${field}</th>
269                  </g:each>
270
271                  <%
272                    // Determine a union of the fields for all different
273                    // subjects in all studies. In order to show a proper list.
274                    // We want every field to appear just once,
275                    // so the list is filtered for unique values
276                    subjectTemplates = studyList*.giveSubjectTemplates().flatten().unique()
277                    subjectFields = subjectTemplates*.fields.flatten().unique()
278
279                    showSubjectFields = subjectFields
280
281                    /*
282                     * These lines are rewritten because
283                     * performance sucked
284                     *
285                     *   // These took about 9 seconds (for 31 subjects and
286                     *   allSubjects = studyList*.subjects.flatten()
287                     *
288                     *   subjectFields = subjectFields.findAll { subjectField ->
289                     *     ( true in allSubjects.collect { subject -> subject.fieldExists( subjectField.name ) && subject.getFieldValue( subjectField.name ) != null }.flatten() )
290                     *   }
291                     */
292
293                    // Filter out all fields that are left blank for all subjects
294                    allSubjects = studyList*.subjects.flatten()
295
296                    showSubjectFields = []
297                    subjectFields.each { subjectField ->
298                      for( subject in allSubjects )
299                      {
300                        // If the field is filled for this subject, we have to
301                        // show the field and should not check any other
302                        // subjects (hence the break)
303                        if( subject.fieldExists( subjectField.name ) && subject.getFieldValue( subjectField.name ) ) {
304                          showSubjectFields << subjectField;
305                          break;
306                        }
307                      }
308                    }
309                  %>
310
311                  <g:each in="${showSubjectFields}" var="field">
312                    <th>${field}</th>
313                  </g:each>
314
315                </tr>
316              </thead>
317
318              <g:set var="i" value="${1}" />
319
320              <g:each in="${studyList}" var="studyInstance">
321                <%
322                  // Sort subjects by name
323                  subjects = studyInstance.subjects;
324                  sortedSubjects = subjects.sort( { a, b -> a.name <=> b.name } as Comparator )
325                %>
326
327                <g:each in="${sortedSubjects}" var="subject" status="j">
328                  <tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
329                    <g:if test="${multipleStudies && j==0}">
330                      <td class="studytitle" rowspan="${sortedSubjects.size()}">
331                        ${studyInstance.title}
332                      </td>
333                    </g:if>
334                    <g:each in="${subject.giveDomainFields()}" var="field">
335                      <td>${subject.getFieldValue(field.name)}</td>
336                    </g:each>
337                 
338                    <g:each in="${showSubjectFields}" var="field">
339                      <td>
340                        <g:if test="${subject.fieldExists(field.name)}">
341                          ${subject.getFieldValue(field.name)}
342                        </g:if>
343                        <g:else>
344                          N/A
345                        </g:else>
346                      </td>
347                    </g:each>
348
349                  </tr>
350                  <g:set var="i" value="${i + 1}" />
351                </g:each>
352              </g:each>
353            </table>
354          </g:else>
355        </div>
356
357        <div id="events">
358          <g:if test="${studyList*.events.flatten().size()==0 && studyInstance*.samplingEvents.flatten().size()==0 }">
359            No events in these studies
360          </g:if>
361          <g:else>
362            <g:each in="${studyList}" var="study" status="i">
363              <div style="margin: 10px; ">
364                <div class="eventtitles" id="eventtitles-${i}"></div>
365                <div class="eventstimeline" id="eventstimeline-${i}"></div>
366              </div>
367            </g:each>
368            <noscript>
369              <table>
370                <thead>
371                  <tr>
372                    <g:if test="${multipleStudies}">
373                      <th></th>
374                    </g:if>
375                    <th>Start time</th>
376                    <th>Duration</th>
377                    <th>Type</th>
378                    <th>Sampling event</th>
379                    <th>Parameters</th>
380                  </tr>
381                </thead>
382
383                <g:set var="i" value="${1}" />
384
385                <g:each in="${studyList}" var="studyInstance">
386                  <%
387                    // Sort events by starttime and duration
388                    events = studyInstance.events + studyInstance.samplingEvents;
389                    sortedEvents = events.sort( { a, b ->
390                          a.startTime == b.startTime ?
391                            a.getDuration().toMilliseconds() <=> b.getDuration().toMilliseconds() :
392                            a.startTime <=> b.startTime
393                      } as Comparator )
394                  %>
395
396                  <g:each in="${sortedEvents}" var="event" status="j">
397                    <tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
398                      <g:if test="${multipleStudies && j==0}">
399                        <td class="studytitle" rowspan="${sortedEvents.size()}">
400                          ${studyInstance.title}
401                        </td>
402                      </g:if>
403                      <td>${event.getPrettyDuration(studyInstance.startDate,event.startTime)}</td>
404                      <td>${event.getPrettyDuration()}</td>
405                      <td>${event.template.name}</td>
406                      <td>
407                        <g:if test="${event instanceof dbnp.studycapturing.SamplingEvent}">
408                          <g:checkBox name="samplingEvent" disabled="${true}" value="${true}"/>
409                        </g:if>
410                        <g:else>
411                          <g:checkBox name="event" disabled="${true}" value="${false}" />
412                        </g:else>
413                      </td>
414                      <td>
415                        <g:set var="fieldCounter" value="${1}" />
416                        <g:each in="${event.giveTemplateFields()}" var="field">
417                          <g:if test="${event.getFieldValue(field.name)}">
418                            <g:if test="${fieldCounter > 1}">, </g:if>
419                              ${field.name} = ${event.getFieldValue( field.name )}
420                            <g:set var="fieldCounter" value="${fieldCounter + 1}" />
421                          </g:if>
422                        </g:each>
423                      </td>
424                    </tr>
425
426                    <g:set var="i" value="${i + 1}" />
427                  </g:each>
428                </g:each>
429              </table>
430
431            </noscript>
432
433          </g:else>
434        </div>
435
436        <div id="event-group">
437          <g:if test="${studyList*.eventGroups.flatten().size()==0}">
438            No event groups in this study
439          </g:if>
440          <g:else>
441            <%
442              // Determine a union of the event templates for all different
443              // eventgroups in all studies, in order to show a proper list.
444              // We want every field to appear just once,
445              // so the list is filtered for unique values
446              groupTemplates = studyList*.giveAllEventTemplates().flatten().unique()
447              subjectFields = subjectTemplates*.fields.flatten().unique()
448            %>
449            <table>
450              <thead>
451                <tr>
452                  <g:if test="${multipleStudies}">
453                    <th></th>
454                  </g:if>
455                  <th>Name</th>
456                  <th colspan="${groupTemplates.size()}">Events</th>
457                  <th>Subjects</th>
458                </tr>
459                <tr>
460                  <g:if test="${multipleStudies}">
461                    <th></th>
462                  </g:if>
463                  <th></th>
464                  <g:each in="${groupTemplates}" var="eventTemplate">
465                    <th>${eventTemplate.name}</th>
466                  </g:each>
467                  <th></th>
468                </tr>
469              </thead>
470
471              <g:set var="i" value="${1}" />
472
473              <g:each in="${studyList}" var="studyInstance">
474
475                <g:each in="${studyInstance.eventGroups}" var="eventGroup" status="j">
476                  <tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
477                    <g:if test="${multipleStudies && j==0}">
478                      <td class="studytitle" rowspan="${studyInstance.eventGroups.size()}">
479                        ${studyInstance.title}
480                      </td>
481                    </g:if>
482                    <td>${eventGroup.name}</td>
483
484                    <g:each in="${groupTemplates}" var="currentEventTemplate">
485                      <td>
486                        <g:each in="${eventGroup.events}" var="event">
487                          <g:if test="${event.template.name==currentEventTemplate.name}">
488
489                            <g:set var="fieldCounter" value="${1}" />
490                            <g:each in="${event.giveTemplateFields()}" var="field">
491                              <g:if test="${event.getFieldValue(field.name)}">
492                                <g:if test="${fieldCounter > 1}">, </g:if>
493                                  ${field.name} = ${event.getFieldValue( field.name )}
494                                <g:set var="fieldCounter" value="${fieldCounter + 1}" />
495                              </g:if>
496                            </g:each>
497                          </g:if>
498                        </g:each>
499                      </td>
500                    </g:each>
501                    <td>
502                      <% sortedGroupSubjects = eventGroup.subjects.sort( { a, b -> a.name <=> b.name } as Comparator )  %>
503                      ${sortedGroupSubjects.name.join( ', ' )}
504                    </td>
505                  </tr>
506
507                  <g:set var="i" value="${i + 1}" />
508                </g:each>
509
510              </g:each>
511
512            </table>
513          </g:else>
514        </div>
515
516        <div id="assays">
517          <g:if test="${studyList*.assays.flatten().size()==0}">
518            No assays in these studies
519          </g:if>
520          <g:else>
521            <table>
522              <thead>
523                <tr>
524                  <g:if test="${multipleStudies}">
525                    <th></th>
526                  </g:if>
527                  <th width="100">Assay Name</th>
528                  <th width="100">Module</th>
529                  <th>Type</th>
530                  <th width="150">Platform</th>
531                  <th>Url</th>
532                  <th>Samples</th>
533                </tr>
534              </thead>
535              <g:set var="i" value="${1}" />
536
537              <g:each in="${studyList}" var="studyInstance">
538                <g:each in="${studyInstance.assays}" var="assay" status="j">
539                  <tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
540                    <g:if test="${multipleStudies && j==0}">
541                      <td class="studytitle" rowspan="${studyInstance.assays.size()}">
542                        ${studyInstance.title}
543                      </td>
544                    </g:if>
545                    <td>${assay.name}</td>
546                    <td>${assay.module.name}</td>
547                    <td>${assay.module.type}</td>
548                    <td>${assay.module.platform}</td>
549                    <td>${assay.module.url}</td>
550                    <td>
551                      <% sortedAssaySamples = assay.samples.sort( { a, b -> a.name <=> b.name } as Comparator )  %>
552                      ${sortedAssaySamples.name.join( ', ' )}
553                    </td>
554                  </tr>
555                  <g:set var="i" value="${i + 1}" />
556
557                </g:each>
558              </g:each>
559            </table>
560          </g:else>
561        </div>
562
563        <div id="persons">
564          <%
565            // Determine a list of all persons
566            allPersons = studyList*.persons*.person.flatten().unique()
567          %>
568          <g:if test="${allPersons.size()==0}">
569            No persons involved in these studies
570          </g:if>
571          <g:else>
572            <table>
573              <tr>
574                <thead>
575                  <th>Name</th>
576                  <th>Affiliations</th>
577                  <th>Phone</th>
578                  <th>Email</th>
579                  <g:if test="${multipleStudies}">
580                    <g:each in="${studyList}" var="studyInstance">
581                      <th>${studyInstance.title}</th>
582                    </g:each>
583                  </g:if>
584                  <g:else>
585                    <th>Role</th>
586                  </g:else>
587                </thead>
588              </tr>
589              <g:each in="${allPersons}" var="person" status="i">
590                <tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
591                  <td>${person.firstName} ${person.prefix} ${person.lastName}</td>
592                  <td>
593                    ${person.affiliations.join(', ')}
594                  </td>
595                  <td>${person.phone}</td>
596                  <td>${person.email}</td>
597                  <g:each in="${studyList}" var="studyInstance">
598                    <%
599                      studyperson = studyInstance.persons.find { it.person == person }
600                    %>
601                    <td>
602                      <g:if test="${studyperson}">
603                        ${studyperson.role.name}
604                      </g:if>
605                     </td>
606                  </g:each>
607
608                </tr>
609              </g:each>
610            </table>
611          </g:else>
612        </div>
613
614        <div id="publications">
615          <%
616            // Determine a list of all persons
617            allPublications = studyList*.publications.flatten().unique()
618          %>
619          <g:if test="${allPublications.size()==0}">
620            No publications attached to these studies
621          </g:if>
622          <g:else>
623            <table>
624              <tr>
625                <thead>
626                  <th>Title</th>
627                  <th>Authors</th>
628                  <th>Comments</th>
629
630                  <g:if test="${multipleStudies}">
631                    <g:each in="${studyList}" var="studyInstance">
632                      <th>${studyInstance.title}</th>
633                    </g:each>
634                  </g:if>
635                </thead>
636              </tr>
637              <g:each in="${allPublications}" var="publication" status="i">
638                <tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
639                  <td>${publication.title}</td>
640                  <td>
641                    ${publication.authorsList}
642                  </td>
643                  <td>${publication.comments}</td>
644                  <g:if test="${multipleStudies}">
645                    <g:each in="${studyList}" var="studyInstance">
646                      <td>
647                        <g:if test="${publication in studyInstance.publications}">
648                          x
649                        </g:if>
650                      </td>
651                    </g:each>
652                  </g:if>
653                </tr>
654              </g:each>
655            </table>
656          </g:else>
657        </div>
658
659      </div>
660    </div>
661    <br>
662    <div class="buttons">
663      <g:form>
664        <g:if test="${studyList.size() == 1}">
665          <g:set var="studyInstance" value="${studyList[0]}" />
666          <g:hiddenField name="id" value="${studyInstance?.id}" />
667          <span class="button"><g:actionSubmit class="edit" action="edit" value="${message(code: 'default.button.edit.label', default: 'Edit')}" /></span>
668          <span class="button"><g:actionSubmit class="delete" action="delete" value="${message(code: 'default.button.delete.label', default: 'Delete')}" onclick="return confirm('${message(code: 'default.button.delete.confirm.message', default: 'Are you sure?')}');" /></span>
669        </g:if>
670        <span class="button"><g:link class="backToList" action="list">Back to list</g:link></span>
671      </g:form>
672    </div>
673
674  </div>
675</body>
676</html>
Note: See TracBrowser for help on using the repository browser.