source: extensions/net.sf.basedb.reggie/trunk/resources/libprep/create_pools.jsp @ 2151

Last change on this file since 2151 was 2151, checked in by Nicklas Nordborg, 8 years ago

Fixes #538: Count and display number of libraries with low and high concentration in create pooled library wizards

Added three counters to the two pooling wizards:

  • Separate mix: the number of libraries that need to be mixed separately before pooling
  • Low quantity: the number of libraries with less remaining quantity that required to reach the target molarity/volume for the pool
  • Excluded: the number of libraries that has been excluded from the pool
File size: 27.5 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.util.formatter.WellCoordinateFormatter"
9  import="net.sf.basedb.clients.web.Base" 
10  import="net.sf.basedb.clients.web.extensions.ExtensionsControl"
11%>
12<%@ taglib prefix="base" uri="/WEB-INF/base.tld" %>
13<%@ taglib prefix="p" uri="/WEB-INF/path.tld" %>
14<%@ taglib prefix="tbl" uri="/WEB-INF/table.tld" %>
15<%
16final SessionControl sc = Base.getExistingSessionControl(request, true);
17final String ID = sc.getId();
18final float scale = Base.getScale(sc);
19final String home = ExtensionsControl.getHomeUrl("net.sf.basedb.reggie");
20DbControl dc = null;
21try
22{
23  dc = sc.newDbControl();
24  final User user = User.getById(dc, sc.getLoggedInUserId());
25%>
26<base:page type="default" >
27<base:head scripts="ajax.js" styles="path.css,toolbar.css">
28  <link rel="stylesheet" type="text/css" href="../css/reggie.css">
29  <link rel="stylesheet" type="text/css" href="../css/plate.css">
30  <script language="JavaScript" src="../reggie.js" type="text/javascript" charset="UTF-8"></script>
31  <script language="JavaScript" src="pools.js" type="text/javascript" charset="UTF-8"></script>
32  <script language="JavaScript" src="plate.js" type="text/javascript" charset="UTF-8"></script>
33
34<script language="JavaScript">
35var debug = 0;
36var currentStep = 1;
37
38var targetVolumePerLibIsValid = false;
39var POOL_DATA = [];
40
41// Loaded from servlet when getting Library information
42var TARGET_MOLARITY_IN_POOL;
43var LIMIT_FOR_AUTO_EXCLUDE = 0.25;
44var LIMIT_FOR_EXTRA_LARGE_MIX;
45var EXTRA_LARGE_MIX_FACTOR;
46
47function init()
48{
49  var frm = document.forms['reggie'];
50  var bioplates = getLibraryBioPlates();
51 
52  var plates = frm.bioplate;
53  if (bioplates != null && bioplates.length > 0)
54  {
55    for (var i=0; i < bioplates.length; i++)
56    {
57      var bioplate = bioplates[i];
58      var option = new Option(bioplate.name, bioplate.id);
59      option.bioplate = bioplate;
60      plates.options[plates.length] = option;
61    }
62    bioplateIsValid = true;
63    setInputStatus('bioplate', '', 'valid');
64  }
65  else
66  {
67    var msg = 'No Library bioplates available for processing.';
68    setFatalError(msg);
69    return;
70  }
71}
72
73
74function getLibraryBioPlates()
75{
76  var frm = document.forms['reggie']; 
77 
78  var request = Ajax.getXmlHttpRequest();
79  try
80  {
81    showLoadingAnimation('Loading Library bioplates...');
82    var url = '../Pool.servlet?ID=<%=ID%>&cmd=GetLibraryPlatesForPooling';
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  return response.bioplates;
99}
100
101function createManualPool()
102{
103  location.replace('create_manual_pool.jsp?ID=<%=ID%>');
104}
105
106function goNext(manual)
107{
108  setInnerHTML('gonext.message', '');
109  if (currentStep == 1)
110  {   
111    gotoStep2();
112  }
113  setCurrentStep(currentStep);
114}
115
116function gotoStep2()
117{
118  var frm = document.forms['reggie'];
119  frm.bioplate.disabled = true;
120  Main.addClass(document.getElementById('step.1.section'), 'disabled');
121 
122  loadPoolNames();
123  loadLibraryInformation();
124
125  currentStep = 2;
126  Main.hide('step.1.section');
127  Main.show('step.2.section');
128  Main.hide('gonext');
129  Main.show('gocancel');
130  Main.show('gocreate');
131}
132
133function goCreate()
134{
135  if (!targetVolumePerLibIsValid) return;
136 
137  var submitInfo = {};
138  submitInfo.pools = [];
139  submitInfo.flagged = [];
140  var frm = document.forms['reggie'];
141  var libPlate = frm.bioplate[frm.bioplate.selectedIndex].bioplate;
142  submitInfo.targetVolumeInPoolPerLib = parseFloat(frm.target_volume.value);
143  submitInfo.targetPoolMolarity = TARGET_MOLARITY_IN_POOL;
144  submitInfo.mixingStrategy = Forms.getCheckedRadio(frm.mixing_strategy).value;
145
146  var numPools = Plate.getPools();
147  for (var poolNo = 0; poolNo < numPools; poolNo++)
148  {
149    var wells = Plate.getPool(poolNo);
150   
151    var poolInfo = {};
152    poolInfo.name = POOL_NAMES[poolNo];
153    poolInfo.comment = frm['comment.'+poolNo].value;
154    poolInfo.ebVolumeExtra = POOL_DATA[poolNo].ebVolumeExtra;
155    poolInfo.libPlate = libPlate.id;
156    poolInfo.libs = [];
157    poolInfo.excluded = [];
158   
159    for (var wellNo = 0; wellNo < wells.length; wellNo++)
160    {
161      var lib = wells[wellNo].extract;
162      if (lib)
163      {
164        // We send library id, name and mixin volumes
165        var tmp = {};
166        tmp.id = lib.id;
167        tmp.name = lib.name;
168        tmp.volume = lib.actualVolume; 
169        tmp.eb = lib.actualEb;
170        tmp.mixFactor = lib.mixFactor;
171        tmp.comment = lib.comment;
172       
173        if (lib.excludeFromPool)
174        {
175          poolInfo.excluded[poolInfo.excluded.length] = tmp;
176        }
177        else
178        {
179          poolInfo.libs[poolInfo.libs.length] = tmp;
180        }
181       
182        if (lib.flag)
183        {
184          tmp.flag = lib.flag;
185          submitInfo.flagged[submitInfo.flagged.length] = tmp;
186        }
187      }
188    }
189   
190    submitInfo.pools[submitInfo.pools.length] = poolInfo;
191  }
192 
193  Main.addClass(document.getElementById('step.2.section'), 'disabled');
194  Main.hide('gocancel');
195  Main.hide('gocreate');
196
197  if (debug) Main.debug(JSON.stringify(submitInfo));
198  var request = Ajax.getXmlHttpRequest();
199  try
200  {
201    showLoadingAnimation('Creating pools...');
202    var url = '../Pool.servlet?ID=<%=ID%>';
203    url += '&cmd=CreatePools';
204    request.open("POST", url, false);
205    request.setRequestHeader("Content-Type", "application/json");
206    request.send(JSON.stringify(submitInfo));
207  }
208  finally
209  {
210    hideLoadingAnimation();
211  }
212
213  if (debug) Main.debug(request.responseText);
214
215  var response = JSON.parse(request.responseText);
216  if (response.status != 'ok')
217  {
218    setFatalError(response.message);
219    return false;
220  }
221
222  var msg = '<ul>';
223  for (var i = 0; i < response.messages.length; i++)
224  {
225    msg += '<li>' + response.messages[i];
226  }
227  msg += '</ul>';
228  setInnerHTML('done', msg);
229  Main.show('done');
230  Main.show('gorestart');
231  scrollToBottom(document.getElementById('content'));
232
233}
234
235function loadLibraryInformation()
236{
237  var frm = document.forms['reggie'];
238  var libPlate = frm.bioplate[frm.bioplate.selectedIndex].bioplate;
239
240  // Load Libraries and related info from the selected bioplate
241  var request = Ajax.getXmlHttpRequest();
242  try
243  {
244    showLoadingAnimation('Loading information about libraries...');
245    var url = '../Pool.servlet?ID=<%=ID%>&cmd=GetLibraryInfoForPlate&bioplate='+libPlate.id;   
246    request.open("GET", url, false);
247    request.send(null);
248  }
249  finally
250  {
251    hideLoadingAnimation();
252  }
253 
254  if (debug) Main.debug(request.responseText);
255  var response = JSON.parse(request.responseText);
256  if (response.status != 'ok')
257  {
258    setFatalError(response.message);
259    return false;
260  }
261
262 
263  var schema = PoolSchema.getById(libPlate.poolSchema);
264  var barcodeVariant = PoolSchema.getBarcodeVariantByName(schema, libPlate.barcodeVariant);
265  Plate.setPoolSchema(schema);
266  WellPainter.barcodeVariant = barcodeVariant;
267  Plate.init(8, 12, schema, WellPainter);
268
269  var poolInfo = response.poolInfo;
270  TARGET_MOLARITY_IN_POOL = poolInfo.targetMolarity;
271  EXTRA_LARGE_MIX_FACTOR = poolInfo.extraLargeMixFactor;
272  LIMIT_FOR_EXTRA_LARGE_MIX = poolInfo.limitForExtraLargeMix;
273 
274  setInnerHTML('pool_schema', schema.name);
275  setInnerHTML('barcode_variant', barcodeVariant.name);
276  setInnerHTML('target_molarity', Numbers.formatNumber(TARGET_MOLARITY_IN_POOL, 1, ' nM'));
277
278  var libs = response.libraries;
279  var molarityLimit = TARGET_MOLARITY_IN_POOL * LIMIT_FOR_AUTO_EXCLUDE;
280  for (var i = 0; i < libs.length; i++)
281  {
282    var lib = libs[i];
283    var well = lib.bioWell;
284    lib.excludeFromPool = false;
285   
286    if (lib.molarity != null && lib.molarity < molarityLimit)
287    {
288      lib.excludeFromPool = true;
289      lib.flag = 'ExcludedFromPool';
290      lib.comment = 'Not enough DNA';
291    }
292
293    Plate.getWell(well.row, well.column).setExtract(lib);
294  }
295
296  PoolSchema.buildPoolTableRow(schema, 12);
297  setTargetVolumePerLib(poolInfo.targetVolumePerLib);
298}
299
300function loadPoolNames()
301{
302  var frm = document.forms['reggie'];
303  var libPlate = frm.bioplate[frm.bioplate.selectedIndex].bioplate;
304
305  var schema = PoolSchema.getById(libPlate.poolSchema);
306
307  // Load Libraries and related info from the selected bioplate
308  var request = Ajax.getXmlHttpRequest();
309  try
310  {
311    showLoadingAnimation('Loading Library bioplate information...');
312    var url = '../Pool.servlet?ID=<%=ID%>&cmd=GetNextAutoGeneratedPoolNames&numNames='+schema.numPools;   
313    request.open("GET", url, false);
314    request.send(null);
315  }
316  finally
317  {
318    hideLoadingAnimation();
319  }
320 
321  if (debug) Main.debug(request.responseText);
322  var response = JSON.parse(request.responseText);
323  if (response.status != 'ok')
324  {
325    setFatalError(response.message);
326    return false;
327  }
328 
329  var list = response.names;
330  for (var i = 0; i < list.length; i++)
331  {
332    POOL_NAMES[i] = list[i];
333  }
334
335}
336
337function setTargetVolumePerLib(targetVolumePerLib)
338{
339  var frm = document.forms['reggie'];
340  frm.target_volume.value = targetVolumePerLib;
341 
342  targetVolumePerLibIsValid = false;
343  if (targetVolumePerLib < 2 || targetVolumePerLib > 10)
344  {
345    setInputStatus('target_volume', 'Must be between 2 and 10µl', 'invalid');
346    return;
347  }
348  setInputStatus('target_volume', '', 'valid');
349  targetVolumePerLibIsValid = true;
350
351  // Pre-process the Library items
352  var mixingStrategy = Forms.getCheckedRadio(frm.mixing_strategy).value;
353  var wells = Plate.getWells();
354  for (var i = 0; i < wells.length; i++)
355  {
356    var lib = wells[i].extract;
357    if (lib)
358    {
359      if (lib.remainingQuantity == null)
360      {
361        lib.excludeFromPool = true;
362      }
363      else
364      {
365        PoolMix.calculateLibVolume(lib, TARGET_MOLARITY_IN_POOL, targetVolumePerLib, mixingStrategy);
366        PoolMix.calculateEbVolume(lib, TARGET_MOLARITY_IN_POOL, targetVolumePerLib, mixingStrategy);
367      }
368    }
369  }
370 
371  updatePoolData();
372  WellPainter.mixingStrategy = mixingStrategy;
373  Plate.paint(Plate.getWells());
374}
375
376function calculateRemarks(lib, schema, barcodeVariant)
377{
378  var well = lib.bioWell;
379  var remarks = [];
380
381  // Check if default barcode has been modified
382  var indexSet = barcodeVariant.indexSets[well.column];
383  if (indexSet)
384  {
385    var defaultBarcode = indexSet.barcodes[well.row];
386    if (defaultBarcode && lib.barcode.name != defaultBarcode)
387    {
388      remarks[remarks.length] = 'Modified barcode';
389      lib.barcode.modified = true;
390    }
391  }
392 
393  if (lib.molarity != null)
394  {
395    if (lib.volume != lib.actualVolume)
396    {
397      if (lib.volume > lib.remainingVolume)
398      {
399        remarks[remarks.length] = 'Low quantity';
400      }
401      else
402      {
403        remarks[remarks.length] = 'Low molarity';
404      }
405    }
406
407    if (lib.speedVacConc != null)
408    {
409      remarks[remarks.length] = 'SpeedVac';
410    }
411   
412    if (lib.mixFactor > 1)
413    {
414      // Larger mix than default
415      remarks[remarks.length] = 'Use ' + Numbers.formatNumber(lib.actualVolume+lib.actualEb, 1, 'µl') + ' in pool';
416    }
417   
418  }
419  lib.stratagene = lib.name.indexOf(GENERIC_STRATAGENE_NAME) == 0;
420  lib.external = lib.name.indexOf(EXTERNAL_RNA_NAME) == 0;
421  lib.remarks = remarks;
422}
423
424
425function updatePoolData()
426{
427  var frm = document.forms['reggie'];
428  var targetVolumePerLib = parseFloat(frm.target_volume.value);
429  var mixingStrategy = Forms.getCheckedRadio(frm.mixing_strategy).value;
430
431  var libPlate = frm.bioplate[frm.bioplate.selectedIndex].bioplate;
432  var schema = PoolSchema.getById(libPlate.poolSchema);
433  var barcodeVariant = PoolSchema.getBarcodeVariantByName(schema, libPlate.barcodeVariant);
434
435  var numSeparateMix = 0;
436  var numLowQuantity = 0;
437  var numExcluded = 0;
438 
439  for (var poolNo = 0; poolNo < Plate.getPools(); poolNo++)
440  {
441    // Get all libs into an array
442    var libs = [];
443    var wells = Plate.getPool(poolNo);
444    for (var wellNo = 0; wellNo < wells.length; wellNo++)
445    {
446      var well = wells[wellNo];
447      var lib = well.extract;
448      if (lib)
449      {
450        if (lib.excludeFromPool)
451        {
452          numExcluded++;
453        }
454        else
455        {
456          libs[libs.length] = lib;
457        }
458      }
459    }
460   
461    // Calculate final pool volumes, molarity, etc.
462    var poolInfo = PoolMix.calculateFinalPoolInfo(libs, TARGET_MOLARITY_IN_POOL, targetVolumePerLib, mixingStrategy);
463    POOL_DATA[poolNo] = poolInfo;
464   
465    // Make remarks for each lib
466    for (var libNo = 0; libNo < libs.length; libNo++)
467    {
468      var lib = libs[libNo];
469      calculateRemarks(lib, schema, barcodeVariant);
470      if (lib.eb != 0 || mixingStrategy == 'fixed') numSeparateMix++;
471      if (lib.volume > lib.actualVolume) numLowQuantity++;
472    }
473   
474    var warnMsg = null;
475    if (poolInfo.ebVolumeExtra < 0) 
476    {
477      warnMsg = 'Too many libs with low molarity';
478    }
479   
480    var poolDiv = document.getElementById('pool.'+poolNo);
481    var poolData = '<div class="pool-data">';
482    poolData += libs.length + ' libs  ';
483    poolData += Numbers.formatNumber(poolInfo.molarity, 2, 'nM')+'  ';
484    poolData += Numbers.formatNumber(poolInfo.totalVolume, 1, 'µl');
485    if (mixingStrategy == 'dynamic')
486    {
487      poolData += '  <span class="pool-eb">'+Numbers.formatNumber(poolInfo.ebVolumeExtra, 1, 'µl')+'</span>';
488    }
489    if (warnMsg)
490    {
491      Main.addClass(poolDiv, 'warning');
492      poolData += '<div class="warning-message">'+warnMsg+'</div>';
493    }
494    else
495    {
496      Main.removeClass(poolDiv, 'warning');
497    }
498    poolData += '</div>';
499    var poolComments = frm['comment.'+poolNo];
500    var comments = poolComments ? poolComments.value : '';
501    poolData += '<textarea name="comment.'+poolNo+'"></textarea>';
502    poolDiv.innerHTML = POOL_NAMES[poolNo] + poolData;
503    frm['comment.'+poolNo].value = comments;
504  }
505 
506  setInnerHTML('num_separate_mix', numSeparateMix);
507  setInnerHTML('num_low_quantity', numLowQuantity);
508  setInnerHTML('num_excluded', numExcluded);
509}
510
511function targetVolumeOnBlur()
512{
513  var frm = document.forms['reggie'];
514  var targetVolumePerLib = parseFloat(frm.target_volume.value);
515  setTargetVolumePerLib(targetVolumePerLib);
516}
517
518function mixingStrategyOnChange()
519{
520  targetVolumeOnBlur();
521}
522
523var WellPainter = function()
524{
525  var painter = {};
526 
527  painter.getClassNameForWell = function(well, schema)
528  {
529    var indexSet = painter.barcodeVariant.indexSets[well.column];
530    var cls = '';
531    var lib = well.extract;
532   
533    if (lib)
534    {
535      if (lib.excludeFromPool)
536      {
537        cls += ' exclude-from-pool';
538      }
539      else if (indexSet)
540      {
541        cls += ' ' + (lib && lib.barcode.modified ? 'bg-modified' : indexSet.color);
542      }
543      if (lib.flag)
544      {
545        cls += ' flagged';
546      }
547      if (!lib.flag && lib.actualVolume < lib.volume)
548      {
549        cls += ' low-volume';
550      }
551    }
552    else if (indexSet)
553    {
554      cls += indexSet.color;
555    }
556    return cls;
557  }
558 
559  painter.getWellText = function(well, schema)
560  {
561    var text = '';
562    var lib = well.extract;
563    if (lib)
564    {
565      var name = lib.name;
566      var i = name.indexOf('.m');
567      var mixFactor = lib.mixFactor;
568      var displayName = name.substring(0, i)+'.<br>&nbsp;'+name.substring(i);
569      text += '<div class="lib">'+displayName+'</div>';
570      text += '<div>';
571      text += '<span class="barcode">'+lib.barcode.name+'</span>';
572      if (lib.molarity != null)
573      {
574        text += '<span class="molarity">'+Numbers.formatNumber(lib.molarity, 2, 'nM')+'</span>';
575      }
576      text += '</div>';
577      if (!lib.excludeFromPool)
578      {
579        mark = (lib.volume > lib.actualVolume) ? '*' : '';
580        text += '<div>';
581        text += '<span class="volume">'+(isFinite(lib.volume) ? Numbers.formatNumber(lib.volume*mixFactor, 1, 'µl'+mark) : '∞')+'</span>';
582        if (painter.mixingStrategy == 'fixed' || lib.mixFactor > 1)
583        {
584          text += '<span class="eb">'+(isFinite(lib.eb) ? Numbers.formatNumber(lib.eb*mixFactor, 1, 'µl') : '-∞')+'</span>';
585        }
586        else
587        {
588          text += '<span class="eb"></span>';
589        }
590        text += '</div>';
591      }
592      if (lib.remarks) text += '<div class="remarks">'+ lib.remarks.join('; ') + '</div>';
593      if (lib.comment)
594      {
595        text += '<div class="remarks">'+ lib.comment + '</div>';
596      }
597    }
598    return text;
599  }
600
601  return painter;
602}();
603
604//Toggle the selected status of a single well
605function toggleWell(row, column)
606{
607  var well = Plate.getWell(row, column);
608  Plate.toggleSelected([well]);
609}
610
611var lastComment = '';
612function excludeSelected()
613{
614  var wells = Plate.getSelected();
615 
616  if (wells.length == 0)
617  {
618    alert('No wells have been selected');
619    return;
620  }
621
622  // See if there is an existing comment
623  var comment;
624  for (var i = 0; i < wells.length; i++)
625  {
626    var lib = wells[i].extract;
627    if (lib && lib.comment) 
628    {
629      comment = lib.comment;
630    }
631  }
632
633  comment = prompt('Comment on reason for exclusion', comment || lastComment);
634  if (comment == null) return;
635  lastComment = comment;
636 
637  if (comment == '') comment = null;
638 
639  for (var i = 0; i < wells.length; i++)
640  {
641    var well = wells[i];
642    var lib = well.extract;
643    if (lib)
644    {
645      lib.excludeFromPool = true;
646      if (!lib.stratagene && !lib.external)
647      {
648        lib.flag = 'ExcludedFromPool';
649        lib.comment = comment;
650      }
651    }
652    well.selected = false;
653  }
654 
655  updatePoolData();
656  Plate.paint(Plate.getWells());
657}
658
659function includeSelected()
660{
661  var wells = Plate.getSelected();
662 
663  if (wells.length == 0)
664  {
665    alert('No wells have been selected');
666    return;
667  }
668
669  for (var i = 0; i < wells.length; i++)
670  {
671    var well = wells[i];
672    var lib = well.extract;
673    if (lib)
674    {
675      lib.excludeFromPool = false;
676      lib.flag = null;
677      lib.oldComment = lib.comment;
678      lib.comment = null;
679    }
680    well.selected = false;
681  }
682 
683  updatePoolData();
684  Plate.paint(Plate.getWells());
685}
686
687//Flag the selected RNA
688function toggleFlag()
689{
690  var wells = Plate.getSelected();
691 
692  if (wells.length == 0)
693  {
694    alert('No wells have been selected');
695    return;
696  }
697
698  var flag = null;
699  var firstLib = true;
700  for (var i = 0; i < wells.length; i++)
701  {
702    var well = wells[i];
703    var lib = well.extract;
704    if (lib)
705    {
706      if (firstLib && !lib.excludeFromPool)
707      {
708        flag = lib.flag ? null : 'ManualFlag';
709        firstLib = false;
710      }
711      lib.flag = lib.excludeFromPool ? 'ExcludedFromPool' : flag;
712    }
713    //well.selected = false;
714  }
715 
716  Plate.paint(wells);
717}
718
719//Set a comment on the selected wells
720function commentSelected(comment)
721{
722  var wells = Plate.getSelected();
723 
724  if (comment == undefined)
725  {
726    if (wells.length == 0)
727    {
728      alert('No wells have been selected');
729      return;
730    }
731   
732    var count = 0;
733    for (var i = 0; i < wells.length; i++)
734    {
735      var well = wells[i];
736      if (well.extract) 
737      {
738        if (well.extract.comment) comment = well.extract.comment;
739        count++;
740      }
741    }
742   
743    if (count == 0)
744    {
745      alert('Only empty wells have been selected');
746      return;
747    }
748   
749    comment = prompt('Comment', comment || lastComment);
750    if (comment == null) return;
751  }
752 
753  lastComment = comment;
754 
755  if (comment == '') comment = null;
756  for (var i = 0; i < wells.length; i++)
757  {
758    var well = wells[i];
759    if (well.extract) 
760    {
761      well.extract.comment = comment;
762    }
763    well.selected = false;
764  }
765  Plate.paint(wells);
766}
767
768
769</script>
770<style>
771.lib
772{
773  font-weight: bold;
774  margin-bottom: 0.25em;
775  overflow: hidden;
776  text-overflow: ellipsis;
777}
778.barcode
779{}
780.molarity
781{
782  float: right;
783}
784
785.volume
786{
787  color: #C80000;
788}
789.eb
790{
791  color: #0000C8;
792  float: right;
793}
794.pool-eb
795{
796  color: #0000C8;
797}
798.remarks
799{
800  color: #C80000;
801  font-style: italic;
802}
803.pool-data
804{
805  font-weight: normal;
806}
807.pool.warning
808{
809  background-image: url('../images/warning.png');
810  background-position: 98% 5%;
811  background-repeat: no-repeat;
812}
813
814.pool-data .warning-message
815{
816  color: #C80000;
817  font-style: italic;
818}
819
820.well.exclude-from-pool
821{
822  background-color: #FFFFFF !important;
823}
824
825.well.exclude-from-pool.selected
826{
827  background-color: #D8D8D8 !important;
828}
829
830.well.exclude-from-pool *
831{
832  color: #999999 !important;
833}
834.well.flagged
835{
836  background-image: url('../images/flag.png');
837  background-position: 98% 5%;
838  background-repeat: no-repeat;
839}
840
841.well.low-volume
842{
843  background-image: url('../images/warning.png') !important;
844  background-position: 98% 5%;
845  background-repeat: no-repeat;
846}
847.pool textarea
848{
849  width: 95%;
850  height: 3.5em;
851}
852</style>
853</base:head>
854<base:body onload="init()">
855
856  <p:path><p:pathelement 
857    title="Reggie" href="<%="../index.jsp?ID="+ID%>" 
858    /><p:pathelement title="Create pooled libraries" 
859    /></p:path>
860
861  <div class="content" id="content">
862  <%
863  if (sc.getActiveProjectId() == 0)
864  {
865    %>
866    <div class="messagecontainer note" style="width: 950px; margin-left: 20px; margin-bottom: 20px; margin-right: 0px; font-weight: bold; color: #cc0000;">
867      No project has been selected. You may proceed with the registration but
868      created items will not be shared.
869    </div>
870    <%
871  }
872  %>
873
874  <div class="allsteps">
875    <div class="step current" id="step.1">1</div>
876    ›
877    <div class="step future" id="step.2">2</div>
878  </div>
879
880  <form name="reggie" onsubmit="return false;">
881 
882  <div id="step.1.section">
883  <table class="stepform">
884  <tr>
885    <td rowspan="3" class="stepno">1</td>
886    <td class="steptitle">Select source for pool</td>
887  </tr>
888  <tr>
889    <td class="stepfields">
890      <table>
891      <tr valign="top">
892        <td class="prompt">Library bioplate</td>
893        <td class="input"><select style="width:90%" 
894            name="bioplate" id="bioplate" onchange="bioPlateOnChange()"></select>
895        </td>
896        <td class="status" id="bioplate.status"></td>
897        <td class="help"><span id="bioplate.message" class="message" style="display: none;"></span>
898          Select an existing Library bioplate. The list contain all Library bioplates that
899          contain libraries with no child items.
900        </td>
901      </tr>
902      <tr valign="top">
903        <td class="prompt"></td>
904        <td class="input"> - or -</td>
905        <td class="status"></td>
906        <td class="help"></td>
907      </tr>
908      <tr valign="top">
909        <td class="prompt"></td>
910        <td class="input">
911          <table><tr><td>
912            <base:button title="Create manual pool" onclick="createManualPool()" image="<%=home+"/images/gonext.png"%>" />
913          </td></tr></table>
914       
915        </td>
916        <td class="status"></td>
917        <td class="help"></td>
918      </tr>
919      </table>
920    </td>
921  </tr>
922  </table>
923  </div>
924 
925  <div id="step.2.section" style="display: none;">
926  <table class="stepform" style="width: auto;">
927  <tr>
928    <td rowspan="2" class="stepno">2</td>
929    <td class="steptitle">Confirm pool layout</td>
930  </tr>
931  <tr>
932    <td class="stepfields">
933
934      <table class="bottomborder" style="width: 100%;">
935      <tr valign="top">
936        <td class="prompt">Pool layout</td>
937        <td class="input">
938          <span id="pool_schema"></span>; <span id="barcode_variant"></span>
939        </td>
940        <td class="status"></td>
941        <td class="help"></td>
942      </tr>
943      <tr valign="top">
944        <td class="prompt">Target molarity</td>
945        <td class="input">
946          <span id="target_molarity"></span>
947        </td>
948        <td class="status"></td>
949        <td class="help"></td>
950      </tr>
951      <tr valign="top">
952        <td class="prompt">Average volume / lib</td>
953        <td class="input">
954          <input type="text" class="text" name="target_volume" 
955            value="5" style="width: 4em;"
956            onblur="targetVolumeOnBlur()"
957            onkeypress="doOnEnter(event, targetVolumeOnBlur); return Numbers.numberOnly(event)"> µl (2--10)
958        </td>
959        <td class="status" id="target_volume.status"></td>
960        <td class="help" rowspan="2"><span id="target_volume.message" class="message" style="display: none;"></span>
961          Select a target volume when mixing each lib to 2nM before pooling.
962          Use the <b>Dynamic</b> strategy to prioritize final pool molarity by mixing
963          different volume for each library. Use the <b>Fixed</b> strategy to mix all
964          libraries to the given volume.
965        </td>
966      </tr>
967      <tr valign="top">
968        <td class="prompt">Mixing strategy</td>
969        <td class="input">
970          <label><input type="radio" name="mixing_strategy" value="dynamic" checked
971            onclick="mixingStrategyOnChange()"
972            >Dynamic</label>
973          <label><input type="radio" name="mixing_strategy" value="fixed"
974            onclick="mixingStrategyOnChange()"
975            >Fixed</label>
976        </td>
977        <td class="status" id="mixing_strategy.status"></td>
978      </tr>
979      </table>
980      <tbl:toolbar subclass="bottomborder">
981        <tbl:button 
982          title="Exclude from pool&hellip;" 
983          image="<%=home+"/images/delete.png"%>" 
984          onclick="excludeSelected()" 
985          tooltip="Exclude the selected libraries from the pool"
986        />
987        <tbl:button 
988          title="Include in pool" 
989          image="<%=home+"/images/new.png"%>" 
990          onclick="includeSelected()" 
991          tooltip="Include the selected libraries in the pool"
992        />
993        <tbl:button 
994          title="Toggle flag" 
995          image="<%=home+"/images/flag.png"%>" 
996          onclick="toggleFlag()" 
997          tooltip="Flag the parent RNA for the selected libraries"
998        />
999        <tbl:button 
1000          title="Comments&hellip;" 
1001          image="<%=home+"/images/comment.png"%>" 
1002          onclick="commentSelected()" 
1003          tooltip="Add a comment to the selected libraries" 
1004        />
1005      </tbl:toolbar>
1006     
1007      <div style="margin: 1em;" class="messagecontainer note">
1008        <base:icon image="info.png"/> 
1009        <b>Separate mix:</b> <span id="num_separate_mix"></span>,
1010        <b>Low quantity:</b> <span id="num_low_quantity"></span>,
1011        <b>Excluded:</b> <span id="num_excluded"></span>
1012      </div>
1013     
1014      <table class="plate" style="margin: 1em 1em 1em 1em;" id="plate">
1015      <%
1016      int columns = 12;
1017      int rows = 8;
1018      WellCoordinateFormatter rowF = new WellCoordinateFormatter(true);
1019      WellCoordinateFormatter colF = new WellCoordinateFormatter(false);
1020      %>
1021      <tr class="header">
1022        <th></th>
1023        <%
1024        for (int c = 0; c < columns; ++c)
1025        {
1026          %>
1027          <th id="col.<%=c%>"><%=colF.format(c)%></th>
1028          <%
1029        }
1030        %>
1031      </tr>
1032      <tbody>
1033      <%
1034      for (int r = 0; r < rows; ++r)
1035      {
1036        String row = rowF.format(r);
1037        %>
1038        <tr class="row-<%=r%>">
1039          <th id="row.<%=r%>" class="rowheader"><%=row%></th>
1040          <%
1041          for (int c = 0; c < columns; ++c)
1042          {
1043            %>
1044            <td class="well col-<%=c%>" id="well.<%=r%>.<%=c%>"
1045              onclick="toggleWell(<%=r%>,<%=c%>)"
1046              title="Select/deselect this well"
1047              ></td>
1048            <%
1049          }
1050          %>
1051        </tr>
1052        <%
1053      }
1054      %>
1055      </tbody>
1056      <tr id="pool-row">
1057        <th colspan="13">&nbsp;</th>
1058      </tr>
1059      </table>
1060      <div style="margin: 1em;">
1061      Low molarity = The concentration of this library too low to mix to target molarity for the pool.<br>
1062      For each pool: <i>Number of libraries</i> • <i>Final molarity</i> • <i>Total volume</i> • <i>EB volume (dynamic mixing only)</i>
1063      </div>
1064    </td>
1065  </tr>
1066  </table>
1067  </div>
1068 
1069  <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>
1070 
1071  <div class="messagecontainer error" id="errorMessage" style="display: none; width: 950px; margin-left: 20px; margin-bottom: 0px;"></div>
1072 
1073  <div id="done" class="success" style="display: none; width: 950px; margin-left: 20px; margin-top: 20px;"></div>
1074 
1075  <table style="margin-left: 20px; margin-top: 10px; margin-bottom: 3em;" class="navigation">
1076    <tr>
1077      <td><base:button id="gocancel" title="Cancel" onclick="goRestart(false)" /></td>
1078      <td><base:button id="gonext" title="Next" image="<%=home+"/images/gonext.png"%>" onclick="goNext(true)"/></td>
1079      <td><base:button id="gocreate" title="Create" image="<%=home+"/images/gonext.png"%>" onclick="goCreate()" style="display: none;"/></td>
1080      <td><base:button id="gorestart" title="Restart" image="<%=home+"/images/goback.png"%>" onclick="goRestart(true)" style="display: none;"/></td>
1081      <td id="gonext.message" class="message"></td>
1082    </tr>
1083  </table>
1084 
1085 
1086  </form>
1087  </div>
1088 
1089</base:body>
1090</base:page>
1091<%
1092}
1093finally
1094{
1095  if (dc != null) dc.close();
1096}
1097%>
Note: See TracBrowser for help on using the repository browser.