source: extensions/net.sf.basedb.reggie/branches/ticket-422/resources/libprep/select_rna.jsp @ 1760

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

References #424: Select RNA items for library preparation

Implemented a simple auto-selection feature that find:

  • RNA items with no child mRNA
  • A non-empty creation date
  • Remaining quantity >= 1.1µg
  • Not manually included on the mRNA plate
  • Sorted by RNA plate and location: plate, row, column

The user designing the plate need to account for replicates/stratagene by leaving room on each pool and then using copy/paste to duplicate some RNA. The user must also manually assign items for QC.

File size: 34.9 KB
Line 
1<%@ page
2  pageEncoding="UTF-8"
3  session="false"
4  import="net.sf.basedb.core.Application"
5  import="net.sf.basedb.core.User"
6  import="net.sf.basedb.core.DbControl"
7  import="net.sf.basedb.core.SessionControl"
8  import="net.sf.basedb.clients.web.Base"
9  import="net.sf.basedb.clients.web.util.HTML"
10  import="net.sf.basedb.clients.web.extensions.ExtensionsControl"
11  import="net.sf.basedb.util.Values"
12  import="net.sf.basedb.util.formatter.WellCoordinateFormatter"
13%>
14<%@ taglib prefix="base" uri="/WEB-INF/base.tld" %>
15<%@ taglib prefix="p" uri="/WEB-INF/path.tld" %>
16<%@ taglib prefix="tbl" uri="/WEB-INF/table.tld" %>
17<%
18final SessionControl sc = Base.getExistingSessionControl(request, true);
19final String ID = sc.getId();
20final float scale = Base.getScale(sc);
21final String home = ExtensionsControl.getHomeUrl("net.sf.basedb.reggie");
22DbControl dc = null;
23try
24{
25  dc = sc.newDbControl();
26  final User user = User.getById(dc, sc.getLoggedInUserId());
27%>
28<base:page type="default" >
29<base:head scripts="ajax.js,js-draw.js" styles="path.css,toolbar.css">
30  <link rel="stylesheet" type="text/css" href="../css/reggie.css">
31  <link rel="stylesheet" type="text/css" href="../css/plate.css">
32  <script language="JavaScript" src="../reggie.js" type="text/javascript" charset="UTF-8"></script>
33
34<script language="JavaScript">
35var debug = 1;
36
37var QUANTITY_REGULAR = 1.1;
38var QUANTITY_QC = 1.22;
39
40var Plate = function()
41{
42  var plate = {};
43  plate.rows = 8;
44  plate.columns = 12;
45  plate.wells = [];
46 
47  plate.init = function()
48  {
49    for (var c = 0; c < plate.columns; c++)
50    {
51      for (var r = 0; r < plate.rows; r++)
52      {
53        plate.wells[plate.wells.length] = new Well(r, c);
54      }
55    }
56  }
57 
58  /**
59    Get all wells on the plate.
60  */
61  plate.getWells = function()
62  {
63    return plate.wells;
64  }
65 
66  /**
67    Get all wells in the given row. First row is 0.
68  */
69  plate.getRow = function(row)
70  {
71    var result = [];
72    for (var i = row; result.length < plate.columns; i += plate.rows)
73    {
74      result[result.length] = plate.wells[i];
75    }
76    return result;
77  }
78 
79  /**
80    Get all wells in the given column. First column is 0.
81  */
82  plate.getColumn = function(column)
83  {
84    var result = [];
85    for (var i = column*plate.rows; result.length < plate.rows; i++)
86    {
87      result[result.length] = plate.wells[i];
88    }
89    return result;
90  }
91
92  /**
93    Get all wells in the given pool number. First pool is 0.
94  */
95  plate.getPool = function(pool)
96  {
97    var result = [];
98    for (var i = pool*2*plate.rows; result.length < plate.rows*2; i++)
99    {
100      result[result.length] = plate.wells[i];
101    }
102    return result;
103  }
104
105  /**
106    Get the well at the given coordinate.
107  */
108  plate.getWell = function(row, column)
109  {
110    return plate.wells[row + column * plate.rows];
111  }
112 
113  /**
114    Get all wells that contains RNA with a given name.
115  */
116  plate.getWellsByName = function(name)
117  {
118    var result = [];
119    for (var i = 0; i < plate.wells.length; i++)
120    {
121      var well = plate.wells[i];
122      if (well.rna && well.rna.name == name)
123      {
124        result[result.length] = plate.wells[i];
125      }
126    }
127    return result;
128  }
129 
130  /**
131    Get all wells that are selected.
132  */
133  plate.getSelected = function()
134  {
135    var selected = [];
136    for (var i = 0; i < plate.wells.length; i++)
137    {
138      var well = plate.wells[i];
139      if (well.selected)
140      {
141        selected[selected.length] = well;
142      }
143    }
144    return selected;
145  }
146
147  /**
148    Set the selected status for all wells in the array.
149    The wells are automatically repainted.
150  */
151  plate.setSelected = function(wells, select)
152  {
153    for (var i = 0; i < wells.length; i++)
154    {
155      var well = wells[i];
156      well.selected = select;
157      well.paint();
158    }
159  }
160 
161  /**
162    Toggle the selected status for all wells in the array.
163    The next status is determined by the current status of 
164    the first well in the array.
165  */
166  plate.toggleSelected = function(wells)
167  {
168    if (wells.length == 0) return;
169    plate.setSelected(wells, !wells[0].selected);
170  }
171 
172  /**
173    Enable or disable highlight of the given wells.
174  */
175  plate.setHighlight = function(wells, highlightClass, on)
176  {
177    var tmpClass = on ? highlightClass : null;
178    for (var i = 0; i < wells.length; i++)
179    {
180      var well = wells[i];
181      well.highlightClass = tmpClass;
182      Main.addOrRemoveClass(well.tag, highlightClass, on);
183    }
184  }
185 
186  /**
187    Paint the given wells.
188  */
189  plate.paint = function(wells)
190  {
191    for (var i = 0; i < wells.length; i++)
192    {
193      wells[i].paint();
194    }
195  }
196 
197  /**
198    Check if the plate have any replicated RNA. Eg. RNA that is found
199    in more than one well. If a name is given, only RNA for that name
200    is checked, otherwise the complete plate is checked.
201  */
202  plate.checkReplicates = function(name, noRepaint)
203  {
204    if (name)
205    {
206      // If a name has been given, it is relatively easy
207      var wells = plate.getWellsByName(name);
208      var isReplicate = wells.length > 1;
209      for (var i = 0; i < wells.length; i++)
210      {
211        var well = wells[i];
212        if (well.rna.replicate != isReplicate)
213        {
214          well.rna.replicate = isReplicate;
215          if (!noRepaint) well.paint();
216        }
217      }
218    }
219    else
220    {
221      // No name, we begin by counting the number of times we find any given name
222      var nameCount = [];
223      for (var i = 0; i < plate.wells.length; i++)
224      {
225        var well = plate.wells[i];
226        // Ignore empty wells and wells with 'Stratagene'
227        if (well.rna && !well.rna.stratagene)
228        {
229          nameCount[well.rna.name] = 1 + (nameCount[well.rna.name] || 0);
230        }
231      }
232      // Then, we update the status for all wells 
233      for (var i = 0; i < plate.wells.length; i++)
234      {
235        var well = plate.wells[i];
236        if (well.rna)
237        {
238          var isReplicate = nameCount[well.rna.name] > 1;
239          if (well.rna.replicate != isReplicate)
240          {
241            well.rna.replicate = isReplicate;
242            if (!noRepaint) well.paint();
243          }
244        }
245      }
246    }
247  }
248 
249  plate.findNextMRnaPlateName = function()
250  {
251    var request = Ajax.getXmlHttpRequest();
252    var url = '../MRna.servlet?ID=<%=ID%>&cmd=GetNextAutoGeneratedPlateName&bioPlateType=MRNA'; 
253    if (debug) Main.debug(url);
254    request.open("GET", url, false); 
255    request.send(null);
256
257    if (debug) Main.debug(request.responseText);
258    var response = JSON.parse(request.responseText); 
259    if (response.status != 'ok')
260    {
261      setFatalError(response.message);
262      return false;
263    }
264    plate.name = response.name;
265    return plate.name;
266  }
267 
268  return plate;
269}();
270
271
272var Rna = function()
273{
274  var rna = {};
275  var info = [];
276 
277  /**
278    Create a new RNA object by name. More information
279    about the RNA is automatically loaded from the database.
280  */
281  rna.createByName = function(name)
282  {
283    var tmp = {};
284    tmp.name = name;
285    tmp.stratagene = name == 'Stratagene';
286    tmp.replicate = false;
287    tmp.info = rna.infoByName(name);
288    tmp.id = tmp.info.id;
289    return tmp;
290  }
291 
292  /**
293    Create a new RNA object by info object.
294  */
295  rna.createByInfo = function(info)
296  {
297    var tmp = {};
298    tmp.name = info.name;
299    tmp.stratagene = tmp.name == 'Stratagene';
300    tmp.replicate = false;
301    tmp.id = info.id;
302    tmp.info = info;
303    return tmp;
304  }
305 
306  /**
307    Get information about a RNA item with a given name.
308  */
309  rna.infoByName = function(name)
310  {
311    var key = 'N'+name;
312    if (!info[key])
313    {
314      rna.loadInfoByNames([name]);
315      if (!info[key]) info[key] = {};
316    }
317    return info[key];
318  }
319
320  /**
321    Load and cache RNA information for all RNA items with a name in the
322    given list.
323  */
324  rna.loadInfoByNames = function(names)
325  {
326    var submitInfo = {};
327    submitInfo.names = names;
328    if (debug) Main.debug(JSON.stringify(submitInfo));
329
330    var request = Ajax.getXmlHttpRequest();
331    var url = '../MRna.servlet?ID=<%=ID%>&cmd=GetRnaInfoFromNames'; 
332    request.open("POST", url, false);
333    request.setRequestHeader("Content-Type", "application/json");
334    request.send(JSON.stringify(submitInfo));
335
336    if (debug) Main.debug(request.responseText);
337    var response = JSON.parse(request.responseText); 
338    if (response.status != 'ok')
339    {
340      setFatalError(response.message);
341      return false;
342    }
343   
344    rna.cacheInfo(response.rna);
345  }
346 
347  rna.cacheInfo = function(rnaList)
348  {
349    for (var i = 0; i < rnaList.length; i++)
350    {
351      var rna = rnaList[i];
352      info['N'+rna.name] = rna;
353      info['I'+rna.id] = rna;
354    }
355  }
356
357  return rna;
358}();
359
360// Represents a well on the plate
361// Each well is created when the page is loaded
362function Well(row, column)
363{
364  this.row = row;
365  this.column = column;
366  this.selected = false;
367  this.highlighClass = null;
368  this.rna = null;
369  this.duplicates = null;
370  this.tag = document.getElementById('well.'+row+'.'+column);
371}
372
373/**
374  Set the RNA item that is put into this well. Use
375  'null' to clear the well.
376*/
377Well.prototype.setRna = function(rna)
378{
379  this.rna = rna;
380  this.duplicates = null;
381  if (rna && this.clipboard) this.doneWithCopy();
382}
383
384/**
385  Set a duplicate RNA item in this well. This can
386  happen when using a file import if the same location
387  is specified twice and is an error condition which
388  must be resolved.
389*/
390Well.prototype.addDuplicate = function(rna)
391{
392  if (!this.duplicates)
393  {
394    this.duplicates = [];
395    this.duplicates[0] = this.rna.name;
396  }
397  this.duplicates[this.duplicates.length] = rna.name;
398}
399
400Well.prototype.makeCopy = function()
401{
402  var cp = {};
403  cp.well = this;
404  cp.name = this.rna ? this.rna.name : null;
405  this.clipboard = true;
406  this.copyText = cp.name;
407  return cp;
408}
409
410Well.prototype.doneWithCopy = function()
411{
412  this.clipboard = false;
413  this.copyText = null;
414}
415
416Well.prototype.hasError = function()
417{
418  return this.duplicates || (this.rna && !this.rna.id);
419}
420
421Well.prototype.getClassName = function()
422{
423  var c = this.column;
424  var cls = 'well col-'+c;
425  cls += (c >= 2 && c <= 9) ? ' primary' : ' secondary';
426  cls += c % 2 == 0 ? ' pool-left' : ' pool-right';
427  if (this.selected) cls += ' selected';
428  if (this.clipboard) cls += ' clipboard';
429  if (this.rna)
430  {
431    if (this.rna.replicate) cls += ' replicate';
432    if (this.rna.qc) cls += ' qc';
433  }
434  if (this.hasError()) cls += ' err';
435  if (this.warning) cls += ' warning';
436  if (this.highlightClass) cls += ' ' + this.highlightClass;
437  return cls;
438}
439
440Well.prototype.getText = function()
441{
442  var text = '';
443  if (this.duplicates)
444  {
445    text = '<div class="name">'+this.duplicates.join(', ')+'</div>';
446    text += '<div class="err-msg">Duplicate RNA in this location</div>';
447  }
448  else if (this.rna)
449  {
450    text = '<div class="name">'+this.rna.name+'</div>';
451    var info = this.rna.info;
452    var warningMsg = null;
453    if (info && info.id && !this.rna.stratagene)
454    {
455      var quantity = 10000 * (this.rna.qc ? QUANTITY_QC : QUANTITY_REGULAR);
456      var use = Math.ceil(quantity/info.NDConc);
457      var water = Math.round(500-use);
458      if (info.bioWell)
459      {
460        var well = info.bioWell;
461        text += '<div class="location">'+well.bioPlate.name+'['+WELL_ALPHA[well.row]+(well.column+1)+']</div>';
462      }
463      else
464      {
465        if (!warningMsg) warningMsg = 'No location';
466      }
467      if (info.remainingQuantity)
468      {
469        text += '<div class="quantity">'+Numbers.formatNumber(info.remainingQuantity, 2, 'µg')+'</div>';
470        if (info.remainingQuantity < (this.rna.qc ? QUANTITY_QC : QUANTITY_REGULAR))
471        {
472          if (!warningMsg) warningMsg = 'Low quantity';
473        }
474      }
475      else
476      {
477        if (!warningMsg) warningMsg = 'No quantity';
478      }
479      if (info.NDConc)
480      {
481        text += '<div class="ndconc">'+Numbers.formatNumber(info.NDConc, 2, 'ng/µl') + '</div>';
482        text += '<div class="volumes"><span class="volume">'+Numbers.formatNumber(use/10, 1)+'</span> + <span class="water">'+Numbers.formatNumber(water/10, 1)+'µl</span></div>';
483      }
484      else
485      {
486        if (!warningMsg) warningMsg = 'No NDConc value';
487      }
488      if (warningMsg)
489      {
490        this.warning = true;
491        text += '<div class="warn-msg">'+ warningMsg + '</div>';
492      }
493    }
494    else if (!this.rna.id)
495    {
496      text += '<div class="err-msg">RNA not found</div>'
497    }
498  }
499  else if (this.copyText)
500  {
501    text = '<div class="copy-text">'+this.copyText+'</div>';
502  }
503  return text;
504}
505
506Well.prototype.getTooltip = function()
507{
508  var tooltip = 'Select/deselect this well';
509  return tooltip;
510}
511
512Well.prototype.paint = function()
513{
514  this.warning = false;
515  this.tag.innerHTML = this.getText();
516  this.tag.className = this.getClassName();
517  this.tag.title = this.getTooltip();
518}
519
520var graphics;
521var pen;
522
523function init()
524{
525  Plate.init();
526  Plate.paint(Plate.getWells());
527 
528  graphics = new jsGraphics(document.getElementById('canvas'));
529  pen = new jsPen(new jsColor('#2288AA'), 2);
530 
531  var plateName = Plate.findNextMRnaPlateName();
532  setInnerHTML('plateName', plateName);
533}
534
535
536/**
537  Parse a tab-separated data file. The columns must be in the following order:
538  0: RNA name
539  1: Row letter (A-H)
540  2: Column number (1-12)
541  3: QC flag (can be empty)
542*/
543function parseRnaFile(data)
544{
545  var lines = data.split(/[\n\r]+/);
546
547  // Load information about all RNA items in a batch (will improve performance)
548  var names = [];
549  for (var i = 0; i < lines.length; i++)
550  {
551    var line = lines[i];
552    if (line)
553    {
554      var cols = lines[i].split(/\t/);
555      if (cols.length < 3) throw 'On line '+(i+1)+': Too few columns (' + cols.length + ')';
556      names[names.length] = cols[0];
557    }
558  }
559  Rna.loadInfoByNames(names);
560 
561  // Place RNA on the plate
562  var duplicates = [];
563  for (var i = 0; i < lines.length; i++)
564  {
565    var line = lines[i];
566    if (line)
567    {
568      var cols = lines[i].split(/\t/);
569
570      var rna = Rna.createByName(cols[0]);
571      var row =  WELL_ALPHA.indexOf(cols[1].toUpperCase());
572      var col =  parseInt(cols[2], 10)-1;
573     
574      var well = Plate.getWell(row, col);
575      if (!well) throw 'On line '+(i+1)+': Invalid plate coordinate ['+cols[1]+','+cols[2]+']';
576
577      rna.qc = cols.length >= 4 && cols[3];
578     
579      // Check for duplicate RNA on same position (which is an error)
580      var pos = 'c'+col+'r'+row;
581      if (duplicates[pos])
582      {
583        well.addDuplicate(rna);
584      }
585      else
586      {
587        duplicates[pos] = rna.name;
588        well.setRna(rna);
589      }
590    }
591  }
592 
593  // Check for replicates on the whole plate and repaint it
594  Plate.checkReplicates(null, true);
595  Plate.paint(Plate.getWells());
596}
597
598/**
599  Add 'Stratagene' to the selected wells.
600*/
601function setToStratagene()
602{
603  var wells = Plate.getSelected();
604 
605  if (wells.length == 0)
606  {
607    alert('No wells have been selected');
608    return;
609  }
610 
611  // Count non-empty wells
612  var count = 0;
613  for (var i = 0; i < wells.length; i++)
614  {
615    var well = wells[i];
616    if (well.rna && !well.hasError()) count++;
617  }
618 
619  if (count > 0)
620  {
621    if (!confirm('Replace RNA in ' + count + ' wells with Stratagene?'))
622    {
623      return;
624    }
625  }
626 
627  var info = Rna.infoByName('Stratagene');
628  if (!info.id)
629  {
630    alert('Could not find any RNA with name=Stratagene. Please check that it exists on the server.');
631    return;
632  }
633 
634  for (var i = 0; i < wells.length; i++)
635  {
636    var well = wells[i];
637    var rna = Rna.createByInfo(info);
638    rna.qc = true;
639    well.setRna(rna);
640    well.selected = false;
641    well.paint();
642  }
643 
644  // Check for replicated RNA if some have been replaced with Stratagene
645  if (count > 0) Plate.checkReplicates();
646}
647
648/**
649  Toggle the QC flag for the selected wells. The first non-empty
650  well is toggled and the rest of the wells will use the same new QC
651  value.
652*/
653function toggleQc()
654{
655  var wells = Plate.getSelected();
656
657  if (wells.length == 0)
658  {
659    alert('No wells have been selected');
660    return;
661  }
662 
663  var gotQc = false;
664  var newQc;
665  var count = 0;
666  for (var i = 0; i < wells.length; i++)
667  {
668    var well = wells[i];
669    if (well.rna)
670    {
671      // Toggle QC flag for the first well with RNA, then use the same flag for the rest
672      if (!gotQc)
673      {
674        gotQc = true;
675        newQc = !well.rna.qc;
676      }
677      well.rna.qc = newQc;
678      well.paint();
679      count++;
680    }
681  }
682
683  if (count == 0)
684  {
685    alert('None of the selected wells contain any RNA');
686  }
687}
688
689/**
690  Empty the selected wells from RNA. They can later be pasted again.
691*/
692function cutSelected()
693{
694  var wells = Plate.getSelected();
695 
696  if (wells.length == 0)
697  {
698    alert('No wells have been selected');
699    return;
700  }
701 
702  var count = 0;
703  var valid = 0;
704  for (var i = 0; i < wells.length; i++)
705  {
706    var well = wells[i];
707    if (well.rna) 
708    {
709      count++;
710      if (!well.hasError()) valid++;
711    }
712  }
713 
714  if (count == 0)
715  {
716    alert('None of the selected wells contain any RNA');
717    return;
718  }
719 
720  // Ask for confirmation before deleting from valid wells
721  if (valid > 0)
722  {
723    if (!confirm('Clear RNA from ' + count + ' of ' + wells.length + ' selected wells?'))
724    {
725      return;
726    }
727  }
728
729  copySelected();
730  for (var i = 0; i < wells.length; i++)
731  {
732    var well = wells[i];
733    well.setRna(null);
734    well.selected = false;
735    well.paint();
736  }
737  Plate.checkReplicates();
738}
739
740var copy;
741/**
742  Copy information about the selected wells. 
743*/
744function copySelected()
745{
746  // Clear existing wells in the copy
747  if (copy && copy.length > 0)
748  {
749    for (var i = 0; i < copy.length; i++)
750    {
751      var cp = copy[i];
752      cp.well.doneWithCopy();
753      cp.well.paint();
754    }
755  }
756 
757  // Place selected wells in the copy
758  var wells = Plate.getSelected();
759  copy = [];
760  for (var i = 0; i < wells.length; i++)
761  {
762    var well = wells[i];
763    copy[copy.length] = well.makeCopy();
764    well.selected = false;
765    well.paint();
766  }
767}
768
769/**
770  Paste information into the selected wells.
771*/
772function pasteToSelected()
773{
774  if (!copy || copy.length == 0) 
775  {
776    alert('Nothing to paste. Please cut or copy wells first.');
777    return;
778  }
779 
780  var wells = Plate.getSelected();
781  // Count non-empty and valid wells
782  var count = 0;
783  for (var i = 0; i < wells.length; i++)
784  {
785    var well = wells[i];
786    if (well.rna && !well.hasError()) count++;
787  }
788 
789  if (count > 0)
790  {
791    if (!confirm('Replace RNA in ' + count + ' wells with copy?'))
792    {
793      return;
794    }
795  }
796 
797  var wi = 0;
798  var ci = 0;
799  var copyEmpty;
800  var askIfEmpty = true;
801 
802  while (wi < wells.length && ci < copy.length)
803  {
804    var well = wells[wi];
805    var cp = copy[ci];
806    var rna = null;
807    cp.well.doneWithCopy();
808    cp.well.paint();
809    if (cp.name)
810    {
811      rna = Rna.createByName(cp.name);
812    }
813    else
814    {
815      // The copy is from an empty well
816      if (askIfEmpty)
817      {
818        askIfEmpty = false;
819        copyEmpty = confirm('Do you want to copy empty wells? If not, only non-empty well are copied.');
820      }
821    }
822    if (rna != null || copyEmpty)
823    {
824      well.setRna(rna);
825      well.selected = false;
826      well.paint();
827      wi++;
828    }
829    ci++;
830  }
831  copy.splice(0, ci);
832  Plate.checkReplicates();
833}
834
835
836/**
837  Open a popup dialog for selecting a data files.
838*/
839function selectFile()
840{
841  Main.openPopup('select_file.jsp?ID=<%=ID%>', 'SelectFile', 600, 400); 
842}
843
844
845/**
846  Let the wizard automatically select among unprocessed RNA items.
847*/
848function autoSelect()
849{
850
851  var wells = Plate.getWells();
852  var ignore = [];
853  var selected = 0;
854  var notEmpty = 0;
855 
856  // Count selected and non-empty wells and keep track of RNA that is already present
857  for (var i = 0; i < wells.length; i++)
858  {
859    var well = wells[i];
860    if (well.selected) 
861    {
862      selected++;
863      if (well.rna && !well.hasError()) notEmpty++;
864    }
865    if (well.rna && well.rna.id)
866    {
867      ignore[ignore.length] = well.rna.id;
868    }
869  }
870 
871  if (selected == 0)
872  {
873    alert('Please select one or more wells were RNA should be placed.');
874    return;
875  }
876 
877  if (notEmpty > 0)
878  {
879    if (!confirm('Replace RNA in ' + notEmpty + ' wells?'))
880    {
881      return;
882    }
883  }
884
885  var request = Ajax.getXmlHttpRequest();
886  var url = '../MRna.servlet?ID=<%=ID%>&cmd=AutoSelectRnaForMRna&numToSelect='+currentSelected;
887  url += '&ignore='+ignore.join(',');
888  request.open("GET", url, false);
889  request.send(null);
890
891  if (debug) Main.debug(request.responseText);
892  var response = JSON.parse(request.responseText); 
893  if (response.status != 'ok')
894  {
895    setFatalError(response.message);
896    return false;
897  }
898 
899  // Cache RNA information
900  Rna.cacheInfo(response.rna);
901 
902  if (response.rna.length == 0)
903  {
904    alert('Could not find any unprocessed RNA at this time.');
905  }
906 
907  for (var i = 0; i < response.rna.length; i++)
908  {
909    if (i < selected.length)
910    {
911      var well = selected[i];
912      // Create a new RNA object
913      var rna = Rna.createByName(response.rna[i].name);
914      well.setRna(rna);
915      well.selected = false;
916    }
917  }
918 
919  // Check for replicates on the whole plate and repaint it
920  Plate.checkReplicates(null, true);
921  Plate.paint(Plate.getWells());
922}
923
924
925var currentSelected;
926var currentIndex = 0;
927var subtypeRna = null;
928
929/**
930  Open a popup dialog for manual selection of RNA.
931 */
932function manualSelect()
933{
934  currentSelected = Plate.getSelected();
935  currentIndex = 0;
936 
937  if (currentSelected.length == 0)
938  {
939    alert('Please select one or more wells were RNA should be placed.');
940    return;
941  }
942 
943  if (subtypeRna == null)
944  {
945    var request = Ajax.getXmlHttpRequest();
946    var url = '../Subtype.servlet?ID=<%=ID%>&cmd=GetSubtypeInfo&name=RNA';
947    request.open("GET", url, false); 
948    request.send(null);
949
950    if (debug) Main.debug(request.responseText);
951    var response = JSON.parse(request.responseText); 
952    if (response.status != 'ok')
953    {
954      setFatalError(response.message);
955      return false;
956    }
957    subtypeRna = response.subtype;
958  }
959
960  var url = getRoot() + 'biomaterials/extracts/index.jsp?ID=<%=ID%>';
961  url += '&cmd=UpdateContext&mode=selectmultiple&callback=setRnaCallback&resetTemporary=1';
962  url += '&tmpfilter:INT:itemSubtype='+subtypeRna.id;
963  url += '&tmpfilter:DATE:creationEvent.eventDate='+encodeURIComponent('<>');
964  url += '&tmpfilter:FLOAT:remainingQuantity='+encodeURIComponent('>=1');
965  Main.openPopup(url, 'SelectRNA', 1000, 700);
966}
967
968/**
969  Callback method for manual selection.
970*/
971function setRnaCallback(id, name)
972{
973  if (currentIndex >= currentSelected.length)
974  {
975    return;
976  }
977  var well = currentSelected[currentIndex];
978 
979  // Keep a reference to the old rna in the well
980  var oldRna = well.rna;
981
982  // Create a new RNA object
983  var rna = Rna.createByName(name);
984  well.setRna(rna);
985  well.selected = false;
986  well.paint();
987 
988  // Update replicate information
989  Plate.checkReplicates(name);
990  if (oldRna) Plate.checkReplicates(oldRna.name);
991 
992  // Move to the next item
993  currentIndex++;
994}
995
996// Toggle the selected status of a single well
997function toggleWell(row, column)
998{
999  var well = Plate.getWell(row, column);
1000  Plate.toggleSelected([well]);
1001}
1002
1003// Toggle the selected status of a complete row
1004function toggleRow(row)
1005{
1006  Plate.toggleSelected(Plate.getRow(row));
1007}
1008
1009// Toggle the selected status of a complete column
1010function toggleColumn(column)
1011{
1012  Plate.toggleSelected(Plate.getColumn(column));
1013}
1014
1015// Toggle the selected status of all wells
1016function toggleAll()
1017{
1018  Plate.toggleSelected(Plate.getWells());
1019}
1020
1021// Toggle the selected status of a complete pool (=two columns)
1022function togglePool(pool)
1023{
1024  Plate.toggleSelected(Plate.getPool(pool));
1025}
1026
1027// Highlight enable/disable all wells in a column
1028function highlightColumn(column, on)
1029{
1030  Main.addOrRemoveClass(document.getElementById('col.'+column), 'highlight-column', on);
1031  var wells = Plate.getColumn(column);
1032  Plate.setHighlight(wells, 'highlight-column', on);
1033}
1034
1035// Highlight enable/disable all wells in a row
1036function highlightRow(row, on)
1037{
1038  Main.addOrRemoveClass(document.getElementById('row.'+row), 'highlight-row', on);
1039  var wells = Plate.getRow(row);
1040  Plate.setHighlight(wells, 'highlight-row', on);
1041}
1042
1043// Highlight enable/disable all wells in a pool
1044function highlightPool(pool, on)
1045{
1046  Main.addOrRemoveClass(document.getElementById('pool.'+pool), 'highlight-pool', on);
1047  var wells = Plate.getPool(pool);
1048  Plate.setHighlight(wells, 'highlight-pool', on);
1049}
1050
1051/**
1052  Highlight all replicated wells with the same RNA as the given well.
1053*/
1054function highlightReplicated(row, column, on)
1055{
1056  var well = Plate.getWell(row, column);
1057  if (well.rna && well.rna.replicate)
1058  {
1059    // Get center coordinates for the current well
1060    var pos = Main.getElementPosition(well.tag);
1061    var jsPos = new jsPoint(pos.left+pos.width/2, pos.top+pos.height/2);
1062
1063    var replicated = Plate.getWellsByName(well.rna.name);
1064    for (var i = 0; i < replicated.length; i++)
1065    {
1066      var rep = replicated[i];
1067      if (rep != well)
1068      {
1069        Main.addOrRemoveClass(rep.tag, 'highlight-replicated', on);
1070        if (rep.line)
1071        {
1072          // Clear any recent lines
1073          graphics.clearDrawing(rep.line);
1074          rep.line = null;
1075        }
1076        if (on)
1077        {
1078          // We draw a line between the current and replicated well
1079          var rPos = Main.getElementPosition(rep.tag);
1080          rep.line = graphics.drawLine(pen, jsPos, new jsPoint(rPos.left+rPos.width/2, rPos.top+rPos.height/2));
1081        }
1082      }
1083    }
1084  }
1085}
1086
1087
1088function goCreate()
1089{
1090  var submitInfo = {};
1091  var plateInfo = {};
1092  submitInfo.bioplate = plateInfo;
1093 
1094  plateInfo.name = Plate.name;
1095  plateInfo.wells = [];
1096
1097  var wells = Plate.getWells();
1098  var numErrors = 0;
1099  var numWarnings = 0;
1100  var numRna = 0;
1101  var numStratagene = 0;
1102  for (var i = 0; i < wells.length; i++)
1103  {
1104    var well = wells[i];
1105    if (well.warning) numWarnings++;
1106    if (well.hasError())
1107    {
1108      numErrors++;
1109    }
1110    else
1111    {
1112      if (well.rna && well.rna.id)
1113      {
1114        var tmp = {};
1115        tmp.row = well.row;
1116        tmp.column = well.column;
1117        tmp.rna = {};
1118        tmp.rna.id = well.rna.id;
1119        tmp.rna.usedQuantity = well.rna.qc ? QUANTITY_QC : QUANTITY_REGULAR;
1120        plateInfo.wells[plateInfo.wells.length] = tmp;
1121        numRna++;
1122        if (well.rna.stratagene) numStratagene++;
1123      }
1124    }
1125  }
1126
1127  if (numErrors > 0)
1128  {
1129    alert('There are ' + numErrors + ' wells with errors. Please fix them before creating the mRNA plate.');
1130    return;
1131  }
1132
1133  if (numRna == 0)
1134  {
1135    alert('There is no RNA in any wells');
1136    return;
1137  }
1138 
1139  if (numWarnings > 0)
1140  {
1141    if (!confirm('There are ' + numWarnings + ' wells with a warning. Continue anyway?')) return;
1142  }
1143 
1144  if (numRna < 64)
1145  {
1146    if (!confirm('Less than 64 wells have RNA in them. Continue anyway?')) return;
1147  }
1148 
1149  if (numRna == numStratagene)
1150  {
1151    if (!confirm('There are only wells with Stratagene on this plate. Continue anyway?')) return;
1152  }
1153 
1154  Main.addClass(document.getElementById('step.1.section'), 'disabled');
1155  Main.hide('gocancel');
1156  Main.hide('gocreate');
1157
1158  if (debug) Main.debug(JSON.stringify(submitInfo));
1159 
1160  var request = Ajax.getXmlHttpRequest();
1161  var url = '../MRna.servlet?ID=<%=ID%>';
1162  url += '&cmd=CreateMRnaPlate';
1163  request.open("POST", url, false);
1164  request.setRequestHeader("Content-Type", "application/json");
1165  request.send(JSON.stringify(submitInfo));
1166
1167  if (debug) Main.debug(request.responseText);
1168
1169  var response = JSON.parse(request.responseText);
1170  if (response.status != 'ok')
1171  {
1172    setFatalError(response.message);
1173    return false;
1174  }
1175
1176  var msg = '<ul>';
1177  for (var i = 0; i < response.messages.length; i++)
1178  {
1179    msg += '<li>' + response.messages[i];
1180  }
1181  msg += '</ul>';
1182  setInnerHTML('done', msg);
1183  Main.show('done');
1184  Main.show('gorestart');
1185}
1186
1187function toggleInfo(what)
1188{
1189  var frm = document.forms['reggie'];
1190  var show = frm[what].checked;
1191  Main.addOrRemoveClass(document.getElementById('plate'), 'hide-'+what, !show);
1192}
1193
1194</script>
1195<style>
1196
1197/* A well assigned for QC include a background icon as indicator */
1198.well.qc
1199{
1200  background-image: url('../images/mrnaqc.png');
1201  background-position: 95% 5%;
1202  background-repeat: no-repeat;
1203}
1204
1205/* A well which contain replicate RNA is also marked with an icon */
1206.well.replicate
1207{
1208  background-image: url('../images/copy.png');
1209  background-position: 95% 5%;
1210  background-repeat: no-repeat;
1211}
1212
1213/* A well that is both a replicate and QC need to re-arrange the icons a bit */
1214.well.qc.replicate
1215{
1216  background-image: url('../images/mrnaqc.png'), url('../images/copy.png');
1217  background-position: 95% 5%, 95% 55%;
1218  background-repeat: no-repeat;
1219}
1220
1221.well .name
1222{
1223  font-weight: bold;
1224}
1225
1226.well .err-msg, .well .warn-msg
1227{
1228  color: #C80000;
1229  font-style: italic;
1230}
1231
1232.well .missing
1233{
1234  font-style: italic;
1235}
1236
1237.plate.hide-location .location
1238{
1239  display: none;
1240}
1241.plate.hide-quantity .quantity
1242{
1243  display: none;
1244}
1245.plate.hide-volumes .volumes
1246{
1247  display: none;
1248}
1249.plate.hide-ndconc .ndconc
1250{
1251  display: none;
1252}
1253
1254.volume
1255{
1256  color: #C80000;
1257}
1258.water
1259{
1260  color: #0000C8;
1261}
1262
1263</style>
1264</base:head>
1265<base:body onload="init()">
1266  <p:path><p:pathelement 
1267    title="Reggie" href="<%="../index.jsp?ID="+ID%>" 
1268    /><p:pathelement title="Create new mRNA plate" 
1269    /></p:path>
1270  <div id="canvas" class="absolutefull" style="z-index: -1;">
1271  <div class="content">
1272  <%
1273  if (sc.getActiveProjectId() == 0)
1274  {
1275    %>
1276    <div class="messagecontainer note" style="width: 950px; margin-left: 20px; margin-bottom: 20px; margin-right: 0px; font-weight: bold; color: #cc0000;">
1277      No project has been selected. You may proceed with the wizard but
1278      created items will not be shared.
1279    </div>
1280    <%
1281  }
1282  %>
1283  <form name="reggie" onsubmit="return false;">
1284 
1285  <table class="stepform" id="step.1.section" style="width: auto;">
1286  <tr>
1287    <td rowspan="3" class="stepno">1</td>
1288    <td class="steptitle">Fragmented mRNA plate</td>
1289  </tr>
1290  <tr>
1291    <td class="stepfields">
1292      <table class="bottomborder" style="width: 100%;">
1293      <tr>
1294        <td class="prompt">Name</td>
1295        <td class="input" id="plateName"></td>
1296        <td class="help">Select RNA items to use for the new mRNA plate.</td>
1297      </tr>
1298      <tr style="vertical-align: top;">
1299        <td class="prompt">Show</td>
1300        <td class="input">
1301          <table>
1302          <tr>
1303            <td>
1304              <input type="checkbox" name="location" id="location" onclick="toggleInfo('location')" checked><label for="location">Bioplate location</label><br>
1305              <input type="checkbox" name="quantity" id="quantity" onclick="toggleInfo('quantity')" checked><label for="quantity">Remaining quantity</label><br>
1306            </td>
1307            <td>
1308              <input type="checkbox" name="ndconc" id="ndconc" onclick="toggleInfo('ndconc')"><label for="ndconc">NDConc</label><br>
1309              <input type="checkbox" name="volumes" id="volumes" onclick="toggleInfo('volumes')"><label for="volumes">Used volume+water</label><br>
1310            </td>
1311          </tr>
1312          </table>
1313          <br>
1314        </td>
1315        <td class="help"></td>
1316      </tr>
1317      </table>
1318    </td>
1319  </tr>
1320 
1321  <tr>
1322    <td>
1323      <tbl:toolbar subclass="bottomborder">
1324        <tbl:button 
1325          title="Load from file&hellip;" 
1326          image="<%=home+"/images/file.png"%>" 
1327          onclick="selectFile()" 
1328          tooltip="Load plate design from file"
1329        />
1330       
1331        <tbl:button 
1332          title="Auto-select" 
1333          image="<%=home+"/images/wizard.png"%>" 
1334          onclick="autoSelect()" 
1335          tooltip="Let the wizard auto-select RNA"
1336        />
1337        <tbl:button 
1338          title="Manual select&hellip;" 
1339          image="<%=home+"/images/manual_rna.png"%>" 
1340          onclick="manualSelect()" 
1341          tooltip="Manually select RNA items" 
1342        />
1343        <tbl:button 
1344          title="Stratagene" 
1345          image="<%=home+"/images/stratagene.png"%>" 
1346          onclick="setToStratagene()" 
1347          tooltip="Place stratagene in the selected wells" 
1348        />
1349        <tbl:button 
1350          title="Toggle QC" 
1351          image="<%=home+"/images/mrnaqc.png"%>" 
1352          onclick="toggleQc()" 
1353          tooltip="Select/deselect RNA for QC" 
1354        />
1355        <tbl:button 
1356          title="Cut&hellip;" 
1357          image="<%=home+"/images/cut.png"%>" 
1358          onclick="cutSelected()" 
1359          tooltip="Clear the selected wells" 
1360        />
1361        <tbl:button 
1362          title="Copy" 
1363          image="<%=home+"/images/copy.png"%>" 
1364          onclick="copySelected()" 
1365          tooltip="Make a copy of the selected RNA" 
1366        />
1367        <tbl:button 
1368          title="Paste" 
1369          image="<%=home+"/images/paste.png"%>" 
1370          onclick="pasteToSelected()" 
1371          tooltip="Paste RNA into selected wells" 
1372        />
1373      </tbl:toolbar>
1374        <table class="plate hide-volumes hide-ndconc" style="margin: 1em 1em 0 1em;" id="plate">
1375        <%
1376        int columns = 12;
1377        int rows = 8;
1378        WellCoordinateFormatter rowF = new WellCoordinateFormatter(true);
1379        WellCoordinateFormatter colF = new WellCoordinateFormatter(false);
1380        %>
1381        <tr class="header">
1382          <th>
1383            <base:icon image="<%=home+"/images/select_all.png"%>" 
1384              onclick="toggleAll()" 
1385              tooltip="Select/deselect all wells on the plate" 
1386            />
1387          </th>
1388          <%
1389          for (int c = 0; c < columns; ++c)
1390          {
1391            %>
1392            <th class="link" id="col.<%=c%>"
1393              onclick="toggleColumn(<%=c%>)" 
1394              onmouseover="highlightColumn(<%=c%>, true)"
1395              onmouseout="highlightColumn(<%=c%>, false)"
1396              title="Select/deselect all wells in this column"><%=colF.format(c)%></td>
1397            <%
1398          }
1399          %>
1400        </tr>
1401        <tbody>
1402        <%
1403        for (int r = 0; r < rows; ++r)
1404        {
1405          String row = rowF.format(r);
1406          %>
1407          <tr class="row-<%=r%>">
1408            <th class="link" id="row.<%=r%>"
1409              onclick="toggleRow(<%=r%>)"
1410              onmouseover="highlightRow(<%=r%>, true)"
1411              onmouseout="highlightRow(<%=r%>, false)"
1412              title="Select/deselect all wells in this row"><%=row%></th>
1413            <%
1414            for (int c = 0; c < columns; ++c)
1415            {
1416              %>
1417              <td id="well.<%=r%>.<%=c%>" 
1418                onclick="toggleWell(<%=r%>,<%=c%>)"
1419                onmouseenter="highlightReplicated(<%=r%>, <%=c%>, true)" 
1420                onmouseleave="highlightReplicated(<%=r%>, <%=c%>, false)"
1421                title="Select/deselect this well"></td>
1422              <%
1423            }
1424            %>
1425          </tr>
1426          <%
1427        }
1428        %>
1429        </tbody>
1430        <tr>
1431          <th></th>
1432          <%
1433          for (int i = 0; i < columns / 2; ++i)
1434          {
1435            %>
1436            <th colspan="2" class="link" id="pool.<%=i %>"
1437              onclick="togglePool(<%=i%>)" 
1438              onmouseover="highlightPool(<%=i%>, true)"
1439              onmouseout="highlightPool(<%=i%>, false)"
1440              title="Select/deselect all wells in this pool"
1441              ><%=i==0 || i == (columns / 2 - 1) ? "Extra" : "Pool #" + i %></td>
1442            <%
1443          }
1444          %>
1445        </tr>
1446        </table>
1447        <div style="padding-left: 1em; padding-bottom: 0.5em; padding-top: 2px;">
1448          <base:icon image="<%=home+"/images/mrnaqc.png"%>" />=Selected for QC
1449          <base:icon image="<%=home+"/images/copy.png"%>" style="padding-left: 1em;" />=Replicated RNA
1450          <base:icon image="<%=home+"/images/error.png"%>" style="padding-left: 1em;" />=Error that prevent plate creation
1451          <base:icon image="<%=home+"/images/warning.png"%>" style="padding-left: 1em;" />=Warning but plate can be created
1452        </div>
1453    </td>
1454  </tr>
1455  </table>
1456 
1457
1458  <div class="messagecontainer error" id="errorMessage" style="display: none; width: 950px; margin-left: 20px; margin-bottom: 0px;"></div>
1459
1460  <div id="done" class="success" style="display: none; width: 950px; margin-left: 20px; margin-top: 20px;"></div>
1461
1462  <table style="margin-left: 20px; margin-top: 10px;" class="navigation">
1463  <tr>
1464    <td><base:button id="gocancel" title="Cancel" onclick="goRestart(false)" /></td>
1465    <td><base:button id="gocreate" title="Create" image="<%=home+"/images/gonext.png"%>" onclick="goCreate()" /></td>
1466    <td><base:button id="gorestart" title="Restart" image="<%=home+"/images/goback.png"%>" onclick="goRestart(true)" style="display: none;"/></td>
1467  </tr>
1468  </table>
1469  </form>
1470 
1471  <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>
1472 
1473</div>
1474  </div>
1475</base:body>
1476</base:page>
1477<%
1478}
1479finally
1480{
1481  if (dc != null) dc.close();
1482}
1483%>
Note: See TracBrowser for help on using the repository browser.