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

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

References #479 and #485. Re-worked the process of selecing libraries for pooling. The first step will now create the PooledLibrary item and link to the used libraries with quantities. All calculations are base on pooling 5µl/2nM of each library. If a larger mix is required for a library dis is registed as a special item with .dil as a suffix. All items are registered without a creation date to indicate that it has yet to be done in the lab.

The lab protocol will use as much information as possible from the database.

Lots of error handling is still needed, and special cases are probably not well supported yet.

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