Changeset 1213


Ignore:
Timestamp:
Nov 29, 2010, 4:56:48 PM (13 years ago)
Author:
robert@…
Message:

Improved the study overview page such that the different tabs are loaded when needed. Also rewritten parts of the code. See ticket #155

Location:
trunk
Files:
8 added
6 edited

Legend:

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

    r1203 r1213  
    124124        }
    125125    }
     126
     127        /**
     128     * Shows the subjects tab of one or more studies. Is called when opening the subjects-tab
     129         * on the study overview screen.
     130     */
     131    def show_subjects = {
     132                def studyList = readStudies( params.id );
     133
     134                if( !studyList )
     135                        return
     136
     137                [studyList: studyList, studyInstanceTotal: Study.count(), multipleStudies: ( studyList.size() > 1 ), loggedInUser: AuthenticationService.getLoggedInUser() ]
     138    }
     139
     140        /**
     141     * Shows the events timeline tab of one or more studies. Is called when opening the events timeline-tab
     142         * on the study overview screen.
     143     */
     144    def show_events_timeline = {
     145                def studyList = readStudies( params.id );
     146
     147                if( !studyList )
     148                        return
     149
     150                [studyList: studyList, studyInstanceTotal: Study.count(), multipleStudies: ( studyList.size() > 1 ), loggedInUser: AuthenticationService.getLoggedInUser() ]
     151    }
     152
     153        /**
     154     * Shows the events table tab of one or more studies. Is called when opening the events table-tab
     155         * on the study overview screen.
     156     */
     157    def show_events_table = {
     158                def studyList = readStudies( params.id );
     159
     160                if( !studyList )
     161                        return
     162
     163                [studyList: studyList, studyInstanceTotal: Study.count(), multipleStudies: ( studyList.size() > 1 ), loggedInUser: AuthenticationService.getLoggedInUser() ]
     164    }
     165
     166        /**
     167     * Shows the assays tab of one or more studies. Is called when opening the assays tab
     168         * on the study overview screen.
     169     */
     170    def show_assays = {
     171                def studyList = readStudies( params.id );
     172
     173                if( !studyList )
     174                        return
     175
     176                [studyList: studyList, studyInstanceTotal: Study.count(), multipleStudies: ( studyList.size() > 1 ), loggedInUser: AuthenticationService.getLoggedInUser() ]
     177    }
     178
     179        /**
     180     * Shows the samples tab of one or more studies. Is called when opening the samples-tab
     181         * on the study overview screen.
     182     */
     183    def show_samples = {
     184                def studyList = readStudies( params.id );
     185
     186                if( !studyList )
     187                        return
     188
     189                [studyList: studyList, studyInstanceTotal: Study.count(), multipleStudies: ( studyList.size() > 1 ), loggedInUser: AuthenticationService.getLoggedInUser() ]
     190    }
     191
     192        /**
     193     * Shows the persons tab of one or more studies. Is called when opening the persons tab
     194         * on the study overview screen.
     195     */
     196    def show_persons = {
     197                def studyList = readStudies( params.id );
     198
     199                if( !studyList )
     200                        return
     201
     202                [studyList: studyList, studyInstanceTotal: Study.count(), multipleStudies: ( studyList.size() > 1 ), loggedInUser: AuthenticationService.getLoggedInUser() ]
     203    }
     204
     205        /**
     206     * Shows the publications tab of one or more studies. Is called when opening the publications tab
     207         * on the study overview screen.
     208     */
     209    def show_publications = {
     210                def studyList = readStudies( params.id );
     211
     212                if( !studyList )
     213                        return
     214
     215                [studyList: studyList, studyInstanceTotal: Study.count(), multipleStudies: ( studyList.size() > 1 ), loggedInUser: AuthenticationService.getLoggedInUser() ]
     216    }
     217
     218        /**
     219         * Creates the javascript for showing the timeline of one or more studies
     220         */
     221        def createTimelineBandsJs = {
     222                def studyList = readStudies( params.id );
     223
     224                if( !studyList )
     225                        return
     226
     227                [studyList: studyList, studyInstanceTotal: Study.count(), multipleStudies: ( studyList.size() > 1 ) ]
     228        }
     229
     230    /**
     231         * Reads one or more studies from the database and checks whether the logged
     232         * in user is allowed to access them.
     233         *
     234         * Is used by several show_-methods
     235         *
     236         * @return List with Study objects or false if an error occurred.
     237         */
     238        private def readStudies( id ) {
     239                // If nothing has been selected, redirect the user
     240                if( !id || !( id instanceof String)) {
     241            response.status = 500;
     242            render 'No study selected';
     243            return false
     244                }
     245
     246                // Check whether one id has been selected or multiple.
     247                def ids = URLDecoder.decode( id ).split( "," );
     248
     249                // Parse strings to a long
     250                def long_ids = []
     251                ids.each { long_ids.add( Long.parseLong( it ) ) }
     252
     253                def c = Study.createCriteria()
     254
     255        def studyList = c {
     256                        maxResults( Math.min(params.max ? params.int('max') : 10, 100) )
     257                        'in'( "id", long_ids )
     258                }
     259
     260                // Check whether the user may see these studies
     261                def studiesAllowed = []
     262        def loggedInUser = AuthenticationService.getLoggedInUser()
     263
     264                studyList.each { studyInstance ->
     265            if( studyInstance.canRead(loggedInUser) ) {
     266                                studiesAllowed << studyInstance
     267            }
     268                }
     269
     270                // If the user is not allowed to see any of the studies, return 404
     271                if( studiesAllowed.size() == 0 ) {
     272            response.status = 404;
     273            render 'Selected studies not found';
     274            return false
     275                }
     276               
     277                return studyList
     278        }
    126279
    127280    def showByToken = {
  • trunk/grails-app/domain/dbnp/authentication/SecUser.groovy

    r1144 r1213  
    2929        }
    3030
    31         public boolean equals(Object y)
    32         {
    33             if( !( y instanceof SecUser ) ) {
    34                 return false;
    35             }
     31        public boolean equals(Object y)
     32        {
     33                if( !( y instanceof SecUser ) ) {
     34                        return false;
     35                }
    3636
    37             if (y == null) return false;
     37                if (y == null) return false;
    3838
    39             return this.id == y.id
    40         }
     39                return this.id == y.id
     40        }
     41
     42        public boolean hasAdminRights() {
     43                return getAuthorities().contains( SecRole.findByAuthority( 'ROLE_ADMIN' ) );
     44        }
     45
    4146}
  • trunk/grails-app/domain/dbnp/studycapturing/Subject.groovy

    r1198 r1213  
    6868                return name
    6969        }
     70
     71        /**
     72         * Returns a human readable string of a list of subjects, with a maximum number
     73         * of characters
     74         *
     75         * @param subjectList   List with Subject objects
     76         * @param maxChars              maximum number of characters returned
     77         * @return                              human readble string with at most maxChars characters, representing the subjects given.
     78         */
     79        public static String trimSubjectNames( ArrayList subjectList, Integer maxChars ) {
     80                def simpleSubjects = subjectList.name.join( ', ' );
     81                def showSubjects
     82               
     83                // If the subjects will fit, show them all
     84                if( !maxChars || simpleSubjects.size() < maxChars ) {
     85                  showSubjects = simpleSubjects;
     86                } else {
     87                  // Always add the first name
     88                  def subjectNames = subjectList[0]?.name;
     89
     90                  // Continue adding names until the length is to long
     91                  def id = 0;
     92                  subjectList.each { subject ->
     93                        if( id > 0 ) {
     94                          if( subjectNames?.size() + subject.name?.size() < maxChars - 15 ) {
     95                                subjectNames += ", " + subject.name;
     96                          } else {
     97                                return;
     98                          }
     99                        }
     100                        id++;
     101                  }
     102
     103                  // Add a postfix
     104                  subjectNames += " and " + ( subjectList?.size() - id ) + " more";
     105
     106                  showSubjects = subjectNames;
     107                }
     108
     109                return showSubjects
     110        }
    70111}
  • trunk/grails-app/domain/dbnp/studycapturing/TemplateField.groovy

    r1175 r1213  
    353353        }
    354354
     355        /**
     356         * Checks whether this field is filled in any of the entities in the given list
     357         *
     358         * @param       List    List of TemplateEntities to search in
     359         * @return      boolean True iff any of the given entities has this field as template field, and has a value for it. False otherwise
     360         */
     361        def isFilledInList( entityList ) {
     362                if( !entityList )
     363                        return false;
     364                       
     365                return true in entityList.collect { it.fieldExists( this.name ) && it.getFieldValue( this.name ) != null }?.flatten()
     366        }
     367
    355368}
  • trunk/grails-app/views/study/show.gsp

    r1206 r1213  
    1 
    21<%@ page import="dbnp.studycapturing.Study" %>
    32<%@ page import="dbnp.studycapturing.EventGroup" %>
     
    109    <title><g:message code="default.show.label" args="[entityName]" /></title>
    1110    <script type="text/javascript">
    12       // Flag whether the timelines have been loaded
    13       var timelineloaded = false;
    14      
    1511      // Number of timelines that should be loaded
    1612      var numTimelines = ${studyList?.size()};
     
    1915      $(function() {
    2016              $("#tabs").tabs({
    21                 show: function(event, ui) {
     17                load: function(event, ui) {
    2218                  // If the events tab is shown, the timeline should be redrawn
    23                   if( ui.tab.hash == '#events-timeline' && !timelineloaded ) {
     19                  if( ui.tab.hash == '#Events_timeline' ) {
    2420                    loadTimeline( 'eventstimeline', 'eventtitles', 0 );
    25                     timelineloaded = true;
    2621                  }
    27                 }
     22                },
     23                                ajaxOptions: {
     24                                        error: function( xhr, status, index, anchor ) {
     25                                                $( anchor.hash ).html(
     26                                                        "Couldn't load this tab. We'll try to fix this as soon as possible." );
     27                                        }
     28                                }
    2829              });
    2930      });
     31
     32      // Parameters for the SIMILE timeline
     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
    3037    </script>
    3138    <link rel="stylesheet" type="text/css" href="${resource(dir: 'css', file: 'studies.css')}"/>
    3239
    3340    <!-- 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>
    3941    <script src="${resource(dir: 'js', file: 'timeline-simile/timeline-api.js')}" type="text/javascript"></script>
    4042    <script src="${resource(dir: 'js', file: 'timeline-simile/custom-timeline.js')}" type="text/javascript"></script>
     
    4345
    4446    <!-- 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>
     47    <script type="text/javascript" src="<g:createLink action="createTimelineBandsJs" id="${studyList.id.join(',')}" />" type="text/javascript"></script>
    19748</head>
    19849<body>
     
    20758        <ul>
    20859          <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>
     60          <li><a href="<g:createLink action="show_subjects" id="${studyList.id.join(',')}" />" title="Subjects"><span>Subjects</span></a></li>
     61          <li><a href="<g:createLink action="show_events_timeline" id="${studyList.id.join(',')}" />" title="Events timeline"><span>Events timeline</span></a></li>
     62          <li><a href="<g:createLink action="show_events_table" id="${studyList.id.join(',')}" />" title="Events table"><span>Events table</span></a></li>
     63          <li><a href="<g:createLink action="show_assays" id="${studyList.id.join(',')}" />" title="Assays"><span>Assays</span></a></li>
     64          <li><a href="<g:createLink action="show_samples" id="${studyList.id.join(',')}" />" title="Samples"><span>Samples</span></a></li>
     65          <li><a href="<g:createLink action="show_persons" id="${studyList.id.join(',')}" />" title="Persons"><span>Persons</span></a></li>
     66          <li><a href="<g:createLink action="show_publications" id="${studyList.id.join(',')}" />" title="Publications"><span>Publications</span></a></li>
    21667        </ul>
    21768
     
    23788            <!-- Show all template and domain fields, if filled -->
    23889            <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}">
     90              <g:if test="${field.isFilledInList( studyList )}">
    24591                <tr>
    24692                  <td>${field}</td>
     
    331177        </div>
    332178
    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                 <g:each in="${studyInstance.subjects}" var="subject" status="j">
    406                   <tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
    407                     <g:if test="${multipleStudies && j==0}">
    408                       <td class="studytitle" rowspan="${sortedSubjects?.size()}">
    409                         ${studyInstance.title}
    410                       </td>
    411                     </g:if>
    412                     <g:each in="${subject.giveDomainFields()}" var="field">
    413                       <td><wizard:showTemplateField field="${field}" entity="${subject}" /></td>
    414                     </g:each>
    415                  
    416                     <g:each in="${showSubjectFields}" var="field">
    417                       <td>
    418                         <g:if test="${subject.fieldExists(field.name)}">
    419                                 <wizard:showTemplateField field="${field}" entity="${subject}" />
    420                         </g:if>
    421                         <g:else>
    422                           N/A
    423                         </g:else>
    424                       </td>
    425                     </g:each>
    426 
    427                   </tr>
    428                   <g:set var="i" value="${i + 1}" />
    429                 </g:each>
    430               </g:each>
    431             </table>
    432           </g:else>
    433         </div>
    434 
    435         <div id="events-timeline">
    436           <g:if test="${studyList*.events?.flatten()?.size()==0 && studyInstance*.samplingEvents?.flatten()?.size()==0 }">
    437             No events in these studies
    438           </g:if>
    439           <g:else>
    440             <g:each in="${studyList}" var="study" status="i">
    441               <div style="margin: 10px; ">
    442                 <div class="eventtitles" id="eventtitles-${i}"></div>
    443                 <div class="eventstimeline" id="eventstimeline-${i}"></div>
    444               </div>
    445             </g:each>
    446             <noscript>
    447               <table>
    448                 <thead>
    449                   <tr>
    450                     <g:if test="${multipleStudies}">
    451                       <th></th>
    452                     </g:if>
    453                     <th>Start time</th>
    454                     <th>Duration</th>
    455                     <th>Type</th>
    456                     <th>Sampling event</th>
    457                     <th>Parameters</th>
    458                   </tr>
    459                 </thead>
    460 
    461                 <g:set var="i" value="${1}" />
    462 
    463                 <g:each in="${studyList}" var="studyInstance">
    464                   <%
    465                     // Sort events by starttime and duration
    466                     events = studyInstance.events + studyInstance.samplingEvents;
    467                     sortedEvents = events.sort( { a, b ->
    468                           //a.startTime == b.startTime ?
    469                             //a.getDuration().getValue() <=> b.getDuration().getValue() :
    470                           a.startTime <=> b.startTime
    471                       } as Comparator )
    472                   %>
    473 
    474                   <g:each in="${sortedEvents}" var="event" status="j">
    475                     <tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
    476                       <g:if test="${multipleStudies && j==0}">
    477                         <td class="studytitle" rowspan="${sortedEvents?.size()}">
    478                           ${studyInstance.title}
    479                         </td>
    480                       </g:if>
    481                       <td>${event.getStartTimeString()}</td>
    482                       <td>${((event.getClass() == 'Event') ? event.getDurationString() : '')}</td>
    483                       <td>${event.template.name}</td>
    484                       <td>
    485                         <g:if test="${event instanceof dbnp.studycapturing.SamplingEvent}">
    486                           <g:checkBox name="samplingEvent" disabled="${true}" value="${true}"/>
    487                         </g:if>
    488                         <g:else>
    489                           <g:checkBox name="event" disabled="${true}" value="${false}" />
    490                         </g:else>
    491                       </td>
    492                       <td>
    493                         <g:set var="fieldCounter" value="${1}" />
    494                         <g:each in="${event.giveTemplateFields()}" var="field">
    495                           <g:if test="${event.getFieldValue(field.name)}">
    496                             <g:if test="${fieldCounter > 1}">, </g:if>
    497                               ${field.name} = <wizard:showTemplateField field="${field}" entity="${event}" />
    498                             <g:set var="fieldCounter" value="${fieldCounter + 1}" />
    499                           </g:if>
    500                         </g:each>
    501                       </td>
    502                     </tr>
    503 
    504                     <g:set var="i" value="${i + 1}" />
    505                   </g:each>
    506                 </g:each>
    507               </table>
    508 
    509             </noscript>
    510 
    511           </g:else>
    512         </div>
    513 
    514         <div id="events-table">
    515           <g:if test="${studyList*.eventGroups?.flatten()?.size()==0}">
    516             No event groups in this study
    517           </g:if>
    518           <g:else>
    519             <%
    520               // Determine a union of the event templates for all different
    521               // eventgroups in all studies, in order to show a proper list.
    522               // We want every field to appear just once,
    523               // so the list is filtered for unique values
    524               def groupTemplates = studyList*.giveAllEventTemplates()?.flatten().unique()
    525                           def showTemplates = groupTemplates;
    526 
    527                           def showProperties = [:];
    528                           def allEvents = studyList*.events.flatten() + studyList*.samplingEvents.flatten();
    529                           def eventColumns = 0;
    530 
    531                           showTemplates.each { template ->
    532                                 // We want to show all properties only once. If the properties are never filled
    533                                 // we shouldn't show them at all.
    534                                 def showFields = []
    535                                 template.fields.each { field ->
    536                                   for( def event: allEvents.findAll { it.template == template } ) {
    537                                         if( event.getFieldValue( field.name ) ) {
    538                                           showFields << field;
    539                                           break;
    540                                         }
    541                                   }
    542                                 }
    543 
    544                                 showProperties[ template.name ] = showFields;
    545 
    546                                 // Compute the total number of columns under 'Events' (the +1 is
    547                                 // because of the 'start time' column)
    548                                 eventColumns += [ 1, showFields.size() + 1 ].max();
    549                           }
    550 
    551             %>
    552             <table>
    553               <thead>
    554                 <tr>
    555                   <g:if test="${multipleStudies}">
    556                     <th></th>
    557                   </g:if>
    558                   <th>Name</th>
    559                   <th colspan="${eventColumns}">Events</th>
    560                   <th>Subjects</th>
    561                 </tr>
    562                 <tr>
    563                   <g:if test="${multipleStudies}">
    564                     <th></th>
    565                   </g:if>
    566                   <th></th>
    567                   <g:each in="${showTemplates}" var="eventTemplate">
    568                     <th colspan="${[1, showProperties[ eventTemplate.name ].size() + 1 ].max()}">${eventTemplate.name}</th>
    569                   </g:each>
    570                   <th></th>
    571                 </tr>
    572                 <tr class="templateFields">
    573                   <g:if test="${multipleStudies}">
    574                     <th></th>
    575                   </g:if>
    576                   <th></th>
    577                   <g:each in="${showTemplates}" var="eventTemplate">
    578                                         <th>start time</th>
    579                                         <g:if test="${showProperties[ eventTemplate.name ].size() > 0}">
    580                                           <g:each in="${showProperties[ eventTemplate.name ]}" var="field">
    581                                                 <th>${field.name}</th>
    582                                           </g:each>
    583                                         </g:if>
    584                   </g:each>
    585                   <th></th>
    586                 </tr>
    587               </thead>
    588 
    589               <g:set var="i" value="${1}" />
    590 
    591               <g:each in="${studyList}" var="studyInstance">
    592                 <%
    593                   // Sort the groups by name
    594                                   def sortedEventGroups = studyInstance.eventGroups.sort( { a, b ->
    595                       return a.name <=> b.name;
    596                   }  as Comparator );
    597 
    598                                   // Determine the number of rows per group (depending on the max
    599                                   // number of events per template in a group)
    600                                   def maxNumberEventsPerTemplate = [:];
    601                                   def rowsPerStudy = 0;
    602                                   sortedEventGroups.each { group ->
    603                                         def max = 1;
    604                                         showTemplates.each { template ->
    605                                           def num = ( group.events + group.samplingEvents ).findAll { it.template == template }.size();
    606                                           if( num > max )
    607                                                 max = num;
    608                                         }
    609                                         maxNumberEventsPerTemplate[group.name] = max;
    610                                         rowsPerStudy += max;
    611                                   }
    612 
    613                   def orphans = studyInstance.getOrphanEvents();
    614                   if( orphans?.size() > 0 ) {
    615                     sortedEventGroups.add( new EventGroup(
    616                       id: -1,
    617                       name: 'No group',
    618                       events: orphans,
    619                       subjects: []
    620                     ));
    621                   }
    622                 %>
    623                 <g:each in="${sortedEventGroups}" var="eventGroup" status="j">
    624                                   <g:set var="n" value="${1}" />
    625                   <g:while test="${n <= maxNumberEventsPerTemplate[ eventGroup.name ]}">
    626 
    627                                         <tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
    628                                           <g:if test="${n == 1}">
    629                                                 <g:if test="${multipleStudies && j==0}">
    630                                                   <td class="studytitle" rowspan="${rowsPerStudy}">
    631                                                         ${studyInstance.title}
    632                                                   </td>
    633                                                 </g:if>
    634                                                 <td rowspan="${maxNumberEventsPerTemplate[ eventGroup.name ]}">${eventGroup.name}</td>
    635                                           </g:if>
    636                                        
    637                                           <g:each in="${showTemplates}" var="currentEventTemplate">
    638                                                 <g:if test="${showProperties[ currentEventTemplate.name ].size() == 0}">
    639                                                   <td>&nbsp;</td>
    640                                                 </g:if>
    641                                                 <g:else>
    642                                                   <%
    643                                                         def templateEvents = (eventGroup.events + eventGroup.samplingEvents).findAll { it.template == currentEventTemplate }.sort { a, b -> a.startTime <=> b.startTime }.asType(List)
    644                                                         def event = templateEvents.size() >= n ? templateEvents[ n - 1 ] : null;
    645                                                   %>
    646                                                   <td class="templateFieldValue"><g:if test="${event}">${new RelTime( event.startTime ).toString()}</g:if></td>
    647                                                   <g:each in="${showProperties[ currentEventTemplate.name ]}" var="field">
    648                                                         <td class="templateFieldValue"><wizard:showTemplateField field="${field}" entity="${event}" /></td>
    649                                                   </g:each>
    650                                                 </g:else>
    651                                           </g:each>
    652                                        
    653                                           <g:if test="${n == 1}">
    654                                                 <% sortedGroupSubjects = eventGroup.subjects.sort( { a, b -> a.name <=> b.name } as Comparator )  %>
    655 
    656                                                 <td rowspan="${maxNumberEventsPerTemplate[ eventGroup.name ]}" title="${sortedGroupSubjects.name.join( ', ' )}">
    657                                                         <g:if test="${eventGroup.subjects.size()==0}">
    658                                                                 -
    659                                                         </g:if>
    660                                                         <g:else>
    661                                                                 <g:each in="${eventGroup.subjects.species.unique()}" var="currentSpecies" status="k">
    662                                                                         <g:if test="${k > 0}">,</g:if>
    663                                                                         <%=eventGroup.subjects.findAll { return it.species == currentSpecies; }.size() %>
    664                                                                         ${currentSpecies}
    665                                                                 </g:each>
    666                                                         </g:else>
    667                                                 </td>
    668                                           </g:if>
    669                                         </tr>
    670 
    671 
    672                                         <g:set var="n" value="${n+1}" />
    673                                   </g:while>
    674 
    675                   <g:set var="i" value="${i + 1}" />
    676                 </g:each>
    677 
    678               </g:each>
    679 
    680             </table>
    681           </g:else>
    682         </div>
    683 
    684         <div id="assays">
    685           <g:if test="${studyList*.assays?.flatten()?.size()==0}">
    686             No assays in these studies
    687           </g:if>
    688           <g:else>
    689             <table>
    690               <thead>
    691                 <tr>
    692                   <g:if test="${multipleStudies}">
    693                     <th></th>
    694                   </g:if>
    695                         <th width="100">Assay Code</th>
    696                   <th width="100">Assay Name</th>
    697                   <th width="100">Module</th>
    698                   <th width="150">Platform</th>
    699                   <th>Link</th>
    700                   <th>Samples</th>
    701                 </tr>
    702               </thead>
    703               <g:set var="i" value="${1}" />
    704 
    705               <g:each in="${studyList}" var="studyInstance">
    706                 <g:each in="${studyInstance.assays}" var="assay" status="j">
    707                   <tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
    708                     <g:if test="${multipleStudies && j==0}">
    709                       <td class="studytitle" rowspan="${studyInstance.assays?.size()}">
    710                         ${studyInstance.title}
    711                       </td>
    712                     </g:if>
    713                           <td>${assay.token}</td>
    714                     <td>${assay.name}</td>
    715                     <td>${assay.module.name}</td>
    716                     <td>${assay.module.platform}</td>
    717                     %{--<td><a href="${assay.module.url}/assay/${assay.externalAssayID}">view</a></td>--}%
    718                     <td><jumpbar:link
    719                       linkDest="${createLink(action:'show', id:studyInstance.id)}"
    720                       linkText='Go back to GSCF'
    721                       frameSource="${assay.module.url}/assay/showByToken/${assay.externalAssayID}"
    722                       pageTitle="Assay View in Module">
    723                       view
    724                     </jumpbar:link></td>
    725                     <td>
    726                       <% sortedAssaySamples = assay.samples.sort( { a, b -> a.name <=> b.name } as Comparator )  %>
    727                       ${sortedAssaySamples.name.join( ', ' )}
    728                     </td>
    729                   </tr>
    730                   <g:set var="i" value="${i + 1}" />
    731 
    732                 </g:each>
    733               </g:each>
    734             </table>
    735           </g:else>
    736         </div>
    737 
    738         <div id="samples">
    739 
    740           <g:if test="${studyList*.samples.flatten()?.size()==0}">
    741             No samples in the selected studies
    742           </g:if>
    743           <g:else>
    744             <table>
    745               <thead>
    746                 <tr>
    747                   <g:if test="${multipleStudies}">
    748                     <th></th>
    749                   </g:if>
    750 
    751                         <th>Parent Subject</th>
    752                         <th>Parent Sampling Event</th>
    753 
    754 
    755                   <g:each in="${new dbnp.studycapturing.Sample().giveDomainFields()}" var="field">
    756                     <th>${field}</th>
    757                   </g:each>
    758 
    759                   <%
    760                     // Determine a union of the fields for all different
    761                     // samples in all studies. In order to show a proper list.
    762                     // We want every field to appear just once,
    763                     // so the list is filtered for unique values
    764                     sampleTemplates = studyList*.giveSampleTemplates().flatten().unique()
    765 
    766                     if( !sampleTemplates ) {
    767                       sampleTemplates = [];
    768                       sampleFields = [];
    769                       showSampleFields = [];
    770                     } else {
    771                       sampleFields = sampleTemplates*.fields.flatten().unique()
    772                       if( !sampleFields ) {
    773                         sampleFields = [];
    774                         showSampleFields = [];
    775                       } else {
    776                         // Filter out all fields that are left blank for all samples
    777                         allSamples = studyList*.samples.flatten()
    778 
    779                         showSampleFields = [];
    780                         sampleFields.each { sampleField ->
    781                           for( sample in allSamples )
    782                           {
    783                             // If the field is filled for this subject, we have to
    784                             // show the field and should not check any other
    785                             // samples (hence the break)
    786                             if( sample.fieldExists( sampleField.name ) && sample.getFieldValue( sampleField.name ) ) {
    787                               showSampleFields << sampleField;
    788                               break;
    789                             }
    790                           }
    791                         }
    792                       }
    793                     }
    794                   %>
    795 
    796                   <g:each in="${showSampleFields}" var="field">
    797                     <th>${field}</th>
    798                   </g:each>
    799 
    800                 </tr>
    801               </thead>
    802 
    803               <g:set var="i" value="${1}" />
    804 
    805               <g:each in="${studyList}" var="studyInstance">
    806                 <%
    807                   // Sort samples by name
    808                   samples = studyInstance.samples;
    809                   sortedSamples = samples.sort( { a, b -> a.name <=> b.name } as Comparator )
    810                 %>
    811 
    812                 <g:each in="${sortedSamples}" var="sample" status="j">
    813                   <tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
    814                     <g:if test="${multipleStudies && j==0}">
    815                       <td class="studytitle" rowspan="${sortedSamples?.size()}">
    816                         ${studyInstance.title}
    817                       </td>
    818                     </g:if>
    819                           <td>${sample.parentSubject?.name}</td>
    820                           <td>${sample.parentEvent?.template?.name} at ${sample.parentEvent?.getStartTimeString()}</td>
    821                     <g:each in="${sample.giveDomainFields()}" var="field">
    822                       <td><wizard:showTemplateField field="${field}" entity="${sample}" /></td>
    823                     </g:each>
    824 
    825                     <g:each in="${showSampleFields}" var="field">
    826                       <td>
    827                         <g:if test="${sample.fieldExists(field.name)}">
    828                           <wizard:showTemplateField field="${field}" entity="${sample}" />
    829                         </g:if>
    830                         <g:else>
    831                           N/A
    832                         </g:else>
    833                       </td>
    834                     </g:each>
    835 
    836                   </tr>
    837                   <g:set var="i" value="${i + 1}" />
    838                 </g:each>
    839               </g:each>
    840 
    841             </table>
    842           </g:else>
    843         </div>
    844 
    845         <div id="persons">
    846           <%
    847             // Determine a list of all persons
    848             allPersons = studyList*.persons*.person.flatten().unique()
    849           %>
    850           <g:if test="${allPersons?.size()==0}">
    851             No persons involved in these studies
    852           </g:if>
    853           <g:else>
    854             <table>
    855               <tr>
    856                 <thead>
    857                   <th>Name</th>
    858                   <th>Affiliations</th>
    859                   <th>Phone</th>
    860                   <th>Email</th>
    861                   <g:if test="${multipleStudies}">
    862                     <g:each in="${studyList}" var="studyInstance">
    863                       <th>${studyInstance.title}</th>
    864                     </g:each>
    865                   </g:if>
    866                   <g:else>
    867                     <th>Role</th>
    868                   </g:else>
    869                 </thead>
    870               </tr>
    871               <g:each in="${allPersons}" var="person" status="i">
    872                 <tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
    873                   <td>${person.firstName} ${person.prefix} ${person.lastName}</td>
    874                   <td>
    875                     ${person.affiliations.join(', ')}
    876                   </td>
    877                   <td>${person.phone}</td>
    878                   <td>${person.email}</td>
    879                   <g:each in="${studyList}" var="studyInstance">
    880                     <%
    881                       studyperson = studyInstance.persons.find { it.person == person }
    882                     %>
    883                     <td>
    884                       <g:if test="${studyperson}">
    885                         ${studyperson.role.name}
    886                       </g:if>
    887                      </td>
    888                   </g:each>
    889 
    890                 </tr>
    891               </g:each>
    892             </table>
    893           </g:else>
    894         </div>
    895 
    896         <div id="publications">
    897           <%
    898             // Determine a list of all persons
    899             allPublications = studyList*.publications.flatten().unique()
    900           %>
    901           <g:if test="${allPublications?.size()==0}">
    902             No publications attached to these studies
    903           </g:if>
    904           <g:else>
    905             <table>
    906               <tr>
    907                 <thead>
    908                   <th>Title</th>
    909                   <th>Authors</th>
    910                   <th>Comments</th>
    911 
    912                   <g:if test="${multipleStudies}">
    913                     <g:each in="${studyList}" var="studyInstance">
    914                       <th>${studyInstance.title}</th>
    915                     </g:each>
    916                   </g:if>
    917                 </thead>
    918               </tr>
    919               <g:each in="${allPublications}" var="publication" status="i">
    920                 <tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
    921                   <td>${publication.title}</td>
    922                   <td>
    923                     ${publication.authorsList}
    924                   </td>
    925                   <td>${publication.comments}</td>
    926                   <g:if test="${multipleStudies}">
    927                     <g:each in="${studyList}" var="studyInstance">
    928                       <td>
    929                         <g:if test="${publication in studyInstance.publications}">
    930                           x
    931                         </g:if>
    932                       </td>
    933                     </g:each>
    934                   </g:if>
    935                 </tr>
    936               </g:each>
    937             </table>
    938           </g:else>
    939         </div>
     179                <% /*
     180                  All other tabs are moved to separate views and are loaded using
     181                  ajax calls when a tab is opened. See http://jqueryui.com/demos/tabs/#ajax
     182                */ %>
    940183
    941184      </div>
  • trunk/web-app/js/timeline-simile/relative-time.js

    r1203 r1213  
    112112    this._backgroundLayer = band.createLayerDiv(0);
    113113    this._backgroundLayer.setAttribute("name", "ether-background"); // for debugging
    114     this._backgroundLayer.style.background = this._theme.ether.backgroundColors[band.getIndex()];
     114    //this._backgroundLayer.style.background = this._theme.ether.backgroundColors[band.getIndex()];
    115115
    116116    this._markerLayer = null;
Note: See TracChangeset for help on using the changeset viewer.