source: extensions/net.sf.basedb.reggie/trunk/resources/libprep/create_manual_pool.jsp @ 2150

Last change on this file since 2150 was 2150, checked in by Nicklas Nordborg, 10 years ago

Fixes #537: Allow 10µl as max volume in Create pooled libraries wizard

File size: 23.4 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  <script language="JavaScript" src="../reggie.js" type="text/javascript" charset="UTF-8"></script>
30  <script language="JavaScript" src="pools.js" type="text/javascript" charset="UTF-8"></script>
31
32<script language="JavaScript">
33var debug = 0;
34var currentStep = 1;
35
36var selectedLibraries = [];
37var targetVolumePerLibIsValid = false;
38var poolInfo;
39
40// Loaded from servlet when getting Library information
41var TARGET_MOLARITY_IN_POOL;
42var LIMIT_FOR_AUTO_EXCLUDE = 0.25;
43var LIMIT_FOR_EXTRA_LARGE_MIX;
44var EXTRA_LARGE_MIX_FACTOR;
45
46function init()
47{
48  var frm = document.forms['reggie'];
49
50  // Load some default pooling options and the auto-generated name for the next pool
51  var response = loadPoolInfo();
52  var poolInfo = response.poolInfo;
53  TARGET_MOLARITY_IN_POOL = poolInfo.targetMolarity;
54  EXTRA_LARGE_MIX_FACTOR = poolInfo.extraLargeMixFactor;
55  LIMIT_FOR_EXTRA_LARGE_MIX = poolInfo.limitForExtraLargeMix;
56  setInnerHTML('pool-name', response.names[0]);
57  setInnerHTML('target_molarity', Numbers.formatNumber(TARGET_MOLARITY_IN_POOL, 1, ' nM'));
58 
59  frm.target_volume.value = poolInfo.targetVolumePerLib;
60  frm.poolName.value = response.names[0];
61  targetVolumeOnChange();
62}
63
64
65function loadPoolInfo()
66{
67  var frm = document.forms['reggie'];
68
69  // Load Libraries and related info from the selected bioplate
70  var request = Ajax.getXmlHttpRequest();
71  try
72  {
73    showLoadingAnimation('Loading pooling information...');
74    var url = '../Pool.servlet?ID=<%=ID%>&cmd=GetNextAutoGeneratedPoolNames&numNames=1';   
75    request.open("GET", url, false);
76    request.send(null);
77  }
78  finally
79  {
80    hideLoadingAnimation();
81  }
82 
83  if (debug) Main.debug(request.responseText);
84  var response = JSON.parse(request.responseText);
85  if (response.status != 'ok')
86  {
87    setFatalError(response.message);
88    return false;
89  }
90 
91  return response;
92}
93
94function checkAll()
95{
96  var frm = document.forms['reggie'];
97
98  var check = null;
99  for (var i = 0; i < frm.elements.length; i++)
100  {
101    var e = frm.elements[i];
102    if (e.type == 'checkbox')
103    {
104      if (check == null) check = !e.checked;
105      e.checked = check;
106    }
107  }
108}
109
110function removeSelected()
111{
112  var frm = document.forms['reggie'];
113  var tbody = document.getElementById('lib-table-rows');
114  var numRemoved = 0;
115  for (var libNo = selectedLibraries.length-1; libNo >= 0; libNo--)
116  {
117    var lib = selectedLibraries[libNo];
118    if (frm['check.'+lib.id].checked)
119    {
120      var tr = document.getElementById('lib.'+lib.id);
121      tbody.removeChild(tr);
122      selectedLibraries.splice(libNo, 1);
123      numRemoved++;
124    }
125  }
126 
127  if (numRemoved > 0)
128  {
129    updatePoolData();
130  }
131 
132  if (selectedLibraries.length == 0)
133  {
134    Main.show('not-selected');
135    Main.hide('lib-table');
136  }
137}
138
139var subtypeLibrary = null;
140
141function selectLibraries()
142{
143  var frm = document.forms['reggie'];
144 
145  if (subtypeLibrary == null)
146  {
147    var request = Ajax.getXmlHttpRequest();
148    var url = '../Subtype.servlet?ID=<%=ID%>&cmd=GetSubtypeInfo&name=LIBRARY';
149    request.open("GET", url, false); 
150    request.send(null);
151
152    if (debug) Main.debug(request.responseText);
153    var response = JSON.parse(request.responseText); 
154    if (response.status != 'ok')
155    {
156      setFatalError(response.message);
157      return false;
158    }
159    subtypeLibrary = response.subtype;
160  }
161 
162  var url = getRoot() + 'biomaterials/extracts/index.jsp?ID=<%=ID%>&cmd=UpdateContext&mode=selectmultiple&callback=setLibraryCallback';
163  url += '&resetTemporary=1';
164  url += '&tmpfilter:INT:itemSubtype='+subtypeLibrary.id;
165  url += '&tmpfilter:DATE:creationEvent.eventDate='+encodeURIComponent('<>');
166  url += '&tmpfilter:STRING:bioWell.bioPlate.name='+encodeURIComponent('<>');;
167 
168  var exclude = [];
169  for (var libNo = 0; libNo < selectedLibraries.length; libNo++)
170  {
171    exclude[exclude.length] = selectedLibraries[libNo].id;
172  }
173  if (exclude.length > 0) url += '&exclude='+exclude.join(',');
174 
175  Main.openPopup(url, 'SelectLibrary', 1000, 700);
176}
177
178function setLibraryCallback(id, name)
179{
180  var frm = document.forms['reggie'];
181
182  // Check if this library has already been selected
183  for (var i = 0; i < selectedLibraries.length; i++)
184  {
185    if (selectedLibraries[i].id == id)
186    {
187      return;
188    }
189  }
190 
191  // Disable timer while we are working -- will be re-enabled later
192  if (updateTimerId) clearTimeout(updateTimerId);
193 
194  // Get more information about the selected library
195  var request = Ajax.getXmlHttpRequest();
196  var url = '../Pool.servlet?ID=<%=ID%>&cmd=GetLibraryInfo&libraryId=' + id;   
197  request.open("GET", url, false); 
198  request.send(null);
199
200  if (debug) Main.debug(request.responseText);
201  var response = JSON.parse(request.responseText);
202  if (response.status != 'ok')
203  {
204    setFatalError(response.message);
205    return false;
206  }
207 
208  var lib = response.library;
209  selectedLibraries[selectedLibraries.length] = lib;
210
211  lib.excludeFromPool = lib.molarity > 0 && lib.remainingQuantity > 0 ? false : true;
212 
213  Main.hide('not-selected');
214  Main.show('lib-table');
215
216  addLibraryToTable(lib);
217  updatePoolDataDelayed();
218}
219
220function addLibraryToTable(lib)
221{
222  var tr = document.createElement('tr');
223  tr.id = 'lib.'+lib.id;
224  var className = '';
225  if (lib.excludeFromPool) className += ' excluded';
226  addColumn(tr, 'check', '<input type="checkbox" name="check.'+lib.id+'" value="'+lib.id+'">');
227  addColumn(tr, 'name', lib.name);
228  addColumn(tr, 'barcode', lib.barcode ? lib.barcode.name : '-');
229  addColumn(tr, 'location', lib.bioWell ? lib.bioWell.bioPlate.name + ' ' + lib.bioWell.location : '-');
230  addColumn(tr, 'remain', lib.remainingVolume ? Numbers.formatNumber(lib.remainingVolume, 1) : '-');
231  addColumn(tr, 'molarity', lib.molarity ? Numbers.formatNumber(lib.molarity, 2) : '-');
232  addColumn(tr, 'volume', '');
233  addColumn(tr, 'eb', '');
234  addColumn(tr, 'remarks', '');
235  tr.className = className;
236
237  // Rows should be sorted by barcode
238  // Locate existing row
239  tr.sortBy = lib.barcode ? lib.barcode.name : lib.name;
240  var tbody = document.getElementById('lib-table-rows');
241 
242  var target = null;
243  for (var i = 0; i < tbody.childNodes.length; i++)
244  {
245    var row = tbody.childNodes[i];
246    if (row.sortBy && (row.sortBy > tr.sortBy))
247    {
248      // Found it!
249      target = row;
250      break;
251    };
252  }
253 
254  tbody.insertBefore(tr, target);
255}
256
257function addColumn(tr, idSuffix, text)
258{
259  var td = document.createElement('td');
260  td.id = tr.id+'.'+idSuffix;
261  td.className = idSuffix;
262  td.innerHTML = text;
263  tr.appendChild(td);
264}
265
266
267function calculateRemarks(lib, mixingStrategy, duplicateBarcodes)
268{
269  var remarks = [];
270
271  // Check if default barcode has been modified
272  if (lib.molarity != null)
273  {
274    if (duplicateBarcodes[lib.barcode.name])
275    {
276      remarks[remarks.length] = 'Duplicate barcode: ' + lib.barcode.name;
277    }
278   
279    if (lib.volume != lib.actualVolume)
280    {
281      if (lib.volume > lib.remainingVolume)
282      {
283        remarks[remarks.length] = 'Low quantity';
284      }
285      else
286      {
287        remarks[remarks.length] = 'Low molarity';
288      }
289      if (mixingStrategy == 'fixed')
290      {
291        remarks[remarks.length] = 'Mix <span class="volume">'+Numbers.formatNumber(lib.actualVolume, 1) + '</span>+<span class="eb">' + Numbers.formatNumber(lib.actualEb, 1)+'µl</span>';
292      }
293      else
294      {
295        remarks[remarks.length] = 'Use <span class="volume">'+Numbers.formatNumber(lib.actualVolume, 1) + 'µl</span>';
296      }
297    }
298   
299    if (lib.speedVacConc != null)
300    {
301      remarks[remarks.length] = 'SpeedVac';
302    }
303   
304    if (lib.mixFactor > 1)
305    {
306      // Larger mix than default
307      remarks[remarks.length] = 'Mix <span class="volume">'+Numbers.formatNumber(lib.volume*lib.mixFactor, 1) + '</span>+<span class="eb">' + Numbers.formatNumber(lib.eb*lib.mixFactor, 1)+'µl</span>';
308      remarks[remarks.length] = 'Use <b>' + Numbers.formatNumber(lib.volume+lib.eb, 1) + 'µl</b> in pool';
309    }
310  }
311  if (lib.excludeFromPool)
312  {
313    remarks[remarks.length] = 'Excluded';
314  }
315  if (lib.comment)
316  {
317    remarks[remarks.length] = lib.comment;
318  }
319  lib.stratagene = lib.name.indexOf(GENERIC_STRATAGENE_NAME) == 0;
320  lib.external = lib.name.indexOf(EXTERNAL_RNA_NAME) == 0;
321  lib.remarks = remarks;
322}
323
324
325var updateTimerId = null;
326function updatePoolDataDelayed()
327{
328  // Cancel previous time
329  if (updateTimerId) clearTimeout(updateTimerId);
330  updateTimerId = setTimeout(updatePoolData, 200);
331}
332
333function updatePoolData()
334{
335  updateTimerId = null;
336 
337  if (!targetVolumePerLibIsValid || selectedLibraries.length == 0) return;
338 
339  var frm = document.forms['reggie'];
340  var targetVolumePerLib = parseFloat(frm.target_volume.value);
341  var mixingStrategy = Forms.getCheckedRadio(frm.mixing_strategy).value;
342
343  // Get all libs into an array
344  var libs = [];
345  var usedBarcodes = [];
346  var duplicateBarcodes = [];
347  for (var selectedNo = 0; selectedNo < selectedLibraries.length; selectedNo++)
348  {
349    var lib = selectedLibraries[selectedNo];
350    if (!lib.excludeFromPool)
351    {
352      libs[libs.length] = lib;
353      if (usedBarcodes[lib.barcode.name])
354      {
355        duplicateBarcodes[lib.barcode.name] = 1;
356      }
357      else
358      {
359        usedBarcodes[lib.barcode.name] = 1;
360      }
361      PoolMix.calculateLibVolume(lib, TARGET_MOLARITY_IN_POOL, targetVolumePerLib, mixingStrategy);
362      PoolMix.calculateEbVolume(lib, TARGET_MOLARITY_IN_POOL, targetVolumePerLib, mixingStrategy);
363    }
364  }
365   
366  // Calculate final pool volumes, molarity, etc.
367  poolInfo = PoolMix.calculateFinalPoolInfo(libs, TARGET_MOLARITY_IN_POOL, targetVolumePerLib, mixingStrategy);
368 
369  // Make remarks for each lib
370  for (var libNo = 0; libNo < selectedLibraries.length; libNo++)
371  {
372    var lib = selectedLibraries[libNo];
373    if (!lib.excludeFromPool)
374    {
375      var mark = '';
376      var tr = document.getElementById('lib.'+lib.id);
377      if (duplicateBarcodes[lib.barcode.name])
378      {
379        Main.addClass(tr, 'lib-error');
380        lib.hasError = true;
381      }
382      else
383      {
384        Main.removeClass(tr, 'lib-error');
385        lib.hasError = false;
386      }
387      if (lib.volume != lib.actualVolume)
388      {
389        mark = '*';
390        Main.addClass(tr, 'warning');
391      }
392      else
393      {
394        Main.removeClass(tr, 'warning');
395      }
396      setInnerHTML('lib.'+lib.id+'.volume', lib.mixFactor > 1 ? '-' : Numbers.formatNumber(lib.volume, 1)+mark);
397      if (mixingStrategy == 'fixed' && lib.mixFactor < 1.001)
398      {
399        setInnerHTML('lib.'+lib.id+'.eb', Numbers.formatNumber(lib.eb, 1));
400      }
401      else
402      {
403        setInnerHTML('lib.'+lib.id+'.eb', '-');
404      }
405    }
406   
407    calculateRemarks(lib, mixingStrategy, duplicateBarcodes);
408    setInnerHTML('lib.'+lib.id+'.remarks', lib.remarks.join('; '));
409  }
410 
411  var warnMsg = null;
412  if (poolInfo.ebVolumeExtra < 0) 
413  {
414    warnMsg = 'Too many libs with low molarity';
415  }
416 
417  setInnerHTML('pool.eb', Numbers.formatNumber(poolInfo.ebVolumeExtra, 1));
418
419  var poolDiv = document.getElementById('pool-summary');
420  var poolRow = document.getElementById('lib-table-pool-summary');
421  var poolData = '<div class="pool-data">';
422  poolData += libs.length + ' libs  ';
423  poolData += Numbers.formatNumber(poolInfo.molarity, 2, 'nM')+'  ';
424  poolData += Numbers.formatNumber(poolInfo.totalVolume, 1, 'µl');
425  if (mixingStrategy == 'dynamic')
426  {
427    poolData += '  <span class="eb">'+Numbers.formatNumber(Math.max(0, poolInfo.ebVolumeExtra), 1, 'µl')+'</span>';
428  }
429  if (warnMsg)
430  {
431    Main.addClass(poolRow, 'warning');
432    setInnerHTML('pool.remarks', warnMsg);
433  }
434  else
435  {
436    Main.removeClass(poolRow, 'warning');
437    setInnerHTML('pool.remarks', '');
438  }
439 
440  poolData += '</div>';
441  poolDiv.innerHTML = poolData;
442}
443
444function targetVolumeOnChange()
445{
446  var frm = document.forms['reggie'];
447  var targetVolumePerLib = parseFloat(frm.target_volume.value);
448 
449  targetVolumePerLibIsValid = false;
450  if (targetVolumePerLib < 2 || targetVolumePerLib > 10)
451  {
452    setInputStatus('target_volume', 'Must be between 2 and 10µl', 'invalid');
453    return;
454  }
455  setInputStatus('target_volume', '', 'valid');
456  targetVolumePerLibIsValid = true;
457
458  updatePoolData();
459}
460
461function mixingStrategyOnChange()
462{
463  updatePoolData();
464}
465
466function goCreate()
467{
468  if (!targetVolumePerLibIsValid) return;
469  if (selectedLibraries.length == 0) return;
470
471 
472  var submitInfo = {};
473  submitInfo.pools = [];
474  submitInfo.flagged = []; // Always empty
475  var frm = document.forms['reggie'];
476  submitInfo.targetVolumeInPoolPerLib = parseFloat(frm.target_volume.value);
477  submitInfo.targetPoolMolarity = TARGET_MOLARITY_IN_POOL;
478  submitInfo.mixingStrategy = Forms.getCheckedRadio(frm.mixing_strategy).value;
479 
480  var pool = {};
481  pool.name = frm.poolName.value;
482  pool.comment = frm.poolComments.value;
483  pool.ebVolumeExtra = Math.max(0, poolInfo.ebVolumeExtra);
484  pool.libs = [];
485  pool.excluded = [];
486 
487  for (var libNo = 0; libNo < selectedLibraries.length; libNo++)
488  {
489    var lib = selectedLibraries[libNo];
490    if (lib.hasError) return;
491   
492    // We send library id, name and mixing volumes
493    if (!lib.excludeFromPool)
494    {
495      var tmp = {};
496      tmp.id = lib.id;
497      tmp.name = lib.name;
498      tmp.volume = lib.actualVolume;
499      tmp.eb = lib.actualEb;
500      tmp.mixFactor = lib.mixFactor;
501      tmp.comment = lib.comment;
502      pool.libs[pool.libs.length] = tmp;
503    }
504  }
505  submitInfo.pools[submitInfo.pools.length] = pool;
506 
507  Main.addClass(document.getElementById('step.1.section'), 'disabled');
508  Main.hide('gocancel');
509  Main.hide('gocreate');
510
511  if (debug) Main.debug(JSON.stringify(submitInfo));
512  var request = Ajax.getXmlHttpRequest();
513  try
514  {
515    showLoadingAnimation('Creating pool...');
516    var url = '../Pool.servlet?ID=<%=ID%>';
517    url += '&cmd=CreatePools';
518    request.open("POST", url, false);
519    request.setRequestHeader("Content-Type", "application/json");
520    request.send(JSON.stringify(submitInfo));
521  }
522  finally
523  {
524    hideLoadingAnimation();
525  }
526
527  if (debug) Main.debug(request.responseText);
528
529  var response = JSON.parse(request.responseText);
530  if (response.status != 'ok')
531  {
532    setFatalError(response.message);
533    return false;
534  }
535
536  var msg = '<ul>';
537  for (var i = 0; i < response.messages.length; i++)
538  {
539    msg += '<li>' + response.messages[i];
540  }
541  msg += '</ul>';
542  setInnerHTML('done', msg);
543  Main.show('done');
544  Main.show('gorestart');
545  scrollToBottom(document.getElementById('content'));
546
547}
548
549//Set a comment on the checked libraries
550var lastComment = '';
551function commentChecked()
552{
553  var frm = document.forms['reggie'];
554 
555  // Get array with checked libs
556  var checked = [];
557  var comment;
558  for (var libNo = 0; libNo < selectedLibraries.length; libNo++)
559  {
560    var lib = selectedLibraries[libNo];
561    if (frm['check.'+lib.id].checked)
562    {
563      checked[checked.length] = lib;
564      if (!comment) comment = lib.comment;
565    }
566  }
567 
568  if (checked.length == 0)
569  {
570    alert('No libraries have been selected');
571    return;
572  }
573       
574  comment = prompt('Comment', comment || lastComment);
575  if (comment == null) return;
576
577  lastComment = comment;
578 
579  if (comment == '') comment = null;
580  for (var libNo = 0; libNo < checked.length; libNo++)
581  {
582    var lib = checked[libNo];
583    lib.comment = comment;
584  }
585 
586  updatePoolData();
587}
588
589</script>
590<style>
591
592#pool-table
593{
594  width: 100%;
595}
596
597#pool-name
598{
599  font-size: 125%;
600}
601
602#pool-table th, #pool-table td
603{
604  text-align: left;
605  padding: 2px 0.5em 2px 0.5em;
606}
607
608#lib-table table
609{
610  width: 100%;
611  border-collapse: collapse;
612}
613
614#lib-table thead, #lib-table tbody
615{
616  border-bottom: 1px solid #A0A0A0;
617}
618
619#lib-table th, #lib-table td
620{
621  text-align: left;
622  padding: 2px 0.5em 2px 0.5em;
623  border-left: 1px solid #A0A0A0;
624}
625
626#lib-table thead
627{
628  background-color: #F0F0F0;
629}
630
631#lib-table tbody#lib-table-rows tr
632{
633  border-bottom: 1px dotted #A0A0A0;
634}
635
636#lib-table tbody#lib-table-rows tr.excluded
637{
638    font-style: italic;
639    color: #666666;
640}
641
642#lib-table .check
643{
644  width: 25px;
645  text-align: center;
646  border-left: 0;
647}
648
649#lib-table .name
650{
651  width: 12em;
652}
653
654#lib-table .barcode
655{
656  width: 6em;
657}
658
659#lib-table .plate
660{
661  width: 12em;
662}
663
664#lib-table .remain
665{
666  width: 4em;
667  text-align: center;
668}
669
670
671#lib-table .molarity
672{
673  width: 4em;
674  text-align: center;
675}
676
677#lib-table .volume
678{
679  width: 4em;
680  text-align: center;
681}
682
683#lib-table .eb
684{
685  width: 4em;
686  text-align: center;
687}
688
689td.volume, span.volume
690{
691  color: #C80000;
692}
693
694td.eb, span.eb
695{
696  color: #0000C8;
697}
698
699#lib-table td.remarks
700{
701  font-style: italic;
702  background-position: 2px 50%;
703  background-repeat: no-repeat;
704}
705
706#lib-table .warning .remarks
707{
708  background-image: url('../images/warning.png');
709  padding-left: 25px;
710 
711}
712
713#lib-table .lib-error .remarks
714{
715  background-image: url('../images/error.png');
716  padding-left: 25px;
717  color: #C80000;
718 
719}
720
721
722#lib-table-pool-summary td
723{
724  font-weight: bold;
725}
726</style>
727</base:head>
728<base:body onload="init()">
729
730  <p:path><p:pathelement 
731    title="Reggie" href="<%="../index.jsp?ID="+ID%>" 
732    /><p:pathelement title="Create manual pool" 
733    /></p:path>
734
735  <div class="content" id="content">
736  <%
737  if (sc.getActiveProjectId() == 0)
738  {
739    %>
740    <div class="messagecontainer note" style="width: 950px; margin-left: 20px; margin-bottom: 20px; margin-right: 0px; font-weight: bold; color: #cc0000;">
741      No project has been selected. You may proceed with the registration but
742      created items will not be shared.
743    </div>
744    <%
745  }
746  %>
747
748  <form name="reggie" onsubmit="return false;">
749  <input type="hidden" name="poolName" value="">
750 
751  <div id="step.1.section">
752  <table class="stepform">
753  <tr>
754    <td rowspan="3" class="stepno">1</td>
755    <td class="steptitle">Select pool options and libraries</td>
756  </tr>
757  <tr>
758    <td class="stepfields">
759      <table class="bottomborder" >
760      <tr valign="top">
761        <td class="prompt">Target molarity</td>
762        <td class="input">
763          <span id="target_molarity"></span>
764        </td>
765        <td class="status"></td>
766        <td class="help"></td>
767      </tr>
768      <tr valign="top">
769        <td class="prompt">Average volume / lib</td>
770        <td class="input">
771          <input type="text" class="text" name="target_volume" 
772            value="5" style="width: 4em;"
773            onblur="targetVolumeOnChange()"
774            onkeypress="doOnEnter(event, targetVolumeOnChange); return Numbers.numberOnly(event)"> µl (2--10)
775        </td>
776        <td class="status" id="target_volume.status"></td>
777        <td class="help" rowspan="2"><span id="target_volume.message" class="message" style="display: none;"></span>
778          Select a target volume when mixing each lib to 2nM before pooling.
779          Use the <b>Dynamic</b> strategy to prioritize final pool molarity by mixing
780          different volume for each library. Use the <b>Fixed</b> strategy to mix all
781          libraries to the given volume.
782        </td>
783      </tr>
784      <tr valign="top">
785        <td class="prompt">Mixing strategy</td>
786        <td class="input">
787          <label><input type="radio" name="mixing_strategy" value="dynamic" checked
788            onclick="mixingStrategyOnChange()"
789            >Dynamic</label>
790          <label><input type="radio" name="mixing_strategy" value="fixed"
791            onclick="mixingStrategyOnChange()"
792            >Fixed</label>
793        </td>
794        <td class="status" id="mixing_strategy.status"></td>
795      </tr>
796      </table>
797     
798      <tbl:toolbar subclass="bottomborder">
799        <tbl:button 
800          title="Select libraries&hellip;" 
801          image="<%=home+"/images/new.png"%>" 
802          onclick="selectLibraries()" 
803          tooltip="Select libraries to include in the pool"
804        />
805        <tbl:button 
806          title="Remove" 
807          image="<%=home+"/images/delete.png"%>" 
808          onclick="removeSelected()" 
809          tooltip="Remove the selected libraries from the pool"
810        />
811        <tbl:button 
812          title="Comments&hellip;" 
813          image="<%=home+"/images/comment.png"%>" 
814          onclick="commentChecked()" 
815          tooltip="Add a comment to the selected libraries" 
816        />
817      </tbl:toolbar>
818     
819      <div id="pool-table" class="bottomborder">
820      <table style="width: 100%;">
821      <tr>
822        <th id="pool-name" style="width: 25%;"></th>
823        <td style="border-left: 1px solid #A0A0A0;" rowspan="2"><textarea name="poolComments" style="width: 95%; height: 3.5em;"></textarea></td>
824      </tr>
825      <tr>
826        <td style="width: 25%;" id="pool-summary">0 libs • 0.00nM • 0.0µl</td>
827      </tr>
828      </table>
829      </div>
830     
831      <div id="lib-table" style="display: none;">
832      <table class="bottomborder">
833      <thead>
834        <tr>
835          <th class="check"></th>
836          <th class="name"></th>
837          <th class="barcode"></th>
838          <th class="plate"></th>
839          <th class="molarity">Remain</th>
840          <th class="molarity">DNA</th>
841          <th class="volume">Volume</th>
842          <th class="eb">EB</th>
843          <th class="remarks"></th>
844        </tr>
845        <tr>
846          <th class="check"><base:icon image="check_uncheck.png" tooltip="Check/uncheck all" onclick="checkAll()" /></th>
847          <th class="name">Library</th>
848          <th class="barcode">Barcode</th>
849          <th class="plate">Work plate</th>
850          <th class="molarity">(µl)</th>
851          <th class="molarity">(nM)</th>
852          <th class="volume">(µl)</th>
853          <th class="eb">(µl)</th>
854          <th class="remarks">Remarks</th>
855        </tr>
856      </thead>
857      <tbody id="lib-table-rows"></tbody>
858      <tbody style="border-bottom: 0;">
859        <tr id="lib-table-pool-summary">
860          <td colspan="7" style="text-align: right; border-left: 0;">EB volume to add</td>
861          <td class="eb" id="pool.eb"></td>
862          <td class="remarks" id="pool.remarks"></td>
863        </tr>
864      </tbody>
865      </table>
866      <div style="margin: 1em; font-style: italic;">
867      * Low quantity = The remaining quantity of this library too low to mix to target molarity for the pool.
868      </div>
869      </div>
870     
871      <div id="not-selected" class="messagecontainer note">No libraries have been selected</div>
872    </td>
873  </tr>
874  </table>
875  </div>
876 
877  <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>
878 
879  <div class="messagecontainer error" id="errorMessage" style="display: none; width: 950px; margin-left: 20px; margin-bottom: 0px;"></div>
880 
881  <div id="done" class="success" style="display: none; width: 950px; margin-left: 20px; margin-top: 20px;"></div>
882 
883  <table style="margin-left: 20px; margin-top: 10px; margin-bottom: 3em;" class="navigation">
884    <tr>
885      <td><base:button id="gocancel" title="Cancel" onclick="goRestart(false)" /></td>
886      <td><base:button id="gonext" title="Next" image="<%=home+"/images/gonext.png"%>" onclick="goNext(true)" style="display: none;" /></td>
887      <td><base:button id="gocreate" title="Create" image="<%=home+"/images/gonext.png"%>" onclick="goCreate()" /></td>
888      <td><base:button id="gorestart" title="Restart" image="<%=home+"/images/goback.png"%>" onclick="goRestart(true)" style="display: none;"/></td>
889      <td id="gonext.message" class="message"></td>
890    </tr>
891  </table>
892 
893 
894  </form>
895  </div>
896 
897</base:body>
898</base:page>
899<%
900}
901finally
902{
903  if (dc != null) dc.close();
904}
905%>
Note: See TracBrowser for help on using the repository browser.