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

Last change on this file since 1203 was 1203, checked in by robert@…, 10 years ago

Updated the events timeline in the study view, according to ticket #72

  • Property svn:keywords set to Author Date Rev
File size: 38.0 KB
Line 
1
2<%@ page import="dbnp.studycapturing.Study" %>
3<%@ page import="dbnp.studycapturing.EventGroup" %>
4<%@ page import="dbnp.studycapturing.RelTime" %>
5<html>
6  <head>
7    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
8    <meta name="layout" content="main" />
9    <g:set var="entityName" value="${message(code: 'study.label', default: 'Study')}" />
10    <title><g:message code="default.show.label" args="[entityName]" /></title>
11    <script type="text/javascript">
12      // Flag whether the timelines have been loaded
13      var timelineloaded = false;
14     
15      // Number of timelines that should be loaded
16      var numTimelines = ${studyList?.size()};
17     
18      // This method is called on the event body.onLoad
19      $(function() {
20              $("#tabs").tabs({
21                show: function(event, ui) {
22                  // If the events tab is shown, the timeline should be redrawn
23                  if( ui.tab.hash == '#events-timeline' && !timelineloaded ) {
24                    loadTimeline( 'eventstimeline', 'eventtitles', 0 );
25                    timelineloaded = true;
26                  }
27                }
28              });
29      });
30    </script>
31    <link rel="stylesheet" type="text/css" href="${resource(dir: 'css', file: 'studies.css')}"/>
32
33    <!-- Include scripts for the SIMILE timeline. See http://simile-widgets.org/wiki/ -->
34    <script type="text/javascript">
35      Timeline_ajax_url="${resource(dir: 'js', file: 'timeline-simile/timeline_ajax/simile-ajax-api.js')}";
36      Timeline_urlPrefix='${resource(dir: 'js', file: 'timeline-simile/')}';
37      Timeline_parameters='bundle=true';
38    </script>
39    <script src="${resource(dir: 'js', file: 'timeline-simile/timeline-api.js')}" type="text/javascript"></script>
40    <script src="${resource(dir: 'js', file: 'timeline-simile/custom-timeline.js')}" type="text/javascript"></script>
41    <script src="${resource(dir: 'js', file: 'timeline-simile/relative-time.js')}" type="text/javascript"></script>
42    <script src="${resource(dir: 'js', file: 'jquery-callback-1.2.js')}" type="text/javascript"></script>
43
44    <!-- Create the JSON objects for the timeline with events -->
45    <script type="text/javascript">
46         /*
47          * Creates timeline bands for displaying different timelines
48          *
49          * @returns array with BandInfo objects, as described on http://simile-widgets.org/wiki/Timeline_GettingStarted
50          */
51        function createTimelineBands( timelineNr ) {
52          var bandInfos = [];
53          var eventSources = [];
54          var overviewEventSource = new Timeline.DefaultEventSource();
55
56          // The way the timeline should look. See http://www.linuxjournal.com/article/9301
57          var theme = Timeline.ClassicTheme.create();
58          var emptyEtherPainter = new Timeline.EmptyEtherPainter( { theme: theme } )
59
60          // Now create the bands for all studies, and add them to one timeline
61          // Multiple timeline on one page do not seem to work
62          <g:set var="bandNr" value="${0}" />
63          <g:each in="${studyList}" var="study" status="timelineNr">
64              // The date that the timeline should start on
65              var dateStr = "<g:formatDate format="yyyy/MM/dd HH:mm:ss" date="${study.startDate}"/>";
66              firstDate = new Date ( dateStr );
67
68              //------------- Eventgroup overview ---------------
69
70              <g:set var="datesBandNr" value="${bandNr}" />
71              // Add an empty band to show the dates
72              bandInfos[${bandNr}] =
73                     Timeline.createBandInfo({
74                        width:          40,
75                        intervalUnit:   Timeline.DateTime.DAY,
76                        intervalPixels: 40,
77                        showEventText:  false,
78                        date:           firstDate,
79                        timeZone:       +1,
80                        layout:         'original',
81                        theme:          theme
82                     });
83
84                          // Make sure the date is printed using the relative time
85              bandInfos[${bandNr}].etherPainter = new Timeline.RelativeDateEtherPainter( { theme: theme, startDate: firstDate, unit: Timeline.DateTime.DAY } );
86                          bandInfos[${bandNr}].labeller = new Timeline.RelativeDateLabeller( "en", 0, firstDate );
87
88              bandTitleInfo[ timelineNr ][ ${bandNr} ] = {
89                title: "${study.title}",
90                subjects: "",
91                className: "studytitle"
92              };
93
94              <g:set var="bandNr" value="${bandNr+1}" />
95              <%
96                def sortedEventGroups = study.eventGroups.sort( { a, b ->
97                    return a.name <=> b.name;
98                }  as Comparator );
99
100                def orphans = study.getOrphanEvents();
101                if( orphans?.size() > 0 ) {
102                  sortedEventGroups.add( new EventGroup(
103                    id: -1,
104                    name: 'No group',
105                    events: orphans,
106                    subjects: []
107                  ));
108                }
109
110              %>
111              <g:each in="${sortedEventGroups}" var="eventGroup" status="i">
112
113                //------------- Eventgroup ${bandNr} ---------------
114
115                // Create an eventsource for all events
116                eventSources[${bandNr}] = new Timeline.DefaultEventSource();
117
118                // Load events for this eventsource (using jquery)
119                var event_url = '${createLink(controller:'study', action:'events', id:( eventGroup.id ? eventGroup.id : -1 ), params: [ startDate: study.startDate.getTime(), study: study.id ])}';
120                $.getJSON(event_url, $.callback( _loadJSONEvents, [0, ${bandNr}, eventSources[${bandNr}], overviewEventSource, event_url] ) );
121
122                // Create a new timeline band
123                bandInfos[${bandNr}] =
124                       Timeline.createBandInfo({
125                           eventSource:    eventSources[${bandNr}],
126                           width:          30,
127                           intervalUnit:   Timeline.DateTime.DAY,
128                           intervalPixels: 40,
129                           date:           firstDate,
130                           timeZone:       +1,
131                           syncWith:       1,
132                           layout:         'original',
133                           theme:          theme
134                       });
135
136                // Make sure the date isn't printed by using the empty ether painter
137                bandInfos[${bandNr}].etherPainter = emptyEtherPainter;
138
139                // Add a title to the bandinfo
140                <%
141                  sortedGroupSubjects = eventGroup.subjects.sort( { a, b -> a.name <=> b.name } as Comparator );
142                  def simpleSubjects = sortedGroupSubjects.name.join( ', ' );
143
144                  // We can only show appr. 30 characters per line and as many lines as there are events
145                  def charsPerLine = 30;
146                  def numEvents = eventGroup.events?.size();
147                  def maxChars = numEvents * charsPerLine;
148
149                  // If the subjects will fit, show them all
150                  if( simpleSubjects?.size() < maxChars ) {
151                    showSubjects = simpleSubjects;
152                  } else {
153                    // Always add the first name
154                    def subjectNames = sortedGroupSubjects[0]?.name;
155
156                    // Continue adding names until the length is to long
157                    id = 0;
158                    sortedGroupSubjects.each { subject ->
159                      if( id > 0 ) {
160                        println( "ID: " + id + " - " + subjectNames?.size() + " - " + subject.name?.size() + " - " + maxChars );
161                        if( subjectNames?.size() + subject.name?.size() < maxChars - 15 ) {
162                          subjectNames += ", " + subject.name;
163                        } else {
164                          return;
165                        }
166                      }
167                      id++;
168                    }
169
170                    // Add a postfix
171                    subjectNames += " and " + ( sortedGroupSubjects?.size() - id ) + " more";
172
173                    showSubjects = subjectNames;
174                  }
175
176
177                %>
178                bandTitleInfo[ timelineNr ][ ${bandNr} ] = {
179                  title: "${eventGroup.name}",
180                  className: "<g:if test="${ eventGroup.id == -1 || !eventGroup.id  }">no_group</g:if>",
181                  subjects: "${showSubjects}"
182                };
183
184                <g:set var="bandNr" value="${bandNr+1}" />
185              </g:each>
186
187              // Synchronize all bands
188              <g:each in="${sortedEventGroups}" var="eventGroup" status="i">
189                bandInfos[${i + datesBandNr +1}].syncWith = ${datesBandNr};
190              </g:each>
191
192          </g:each>
193
194          return bandInfos;
195        }
196     </script>
197</head>
198<body>
199
200  <div class="body" id="studies">
201    <h1><g:message code="default.show.label" args="[entityName]" /></h1>
202    <g:if test="${flash.message}">
203      <div class="message">${flash.message}</div>
204    </g:if>
205    <div class="dialog">
206      <div id="tabs">
207        <ul>
208          <li><a href="#study">Study Information</a></li>
209          <li><a href="#subjects">Subjects</a></li>
210          <li><a href="#events-timeline">Events timeline</a></li>
211          <li><a href="#events-table">Events table</a></li>
212          <li><a href="#assays">Assays</a></li>
213          <li><a href="#samples">Samples</a></li>
214          <li><a href="#persons">Persons</a></li>
215          <li><a href="#publications">Publications</a></li>
216        </ul>
217
218        <div id="study">
219          <table>
220            <!-- only show the head section if there are multiple studies -->
221            <g:if test="${multipleStudies}">
222              <thead>
223                <tr>
224                  <th></th>
225                  <g:each in="${studyList}" var="studyInstance">
226                    <th>${studyInstance.title}</th>
227                  </g:each>
228                </tr>
229              </thead>
230            </g:if>
231            <%
232              // Determine a union of the fields from all studies, in order
233              // to show a proper list. We want every field to appear just once,
234              // so the list is filtered for unique values
235              studyFields = studyList[0].giveDomainFields() + studyList*.giveTemplateFields()?.flatten().unique()
236            %>
237            <!-- Show all template and domain fields, if filled -->
238            <g:each in="${studyFields}" var="field">
239              <%
240                // If a value is not set for any of the selected studies, the
241                // field should not appear in the list
242                showField = true in studyList.collect { it.fieldExists( field.name ) && it.getFieldValue( field.name ) != null }?.flatten()
243              %>
244              <g:if test="${showField}">
245                <tr>
246                  <td>${field}</td>
247                  <g:each in="${studyList}" var="studyInstance">
248                    <td>
249                                          <g:if test="${studyInstance.fieldExists(field.name)}">
250                                                <wizard:showTemplateField field="${field}" entity="${studyInstance}" />
251                                          </g:if>
252                                          <g:else>
253                                                -
254                                          </g:else>
255                                        </td>
256                  </g:each>
257                </tr>
258              </g:if>
259            </g:each>
260
261            <!-- Add some extra fields -->
262            <tr>
263              <td>Events</td>
264              <g:each in="${studyList}" var="studyInstance">
265                <td>
266                  <g:if test="${studyInstance.giveEventTemplates()?.size()==0}">
267                    -
268                  </g:if>
269                  <g:else>
270                                        ${studyInstance.giveEventTemplates().name.join(", ")}
271                  </g:else>
272                </td>
273              </g:each>
274            </tr>
275            <tr>
276              <td>Sampling events</td>
277              <g:each in="${studyList}" var="studyInstance">
278                <td>
279                  <g:if test="${studyInstance.giveSamplingEventTemplates()?.size()==0}">
280                    -
281                  </g:if>
282                  <g:else>
283                   ${studyInstance.giveSamplingEventTemplates().name.join(", ")}
284                  </g:else>
285                </td>
286              </g:each>
287            </tr>
288            <tr>
289              <td>Public</td>
290              <g:each in="${studyList}" var="studyInstance">
291                <td>
292                   ${studyInstance.publicstudy}
293                </td>
294              </g:each>
295            </tr>
296            <tr>
297              <td>Owner</td>
298              <g:each in="${studyList}" var="studyInstance">
299                <td>
300                   ${studyInstance.owner?.username}
301                </td>
302              </g:each>
303            </tr>
304            <tr>
305              <td>Readers</td>
306              <g:each in="${studyList}" var="studyInstance">
307                <td>
308                  <g:if test="${studyInstance.readers.size() == 0}">
309                    -
310                  </g:if>
311                  <g:else>
312                    ${studyInstance.readers.username.join( ", " )}
313                  </g:else>
314                </td>
315              </g:each>
316            </tr>
317            <tr>
318              <td>Writers</td>
319              <g:each in="${studyList}" var="studyInstance">
320                <td>
321                  <g:if test="${studyInstance.writers?.size()==0}">
322                    -
323                  </g:if>
324                  <g:else>
325                    ${studyInstance.writers.username.join( ", " )}
326                  </g:else>
327                </td>
328              </g:each>
329            </tr>
330          </table>
331        </div>
332
333        <div id="subjects">
334
335          <g:if test="${studyList*.subjects?.flatten()?.size()==0}">
336            No subjects in the selected studies
337          </g:if>
338          <g:else>
339            <table>
340              <thead>
341                <tr>
342                  <g:if test="${multipleStudies}">
343                    <th></th>
344                  </g:if>
345                  <g:each in="${new dbnp.studycapturing.Subject().giveDomainFields()}" var="field">
346                    <th>${field}</th>
347                  </g:each>
348
349                  <%
350                    // Determine a union of the fields for all different
351                    // subjects in all studies. In order to show a proper list.
352                    // We want every field to appear just once,
353                    // so the list is filtered for unique values
354                    subjectTemplates = studyList*.giveSubjectTemplates()?.flatten().unique()
355                    if( !subjectTemplates ) {
356                      subjectTemplates = [];
357                      subjectFields = [];
358                    } else {
359                      subjectFields = subjectTemplates*.fields?.flatten().unique()
360                      if( !subjectFields ) {
361                        subjectFields = [];
362                      }
363                    }
364
365                    /*
366                     * These lines are rewritten because
367                     * performance sucked
368                     *
369                     *   // These took about 9 seconds (for 31 subjects and
370                     *   allSubjects = studyList*.subjects?.flatten()
371                     *
372                     *   subjectFields = subjectFields.findAll { subjectField ->
373                     *     ( true in allSubjects.collect { subject -> subject.fieldExists( subjectField.name ) && subject.getFieldValue( subjectField.name ) != null }.flatten() )
374                     *   }
375                     */
376
377                    // Filter out all fields that are left blank for all subjects
378                    allSubjects = studyList*.subjects?.flatten()
379
380                    showSubjectFields = []
381                    subjectFields.each { subjectField ->
382                      for( subject in allSubjects )
383                      {
384                        // If the field is filled for this subject, we have to
385                        // show the field and should not check any other
386                        // subjects (hence the break)
387                        if( subject.fieldExists( subjectField.name ) && subject.getFieldValue( subjectField.name ) ) {
388                          showSubjectFields << subjectField;
389                          break;
390                        }
391                      }
392                    }
393                  %>
394
395                  <g:each in="${showSubjectFields}" var="field">
396                    <th>${field}</th>
397                  </g:each>
398
399                </tr>
400              </thead>
401
402              <g:set var="i" value="${1}" />
403
404              <g:each in="${studyList}" var="studyInstance">
405                <%
406                  // Sort subjects by name
407                  subjects = studyInstance.subjects;
408                  sortedSubjects = subjects.sort( { a, b -> a.name <=> b.name } as Comparator )
409                %>
410
411                <g:each in="${sortedSubjects}" var="subject" status="j">
412                  <tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
413                    <g:if test="${multipleStudies && j==0}">
414                      <td class="studytitle" rowspan="${sortedSubjects?.size()}">
415                        ${studyInstance.title}
416                      </td>
417                    </g:if>
418                    <g:each in="${subject.giveDomainFields()}" var="field">
419                      <td><wizard:showTemplateField field="${field}" entity="${subject}" /></td>
420                    </g:each>
421                 
422                    <g:each in="${showSubjectFields}" var="field">
423                      <td>
424                        <g:if test="${subject.fieldExists(field.name)}">
425                                <wizard:showTemplateField field="${field}" entity="${subject}" />
426                        </g:if>
427                        <g:else>
428                          N/A
429                        </g:else>
430                      </td>
431                    </g:each>
432
433                  </tr>
434                  <g:set var="i" value="${i + 1}" />
435                </g:each>
436              </g:each>
437            </table>
438          </g:else>
439        </div>
440
441        <div id="events-timeline">
442          <g:if test="${studyList*.events?.flatten()?.size()==0 && studyInstance*.samplingEvents?.flatten()?.size()==0 }">
443            No events in these studies
444          </g:if>
445          <g:else>
446            <g:each in="${studyList}" var="study" status="i">
447              <div style="margin: 10px; ">
448                <div class="eventtitles" id="eventtitles-${i}"></div>
449                <div class="eventstimeline" id="eventstimeline-${i}"></div>
450              </div>
451            </g:each>
452            <noscript>
453              <table>
454                <thead>
455                  <tr>
456                    <g:if test="${multipleStudies}">
457                      <th></th>
458                    </g:if>
459                    <th>Start time</th>
460                    <th>Duration</th>
461                    <th>Type</th>
462                    <th>Sampling event</th>
463                    <th>Parameters</th>
464                  </tr>
465                </thead>
466
467                <g:set var="i" value="${1}" />
468
469                <g:each in="${studyList}" var="studyInstance">
470                  <%
471                    // Sort events by starttime and duration
472                    events = studyInstance.events + studyInstance.samplingEvents;
473                    sortedEvents = events.sort( { a, b ->
474                          //a.startTime == b.startTime ?
475                            //a.getDuration().getValue() <=> b.getDuration().getValue() :
476                          a.startTime <=> b.startTime
477                      } as Comparator )
478                  %>
479
480                  <g:each in="${sortedEvents}" var="event" status="j">
481                    <tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
482                      <g:if test="${multipleStudies && j==0}">
483                        <td class="studytitle" rowspan="${sortedEvents?.size()}">
484                          ${studyInstance.title}
485                        </td>
486                      </g:if>
487                      <td>${event.getStartTimeString()}</td>
488                      <td>${((event.getClass() == 'Event') ? event.getDurationString() : '')}</td>
489                      <td>${event.template.name}</td>
490                      <td>
491                        <g:if test="${event instanceof dbnp.studycapturing.SamplingEvent}">
492                          <g:checkBox name="samplingEvent" disabled="${true}" value="${true}"/>
493                        </g:if>
494                        <g:else>
495                          <g:checkBox name="event" disabled="${true}" value="${false}" />
496                        </g:else>
497                      </td>
498                      <td>
499                        <g:set var="fieldCounter" value="${1}" />
500                        <g:each in="${event.giveTemplateFields()}" var="field">
501                          <g:if test="${event.getFieldValue(field.name)}">
502                            <g:if test="${fieldCounter > 1}">, </g:if>
503                              ${field.name} = <wizard:showTemplateField field="${field}" entity="${event}" />
504                            <g:set var="fieldCounter" value="${fieldCounter + 1}" />
505                          </g:if>
506                        </g:each>
507                      </td>
508                    </tr>
509
510                    <g:set var="i" value="${i + 1}" />
511                  </g:each>
512                </g:each>
513              </table>
514
515            </noscript>
516
517          </g:else>
518        </div>
519
520        <div id="events-table">
521          <g:if test="${studyList*.eventGroups?.flatten()?.size()==0}">
522            No event groups in this study
523          </g:if>
524          <g:else>
525            <%
526              // Determine a union of the event templates for all different
527              // eventgroups in all studies, in order to show a proper list.
528              // We want every field to appear just once,
529              // so the list is filtered for unique values
530              def groupTemplates = studyList*.giveAllEventTemplates()?.flatten().unique()
531                          def showTemplates = groupTemplates;
532
533                          def showProperties = [:];
534                          def allEvents = studyList*.events.flatten() + studyList*.samplingEvents.flatten();
535                          def eventColumns = 0;
536
537                          showTemplates.each { template ->
538                                // We want to show all properties only once. If the properties are never filled
539                                // we shouldn't show them at all.
540                                def showFields = []
541                                template.fields.each { field ->
542                                  for( def event: allEvents.findAll { it.template == template } ) {
543                                        if( event.getFieldValue( field.name ) ) {
544                                          showFields << field;
545                                          break;
546                                        }
547                                  }
548                                }
549
550                                showProperties[ template.name ] = showFields;
551
552                                // Compute the total number of columns under 'Events' (the +1 is
553                                // because of the 'start time' column)
554                                eventColumns += [ 1, showFields.size() + 1 ].max();
555                          }
556
557            %>
558            <table>
559              <thead>
560                <tr>
561                  <g:if test="${multipleStudies}">
562                    <th></th>
563                  </g:if>
564                  <th>Name</th>
565                  <th colspan="${eventColumns}">Events</th>
566                  <th>Subjects</th>
567                </tr>
568                <tr>
569                  <g:if test="${multipleStudies}">
570                    <th></th>
571                  </g:if>
572                  <th></th>
573                  <g:each in="${showTemplates}" var="eventTemplate">
574                    <th colspan="${[1, showProperties[ eventTemplate.name ].size() + 1 ].max()}">${eventTemplate.name}</th>
575                  </g:each>
576                  <th></th>
577                </tr>
578                <tr class="templateFields">
579                  <g:if test="${multipleStudies}">
580                    <th></th>
581                  </g:if>
582                  <th></th>
583                  <g:each in="${showTemplates}" var="eventTemplate">
584                                        <th>start time</th>
585                                        <g:if test="${showProperties[ eventTemplate.name ].size() > 0}">
586                                          <g:each in="${showProperties[ eventTemplate.name ]}" var="field">
587                                                <th>${field.name}</th>
588                                          </g:each>
589                                        </g:if>
590                  </g:each>
591                  <th></th>
592                </tr>
593              </thead>
594
595              <g:set var="i" value="${1}" />
596
597              <g:each in="${studyList}" var="studyInstance">
598                <%
599                  // Sort the groups by name
600                                  def sortedEventGroups = studyInstance.eventGroups.sort( { a, b ->
601                      return a.name <=> b.name;
602                  }  as Comparator );
603
604                                  // Determine the number of rows per group (depending on the max
605                                  // number of events per template in a group)
606                                  def maxNumberEventsPerTemplate = [:];
607                                  def rowsPerStudy = 0;
608                                  sortedEventGroups.each { group ->
609                                        def max = 1;
610                                        showTemplates.each { template ->
611                                          def num = ( group.events + group.samplingEvents ).findAll { it.template == template }.size();
612                                          if( num > max )
613                                                max = num;
614                                        }
615                                        maxNumberEventsPerTemplate[group.name] = max;
616                                        rowsPerStudy += max;
617                                  }
618
619                  def orphans = studyInstance.getOrphanEvents();
620                  if( orphans?.size() > 0 ) {
621                    sortedEventGroups.add( new EventGroup(
622                      id: -1,
623                      name: 'No group',
624                      events: orphans,
625                      subjects: []
626                    ));
627                  }
628                %>
629                <g:each in="${sortedEventGroups}" var="eventGroup" status="j">
630                                  <g:set var="n" value="${1}" />
631                  <g:while test="${n <= maxNumberEventsPerTemplate[ eventGroup.name ]}">
632
633                                        <tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
634                                          <g:if test="${n == 1}">
635                                                <g:if test="${multipleStudies && j==0}">
636                                                  <td class="studytitle" rowspan="${rowsPerStudy}">
637                                                        ${studyInstance.title}
638                                                  </td>
639                                                </g:if>
640                                                <td rowspan="${maxNumberEventsPerTemplate[ eventGroup.name ]}">${eventGroup.name}</td>
641                                          </g:if>
642                                       
643                                          <g:each in="${showTemplates}" var="currentEventTemplate">
644                                                <g:if test="${showProperties[ currentEventTemplate.name ].size() == 0}">
645                                                  <td>&nbsp;</td>
646                                                </g:if>
647                                                <g:else>
648                                                  <%
649                                                        def templateEvents = (eventGroup.events + eventGroup.samplingEvents).findAll { it.template == currentEventTemplate }.sort { a, b -> a.startTime <=> b.startTime }.asType(List)
650                                                        def event = templateEvents.size() >= n ? templateEvents[ n - 1 ] : null;
651                                                  %>
652                                                  <td class="templateFieldValue"><g:if test="${event}">${new RelTime( event.startTime ).toString()}</g:if></td>
653                                                  <g:each in="${showProperties[ currentEventTemplate.name ]}" var="field">
654                                                        <td class="templateFieldValue"><wizard:showTemplateField field="${field}" entity="${event}" /></td>
655                                                  </g:each>
656                                                </g:else>
657                                          </g:each>
658                                       
659                                          <g:if test="${n == 1}">
660                                                <% sortedGroupSubjects = eventGroup.subjects.sort( { a, b -> a.name <=> b.name } as Comparator )  %>
661
662                                                <td rowspan="${maxNumberEventsPerTemplate[ eventGroup.name ]}" title="${sortedGroupSubjects.name.join( ', ' )}">
663                                                        <g:if test="${eventGroup.subjects.size()==0}">
664                                                                -
665                                                        </g:if>
666                                                        <g:else>
667                                                                <g:each in="${eventGroup.subjects.species.unique()}" var="currentSpecies" status="k">
668                                                                        <g:if test="${k > 0}">,</g:if>
669                                                                        <%=eventGroup.subjects.findAll { return it.species == currentSpecies; }.size() %>
670                                                                        ${currentSpecies}
671                                                                </g:each>
672                                                        </g:else>
673                                                </td>
674                                          </g:if>
675                                        </tr>
676
677
678                                        <g:set var="n" value="${n+1}" />
679                                  </g:while>
680
681                  <g:set var="i" value="${i + 1}" />
682                </g:each>
683
684              </g:each>
685
686            </table>
687          </g:else>
688        </div>
689
690        <div id="assays">
691          <g:if test="${studyList*.assays?.flatten()?.size()==0}">
692            No assays in these studies
693          </g:if>
694          <g:else>
695            <table>
696              <thead>
697                <tr>
698                  <g:if test="${multipleStudies}">
699                    <th></th>
700                  </g:if>
701                        <th width="100">Assay Code</th>
702                  <th width="100">Assay Name</th>
703                  <th width="100">Module</th>
704                  <th width="150">Platform</th>
705                  <th>Link</th>
706                  <th>Samples</th>
707                </tr>
708              </thead>
709              <g:set var="i" value="${1}" />
710
711              <g:each in="${studyList}" var="studyInstance">
712                <g:each in="${studyInstance.assays}" var="assay" status="j">
713                  <tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
714                    <g:if test="${multipleStudies && j==0}">
715                      <td class="studytitle" rowspan="${studyInstance.assays?.size()}">
716                        ${studyInstance.title}
717                      </td>
718                    </g:if>
719                          <td>${assay.token}</td>
720                    <td>${assay.name}</td>
721                    <td>${assay.module.name}</td>
722                    <td>${assay.module.platform}</td>
723                    %{--<td><a href="${assay.module.url}/assay/${assay.externalAssayID}">view</a></td>--}%
724                    <td><jumpbar:link
725                      linkDest="${createLink(action:'show', id:studyInstance.id)}"
726                      linkText='Go back to GSCF'
727                      frameSource="${assay.module.url}/assay/showByToken/${assay.externalAssayID}"
728                      pageTitle="Assay View in Module">
729                      view
730                    </jumpbar:link></td>
731                    <td>
732                      <% sortedAssaySamples = assay.samples.sort( { a, b -> a.name <=> b.name } as Comparator )  %>
733                      ${sortedAssaySamples.name.join( ', ' )}
734                    </td>
735                  </tr>
736                  <g:set var="i" value="${i + 1}" />
737
738                </g:each>
739              </g:each>
740            </table>
741          </g:else>
742        </div>
743
744        <div id="samples">
745
746          <g:if test="${studyList*.samples.flatten()?.size()==0}">
747            No samples in the selected studies
748          </g:if>
749          <g:else>
750            <table>
751              <thead>
752                <tr>
753                  <g:if test="${multipleStudies}">
754                    <th></th>
755                  </g:if>
756
757                        <th>Parent Subject</th>
758                        <th>Parent Sampling Event</th>
759
760
761                  <g:each in="${new dbnp.studycapturing.Sample().giveDomainFields()}" var="field">
762                    <th>${field}</th>
763                  </g:each>
764
765                  <%
766                    // Determine a union of the fields for all different
767                    // samples in all studies. In order to show a proper list.
768                    // We want every field to appear just once,
769                    // so the list is filtered for unique values
770                    sampleTemplates = studyList*.giveSampleTemplates().flatten().unique()
771
772                    if( !sampleTemplates ) {
773                      sampleTemplates = [];
774                      sampleFields = [];
775                      showSampleFields = [];
776                    } else {
777                      sampleFields = sampleTemplates*.fields.flatten().unique()
778                      if( !sampleFields ) {
779                        sampleFields = [];
780                        showSampleFields = [];
781                      } else {
782                        // Filter out all fields that are left blank for all samples
783                        allSamples = studyList*.samples.flatten()
784
785                        showSampleFields = [];
786                        sampleFields.each { sampleField ->
787                          for( sample in allSamples )
788                          {
789                            // If the field is filled for this subject, we have to
790                            // show the field and should not check any other
791                            // samples (hence the break)
792                            if( sample.fieldExists( sampleField.name ) && sample.getFieldValue( sampleField.name ) ) {
793                              showSampleFields << sampleField;
794                              break;
795                            }
796                          }
797                        }
798                      }
799                    }
800                  %>
801
802                  <g:each in="${showSampleFields}" var="field">
803                    <th>${field}</th>
804                  </g:each>
805
806                </tr>
807              </thead>
808
809              <g:set var="i" value="${1}" />
810
811              <g:each in="${studyList}" var="studyInstance">
812                <%
813                  // Sort samples by name
814                  samples = studyInstance.samples;
815                  sortedSamples = samples.sort( { a, b -> a.name <=> b.name } as Comparator )
816                %>
817
818                <g:each in="${sortedSamples}" var="sample" status="j">
819                  <tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
820                    <g:if test="${multipleStudies && j==0}">
821                      <td class="studytitle" rowspan="${sortedSamples?.size()}">
822                        ${studyInstance.title}
823                      </td>
824                    </g:if>
825                          <td>${sample.parentSubject?.name}</td>
826                          <td>${sample.parentEvent?.template?.name} at ${sample.parentEvent?.getStartTimeString()}</td>
827                    <g:each in="${sample.giveDomainFields()}" var="field">
828                      <td><wizard:showTemplateField field="${field}" entity="${sample}" /></td>
829                    </g:each>
830
831                    <g:each in="${showSampleFields}" var="field">
832                      <td>
833                        <g:if test="${sample.fieldExists(field.name)}">
834                          <wizard:showTemplateField field="${field}" entity="${sample}" />
835                        </g:if>
836                        <g:else>
837                          N/A
838                        </g:else>
839                      </td>
840                    </g:each>
841
842                  </tr>
843                  <g:set var="i" value="${i + 1}" />
844                </g:each>
845              </g:each>
846
847            </table>
848          </g:else>
849        </div>
850
851        <div id="persons">
852          <%
853            // Determine a list of all persons
854            allPersons = studyList*.persons*.person.flatten().unique()
855          %>
856          <g:if test="${allPersons?.size()==0}">
857            No persons involved in these studies
858          </g:if>
859          <g:else>
860            <table>
861              <tr>
862                <thead>
863                  <th>Name</th>
864                  <th>Affiliations</th>
865                  <th>Phone</th>
866                  <th>Email</th>
867                  <g:if test="${multipleStudies}">
868                    <g:each in="${studyList}" var="studyInstance">
869                      <th>${studyInstance.title}</th>
870                    </g:each>
871                  </g:if>
872                  <g:else>
873                    <th>Role</th>
874                  </g:else>
875                </thead>
876              </tr>
877              <g:each in="${allPersons}" var="person" status="i">
878                <tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
879                  <td>${person.firstName} ${person.prefix} ${person.lastName}</td>
880                  <td>
881                    ${person.affiliations.join(', ')}
882                  </td>
883                  <td>${person.phone}</td>
884                  <td>${person.email}</td>
885                  <g:each in="${studyList}" var="studyInstance">
886                    <%
887                      studyperson = studyInstance.persons.find { it.person == person }
888                    %>
889                    <td>
890                      <g:if test="${studyperson}">
891                        ${studyperson.role.name}
892                      </g:if>
893                     </td>
894                  </g:each>
895
896                </tr>
897              </g:each>
898            </table>
899          </g:else>
900        </div>
901
902        <div id="publications">
903          <%
904            // Determine a list of all persons
905            allPublications = studyList*.publications.flatten().unique()
906          %>
907          <g:if test="${allPublications?.size()==0}">
908            No publications attached to these studies
909          </g:if>
910          <g:else>
911            <table>
912              <tr>
913                <thead>
914                  <th>Title</th>
915                  <th>Authors</th>
916                  <th>Comments</th>
917
918                  <g:if test="${multipleStudies}">
919                    <g:each in="${studyList}" var="studyInstance">
920                      <th>${studyInstance.title}</th>
921                    </g:each>
922                  </g:if>
923                </thead>
924              </tr>
925              <g:each in="${allPublications}" var="publication" status="i">
926                <tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
927                  <td>${publication.title}</td>
928                  <td>
929                    ${publication.authorsList}
930                  </td>
931                  <td>${publication.comments}</td>
932                  <g:if test="${multipleStudies}">
933                    <g:each in="${studyList}" var="studyInstance">
934                      <td>
935                        <g:if test="${publication in studyInstance.publications}">
936                          x
937                        </g:if>
938                      </td>
939                    </g:each>
940                  </g:if>
941                </tr>
942              </g:each>
943            </table>
944          </g:else>
945        </div>
946
947      </div>
948    </div>
949    <br>
950    <div class="buttons">
951      <g:form action="delete">
952        <g:if test="${studyList?.size() == 1}">
953          <g:set var="studyInstance" value="${studyList[0]}" />
954          <g:hiddenField name="id" value="${studyInstance?.id}" />
955          <g:if test="${studyInstance.canWrite(loggedInUser)}">
956            <span class="button"><g:link class="edit" controller="wizard" params="[jump:'edit']" id="${studyInstance?.id}">${message(code: 'default.button.edit.label', default: 'Edit')}</g:link></span>
957          </g:if>
958          <g:if test="${studyInstance.isOwner(loggedInUser)}">
959            <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>
960          </g:if>
961          </g:if>
962        <span class="button"><g:link class="backToList" action="list">Back to list</g:link></span>
963      </g:form>
964    </div>
965
966  </div>
967</body>
968</html>
Note: See TracBrowser for help on using the repository browser.