source: extensions/net.sf.basedb.reggie/trunk/resources/libprep/pool_protocol2.jsp @ 1975

Last change on this file since 1975 was 1975, checked in by Nicklas Nordborg, 9 years ago

References #485 and #479. Only use 1 decimal in lab protocols for pooling. Use the rounded values when calculating molarity and other values for the pool.

File size: 17.1 KB
Line 
1<%@ page
2  pageEncoding="UTF-8"
3  session="false"
4  import="net.sf.basedb.core.User"
5  import="net.sf.basedb.core.DbControl"
6  import="net.sf.basedb.core.SessionControl"
7  import="net.sf.basedb.core.Application"
8  import="net.sf.basedb.core.Extract"
9  import="net.sf.basedb.core.BioMaterial"
10  import="net.sf.basedb.core.MeasuredBioMaterial"
11  import="net.sf.basedb.core.BioMaterialEventSource"
12  import="net.sf.basedb.core.BioPlate"
13  import="net.sf.basedb.core.BioWell"
14  import="net.sf.basedb.core.PermissionDeniedException"
15  import="net.sf.basedb.core.ItemQuery"
16  import="net.sf.basedb.core.query.Restrictions"
17  import="net.sf.basedb.core.query.Hql"
18  import="net.sf.basedb.core.query.Orders"
19  import="net.sf.basedb.util.Values"
20  import="net.sf.basedb.util.formatter.WellCoordinateFormatter"
21  import="net.sf.basedb.util.extensions.Extension"
22  import="net.sf.basedb.clients.web.Base" 
23  import="net.sf.basedb.clients.web.util.HTML"
24  import="net.sf.basedb.clients.web.extensions.ExtensionsControl"
25  import="java.util.List"
26  import="java.util.ArrayList"
27%>
28<%
29final SessionControl sc = Base.getExistingSessionControl(request, true);
30final String ID = sc.getId();
31final String home = ExtensionsControl.getHomeUrl("net.sf.basedb.reggie");
32final String root = request.getContextPath();
33DbControl dc = null;
34try
35{
36  dc = sc.newDbControl();
37  final Extension reggie = ExtensionsControl.get(dc).getExtension("net.sf.basedb.reggie");
38  final User user = User.getById(dc, sc.getLoggedInUserId());
39 
40  Integer[] pools = Values.getInt(request.getParameterValues("pools"));
41 
42  int libPlateId = Values.getInt(request.getParameter("bioplate"));
43  BioPlate libPlate = libPlateId == 0 ? null : BioPlate.getById(dc, libPlateId);
44  String view = Values.getString(request.getParameter("view"), "list");
45%>
46<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
47<html>
48<head>
49  <%
50  if (libPlate != null)
51  {
52    %>
53    <title>Lab protocol for pooling <%=HTML.encodeTags(libPlate.getName())%> - <%=view.equals("list") ? "list" : "table"%></title>
54    <%
55  }
56  else
57  {
58    %>
59    <title>Lab protocol for library pooling - <%=view.equals("list") ? "list" : "table"%></title>
60    <%
61  }
62  %>
63  <link rel="SHORTCUT ICON" href="<%=home%>/images/flowcell.png">
64  <link rel="stylesheet" type="text/css" href="<%=home %>/css/printable.css">
65  <link rel="stylesheet" type="text/css" href="<%=home %>/css/plate.css">
66  <link rel="stylesheet" type="text/css" href="<%=home %>/css/reggie.css">
67  <script language="JavaScript" src="<%=root%>/include/scripts/main.js" type="text/javascript" charset="UTF-8"></script>
68  <script language="JavaScript" src="<%=root%>/include/scripts/ajax.js" type="text/javascript" charset="UTF-8"></script>
69  <script language="JavaScript" src="<%=home %>/reggie.js" type="text/javascript" charset="UTF-8"></script>
70  <script language="JavaScript" src="pools.js" type="text/javascript" charset="UTF-8"></script>
71  <script language="JavaScript" src="plate.js" type="text/javascript" charset="UTF-8"></script>
72 
73  <script language="JavaScript">
74  var debug = false;
75  var currentStep = 1;
76 
77  // Loaded from servlet when getting Library information
78  var TARGET_MOLARITY_IN_POOL;
79  var TARGET_VOLUME_IN_POOL_PER_LIB; 
80  var POOL_SCHEMA;
81  var POOL_BARCODE_VARIANT;
82 
83  function init()
84  {
85    // Load information about Library bioplate
86    var libPlate;
87    <%
88    if (libPlateId != 0)
89    {
90      %>
91      // Load Libraries and related info from the selected pools
92      var request = Ajax.getXmlHttpRequest();
93      try
94      {
95        showLoadingAnimation('Loading library bioplate information...');
96        var url = '../Pool.servlet?ID=<%=ID%>&cmd=GetLibPlateInfo&bioplate=<%=libPlateId%>';   
97        request.open("GET", url, false);
98        request.send(null);
99      }
100      finally
101      {
102        hideLoadingAnimation();
103      }
104     
105      if (debug) Main.debug(request.responseText);
106      var response = JSON.parse(request.responseText);
107      if (response.status != 'ok')
108      {
109        setFatalError(response.message);
110        return false;
111      }
112     
113      libPlate = response.libPlate;
114      POOL_SCHEMA = PoolSchema.getById(libPlate.poolSchema);
115      POOL_BARCODE_VARIANT = PoolSchema.getBarcodeVariantByName(POOL_SCHEMA, libPlate.barcodeVariant);
116      <%
117    }
118    %>
119   
120    var pools = [<%=Values.getString(java.util.Arrays.asList(pools), ",", true)%>];
121
122    // Load Libraries and related info from the selected pools
123    var request = Ajax.getXmlHttpRequest();
124    try
125    {
126      showLoadingAnimation('Loading pooled library information...');
127      var url = '../Pool.servlet?ID=<%=ID%>&cmd=GetLibraryInfoForPools&pools='+pools.join(',');   
128      request.open("GET", url, false);
129      request.send(null);
130    }
131    finally
132    {
133      hideLoadingAnimation();
134    }
135   
136    if (debug) Main.debug(request.responseText);
137    var response = JSON.parse(request.responseText);
138    if (response.status != 'ok')
139    {
140      setFatalError(response.message);
141      return false;
142    }
143   
144    var pools = response.pools;
145    var poolInfo = response.poolInfo;
146    TARGET_MOLARITY_IN_POOL = poolInfo.targetMolarity;
147    TARGET_VOLUME_IN_POOL_PER_LIB = poolInfo.targetVolumePerLib;
148
149    var pageTitle = 'Lab protocol for pooling ';
150    // Pre-process the Library items
151    for (var i = 0; i < pools.length; i++)
152    {
153      var pool = pools[i];
154      if (i > 0) pageTitle += ','
155      pageTitle += ' ' + pool.name;
156      for (var j = 0; j < pool.libraries.length; j++)
157      {
158        checkAndPreProcessLibrary(pool.libraries[j], POOL_SCHEMA, POOL_BARCODE_VARIANT);       
159      }
160    }
161   
162    if (!libPlate)
163    {
164      document.title = pageTitle + ' - <%=view%>';
165    }
166   
167    <%
168    if (view.equals("list"))
169    {
170      %>
171      viewAsList(pools, POOL_SCHEMA, POOL_BARCODE_VARIANT);
172      <%
173    }
174    else
175    {
176      %>
177      viewAsPlate(pools, POOL_SCHEMA, POOL_BARCODE_VARIANT)
178      <%
179    }
180    %>
181  }
182 
183  function checkAndPreProcessLibrary(lib, schema, barcodeVariant)
184  {
185    var well = lib.bioWell;
186    var remarks = [];
187
188    // Check if default barcode has been modified
189    if (barcodeVariant)
190    {
191      var indexSet = barcodeVariant.indexSets[well.column];
192      if (indexSet)
193      {
194        var defaultBarcode = indexSet.barcodes[well.row];
195        if (defaultBarcode && lib.barcode.name != defaultBarcode)
196        {
197          remarks[remarks.length] = 'Modified barcode';
198          lib.barcode.modified = true;
199        }
200      }
201    }
202   
203    if (lib.molarity)
204    {
205      if (lib.speedVacConc != null)
206      {
207        remarks[remarks.length] = 'SpeedVac';
208      }
209      if (lib.volume > TARGET_VOLUME_IN_POOL_PER_LIB + 0.001)
210      {
211        remarks[remarks.length] = 'Use 5 µl';
212      }
213 
214      if (lib.mixFactor > 1.001)
215      {
216        // Larger mix than default
217        var mixedVolume = (lib.volume+lib.eb)*(lib.mixFactor);
218        remarks[remarks.length] = 'Mix ' + Numbers.formatNumber(mixedVolume, 0) + 'µl';
219      }
220
221      lib.remarks = remarks;
222    }
223  }
224 
225  /**
226    Get the plate coordinate string for a well, optionally including the plate
227    name or not.
228  */
229  function getPlateCoordinate(well, includePlateName)
230  {
231    var c = '';
232    if (well)
233    {
234      if (includePlateName) c += well.bioPlate.name;
235      c += ' ' + WELL_ALPHA[well.row] + (well.column+1);
236    }
237    return c;
238  }
239 
240 
241  function viewAsList(pools, schema, barcodeVariant)
242  {
243    var lastPoolNum = -1;
244    for (var i = 0; i < pools.length; i++)
245    {
246      var pool = pools[i];
247     
248      var html = '';
249      var tbody = document.getElementById('listview.'+pool.id+'.body');
250     
251      for (var j = 0; j < pool.libraries.length; j++)
252      {
253        var lib = pool.libraries[j];
254        var well = lib.bioWell;
255       
256        var tr = document.createElement('tr');
257        tr.className = well.column % 2 == 0 ? "evencol" : "oddcol";
258   
259        if (barcodeVariant)
260        {
261          var indexSet = barcodeVariant.indexSets[well.column];
262          if (indexSet)
263          {
264            tr.className = lib && lib.barcode.modified ? 'bg-modified' : indexSet.color;
265          }
266        }
267
268        addColumn(tr, 'lib', lib.name);
269        addColumn(tr, 'remain', Numbers.formatNumber((lib.remainingQuantity+lib.usedQuantity)*1000, 2));
270        addColumn(tr, 'molarity', Numbers.formatNumber(lib.molarity, 2));
271        <%
272        if (libPlate==null)
273        {
274          %>
275          addColumn(tr, 'workplate', well.bioPlate.name + ' ' + well.location);
276          <%
277        }
278        else
279        {
280          %>
281          addColumn(tr, 'workplate', well.location);
282          <%
283        }
284        %>
285        var mixFactor = lib.mixFactor || 1.0;
286        addColumn(tr, 'volume', Numbers.formatNumber(lib.volume*mixFactor, 1));
287        addColumn(tr, 'eb', Numbers.formatNumber(lib.eb*mixFactor, 1));
288        addColumn(tr, "remarks", lib.remarks.join('; '));
289        tbody.appendChild(tr);
290      }
291     
292      setInnerHTML('molarity.'+pool.id, Numbers.formatNumber(pool.molarity, 2) + ' nM; ' + Numbers.formatNumber(1000*pool.originalQuantity / pool.conc, 0)+' µl');
293      Main.show('pool.'+pool.id);
294    }
295  }
296 
297  function addColumn(tr, className, html)
298  {
299    var td = document.createElement('td');
300    td.className = className;
301    td.innerHTML = html;
302    tr.appendChild(td);
303  }
304 
305  function viewAsPlate(pools, schema, barcodeVariant)
306  {
307    Plate.init(8, 12, schema, WellPainter);
308   
309    for (var poolNo = 0; poolNo < pools.length; poolNo++)
310    {
311      var pool = pools[poolNo];
312      POOL_NAMES[poolNo] = pool.name;
313      for (var libNo = 0; libNo < pool.libraries.length; libNo++)
314      {
315        var lib = pool.libraries[libNo];
316        var well = lib.bioWell;
317        Plate.getWell(well.row, well.column).setExtract(lib);
318      }
319    }
320
321    WellPainter.barcodeVariant = barcodeVariant;
322    Plate.paint(Plate.getWells());
323    PoolSchema.buildPoolTableRow(schema, 12);
324    Main.show('plateview');
325   
326   
327    for (var poolNo = 0; poolNo < pools.length; poolNo++)
328    {
329      var pool = pools[poolNo];
330      //setInnerHTML('molarity.'+pool.id, Numbers.formatNumber(pool.molarity, 2) + ' nM; ' + Numbers.formatNumber(1000*pool.originalQuantity / pool.conc, 0)+' µl');
331
332      var poolData = '<div class="pool-data">';
333      poolData += Numbers.formatNumber(pool.molarity, 2)+'nM; ';
334      poolData += Numbers.formatNumber(1000*pool.originalQuantity / pool.conc, 0) + 'µl';
335      poolData += '</div>';
336      document.getElementById('pool.'+poolNo).innerHTML = POOL_NAMES[poolNo] + poolData;
337
338    }
339  }
340
341  var WellPainter = function()
342  {
343    var painter = {};
344   
345    painter.getClassNameForWell = function(well, schema)
346    {
347      var cls = '';
348      var indexSet = painter.barcodeVariant.indexSets[well.column];
349      if (indexSet)
350      {
351        var lib = well.extract;
352        cls += lib && lib.barcode.modified ? 'bg-modified' : indexSet.color;
353      }
354      return cls;
355    }
356   
357    painter.getWellText = function(well, schema)
358    {
359      var text = '';
360      var lib = well.extract;
361      if (lib)
362      {
363        var name = lib.name;
364        var mixFactor = lib.mixFactor || 1.0;
365        var i = name.indexOf('.m');
366        text += '<div class="lib">'+name.substring(0, i)+'.<br>&nbsp;'+name.substring(i)+'</div>';
367        text += '<div><span class="volume">'+Numbers.formatNumber(lib.volume*mixFactor, 1)+'µl</span>';
368        text += '<span class="eb">'+Numbers.formatNumber(lib.eb*mixFactor, 1)+'µl</span></div>';
369        text += '<div class="remarks">'+ lib.remarks.join('; ') + '</div>';
370      }
371      return text;
372    }
373
374    return painter;
375  }();
376  </script>
377  <style>
378  table.protocolheader
379  {
380    width: 100%;
381  }
382
383  table.protocolheader > tbody > tr
384  {
385    height: 1.25em;
386  }
387
388  table.protocolheader > tbody > tr > th
389  {
390    text-align: left;
391    font-size: 1em;
392  }
393
394  .pool-section
395  {
396    page-break-inside: avoid;
397  }
398
399  table.poolheader
400  {
401    margin-top: 1em;
402    width: 100%;
403    border: 1px solid #000000;
404    border-bottom: 0px;
405    border-collapse: collapse;
406  }
407
408  table.poolheader > tbody > tr
409  {
410    height: 1.25em;
411  }
412
413  table.poolheader > tbody > tr > th
414  {
415    text-align: left;
416    font-size: 1em;
417    padding: 1px;
418  }
419 
420  .listview
421  {
422    width: 100%;
423    font-size: 85%;
424    border-collapse: collapse;
425    border: 1px solid #000000;
426  }
427 
428  .listview tr.oddcol
429  {
430    background-color: #F0F0F0;
431  }
432 
433  .listview thead
434  {
435    border: 1px solid #000000;
436    background-color: #F0F0F0;
437  }
438 
439  .listview th
440  {
441    border-left: 1px solid #000000;
442  }
443 
444  .listview td
445  {
446    border-left: 1px solid #000000;
447    border-top: 1px dotted #666666;
448    vertical-align: middle;
449  }
450 
451  .listview .col-num
452  {
453    width: 1.75em;
454    text-align: center;
455    font-size: 125%;
456    font-weight: bold;
457    vertical-align: top;
458  }
459 
460  .listview .lib
461  {
462    width: 15em;
463    text-align: center;
464  }
465 
466  .listview .empty .lib
467  {
468    font-style: italic;
469    color: #666666;
470    text-align: center;
471  }
472 
473  .listview .workplate
474  {
475 
476    width: <%=libPlate==null ? "14em" : "7em"%>;
477    text-align: center;
478  }
479 
480  .listview .pool
481  {
482    width: 7em;
483    text-align: center;
484  }
485 
486  .listview .remain, .listview .molarity
487  {
488    width: 4.5em;
489    padding-right: 0.5em;
490    text-align: right;
491  }
492
493  .listview .volume
494  {
495    width: 3.5em;
496    padding-right: 0.5em;
497    text-align: right;
498    color: #C80000;
499  }
500 
501  .listview .eb
502  {
503    width: 3.5em;
504    padding-right: 0.5em;
505    text-align: right;
506    color: #0000C8;
507  }
508 
509  .listview .remarks
510  {
511    vertical-align: top;
512    padding-left: 0.25em;
513  }
514 
515  /* Divide the 12 wells across the full page */
516  #plateview .well
517  {
518    width: 8.2%;
519    max-width: 8.2%;
520    min-width: 8.2%;
521    padding: 4px;
522  }
523 
524  #plateview .well:hover
525  {
526    padding: 3px;
527  }
528 
529  #plateview .rowheader
530  {
531    width: 2em;
532  }
533 
534  #plateview .lib
535  {
536    font-weight: bold;
537    margin-bottom: 0.25em;
538  }
539  #plateview .volume
540  {
541    color: #C80000;
542  }
543  #plateview .eb
544  {
545    color: #0000C8;
546    float: right;
547  }
548 
549  #plateview .remarks
550  {
551    color: #C80000;
552    font-style: italic;
553  }
554  #plateview .pool-data
555  {
556    font-weight: normal;
557  }
558  </style>
559</head>
560<body onload="init()">
561  <div class="paper <%=view.equals("list") ? "" : "landscape"%>">
562  <div class="noprint fullwidth" style="border-bottom: 1px dashed #A0A0A0; padding-left: 1em; padding-bottom: 1em;">
563    <span class="button" onclick="window.print()" style="float: left; margin-right: 1em;">
564      <img src="../images/print.png">Print&hellip;
565    </span>
566    <b>Note!</b> 
567    <%
568    if (view.equals("list"))
569    {
570      %>
571      For better printing reduce margins to about <i>5mm</i> and set page orientation
572      to <i>portrait</i>. To fit everything on a single page, scale down to <i>60-70%</i>.
573      <%
574    }
575    else
576    {
577      %>
578      For better printing reduce margins to about <i>5mm</i> and set page orientation
579      to <i>landscape</i>. The recommended scale is <i>100%</i>.
580      <%
581    }
582    %>
583    <br clear="all">
584  </div>
585 
586  <h1>Lab protocol for library pooling <span class="reggie">Reggie <%=reggie.getAbout().getVersion() %></span></h1>
587
588  <table style="width: 100%; border: 0px;" class="protocolheader">
589  <%
590  if (libPlate != null)
591  {
592    %>
593    <tr valign="top">
594      <th style="width: 40%;">Library plate: <%=HTML.encodeTags(libPlate.getName()) %></th>
595      <td></td>
596    </tr>
597    <%
598  }
599  %>
600  <tr valign="top">
601    <th style="width: 40%; padding-bottom: 1.5em;">Date+operator:</th>
602    <td></td>
603  </tr>
604  </table>
605
606  <%
607  if (view.equals("list"))
608  {
609    for (Integer poolId :pools)
610    {
611      Extract pool = Extract.getById(dc, poolId);
612      %>
613      <div id="pool.<%=poolId%>" style="display: none;" class="pool-section">
614      <table style="width: 100%;" class="poolheader">
615      <tr valign="top">
616        <th style="width: 40%;"><%=HTML.encodeTags(pool.getName())%></th>
617        <th style="width: 60%">Comments:</th>
618      </tr>
619      <tr valign="top">
620        <td style="width: 40%;"><span id="molarity.<%=poolId%>"></span></td>
621        <td><%=HTML.niceFormat(pool.getDescription()) %></td>
622      </tr>
623      </table>
624      <table style="width: 100%;" class="listview" id="listview.<%=poolId%>">
625      <thead>
626        <tr class="toprow">
627          <th class="lib"></th>
628          <th>Remain</th>
629          <th>DNA</th>
630          <th class="workplate">Work</th>
631          <th colspan="2">2nM, 5/10µl</th>
632          <th></th>
633        </tr>
634        <tr>
635          <th class="lib">Library</th>
636          <th>(ng)</th>
637          <th>(nM)</th>
638          <th class="workplate">plate</th>
639          <th>(µl)</th>
640          <th>EB</th>
641          <th>Remarks</th>
642        </tr>
643      </thead>
644      <tbody id="listview.<%=poolId%>.body">
645      </tbody>
646      </table>
647      </div>
648      <%
649    }
650  }
651  %>
652
653  <div class="loading" id="loading" style="display: none;"><table><tr><td><img src="../images/loading.gif"></td><td id="loading.msg">Please wait...</td></tr></table></div>
654  <div class="messagecontainer error" id="errorMessage" style="display: none;"></div>
655  <%
656
657  if (view.equals("plate"))
658  {
659    %>
660    <table class="plate" style="margin: 0em 0 0 0; width: 100%; display: none;" id="plateview">
661    <%
662    WellCoordinateFormatter rowF = new WellCoordinateFormatter(true);
663    WellCoordinateFormatter colF = new WellCoordinateFormatter(false);
664    %>
665    <tr class="header">
666      <th></th>
667      <%
668      for (int c = 0; c < libPlate.getColumns(); ++c)
669      {
670        %>
671        <th id="col.<%=c%>"><%=colF.format(c)%></th>
672        <%
673      }
674      %>
675    </tr>
676    <tbody>
677    <%
678    for (int r = 0; r < libPlate.getRows(); ++r)
679    {
680      String row = rowF.format(r);
681      %>
682      <tr class="row-<%=r%>">
683        <th id="row.<%=r%>" class="rowheader"><%=row%></th>
684        <%
685        for (int c = 0; c < libPlate.getColumns(); ++c)
686        {
687          %>
688          <td class="well col-<%=c%>" id="well.<%=r%>.<%=c%>"></td>
689          <%
690        }
691        %>
692      </tr>
693      <%
694    }
695    %>
696    </tbody>
697    <tr id="pool-row">
698      <th colspan="13">&nbsp;</th>
699    </tr>
700    </table>
701    <%
702  }
703  %>
704  </div>
705</body>
706</html>
707<%
708}
709finally
710{
711  if (dc != null) dc.close();
712}
713%>
Note: See TracBrowser for help on using the repository browser.