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

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

References #424: Select RNA items for library preparation

Added a 'special select' menu that can be used to quickly select wells with a certain condition. For example, all empty wells, wells with Stratagene, wells with an error, etc.

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