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

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

References #424: Select RNA items for library preparation

Added filter that exclude RNA with mRNA child items to the 'Manual select' dialog. This depends on the bug fix http://base.thep.lu.se/ticket/1736 so we now require BASE 3.2.1 for Reggie.

File size: 39.0 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  url += '&'+encodeURIComponent('tmpfilter:STRING:&childCreationEvents(event.bioMaterial.name)')+'='+encodeURIComponent('<>%.m');
984  Main.openPopup(url, 'SelectRNA', 1000, 700);
985}
986
987/**
988  Callback method for manual selection.
989*/
990function setRnaCallback(id, name)
991{
992  if (currentIndex >= currentSelected.length)
993  {
994    return;
995  }
996  var well = currentSelected[currentIndex];
997 
998  // Keep a reference to the old rna in the well
999  var oldRna = well.rna;
1000
1001  // Create a new RNA object
1002  var rna = Rna.createByName(name);
1003  well.setRna(rna);
1004  well.selected = false;
1005  well.paint();
1006 
1007  // Update replicate information
1008  Plate.checkReplicates(name);
1009  if (oldRna) Plate.checkReplicates(oldRna.name);
1010 
1011  // Move to the next item
1012  currentIndex++;
1013}
1014
1015// Toggle the selected status of a single well
1016function toggleWell(row, column)
1017{
1018  var well = Plate.getWell(row, column);
1019  Plate.toggleSelected([well]);
1020}
1021
1022// Toggle the selected status of a complete row
1023function toggleRow(row)
1024{
1025  Plate.toggleSelected(Plate.getRow(row));
1026}
1027
1028// Toggle the selected status of a complete column
1029function toggleColumn(column)
1030{
1031  Plate.toggleSelected(Plate.getColumn(column));
1032}
1033
1034// Toggle the selected status of all wells
1035function toggleAll()
1036{
1037  Plate.toggleSelected(Plate.getWells());
1038}
1039
1040// Toggle the selected status of a complete pool (=two columns)
1041function togglePool(pool)
1042{
1043  Plate.toggleSelected(Plate.getPool(pool));
1044}
1045
1046// Some special toogle operations
1047function specialToggle(what)
1048{
1049  var wells = [];
1050  if (what == 'all' || what == 'empty')
1051  {
1052    // All wells or all empty (will be filtered later)
1053    wells = Plate.getWells();
1054  }
1055  else if (what == 'pools' || what == 'empty-pools')
1056  {
1057    // All primary pools or all empty in the primary pools (will be filtered later)
1058    for (var i = 1; i < 5; i++)
1059    {
1060      wells = wells.concat(Plate.getPool(i));
1061    }
1062  }
1063  else if (what == 'stratagene')
1064  {
1065    // All wells with 'Stratagene'
1066    var tmp = Plate.getWells();
1067    for (var i = 0; i < tmp.length; i++)
1068    {
1069      var well = tmp[i];
1070      if (well.rna && well.rna.stratagene) wells[wells.length] = well;
1071    }
1072  }
1073  else if (what == 'replicates')
1074  {
1075    // All wells with replicated RNA
1076    var tmp = Plate.getWells();
1077    for (var i = 0; i < tmp.length; i++)
1078    {
1079      var well = tmp[i];
1080      if (well.rna && well.rna.replicate) wells[wells.length] = well;
1081    }
1082  }
1083  else if (what == 'error')
1084  {
1085    // All wells with an error
1086    var tmp = Plate.getWells();
1087    for (var i = 0; i < tmp.length; i++)
1088    {
1089      var well = tmp[i];
1090      if (well.hasError()) wells[wells.length] = well;
1091    }
1092  }
1093  else if (what == 'warning')
1094  {
1095    // All wells with a warning
1096    var tmp = Plate.getWells();
1097    for (var i = 0; i < tmp.length; i++)
1098    {
1099      var well = tmp[i];
1100      if (well.warning) wells[wells.length] = well;
1101    }
1102  }
1103 
1104  // Extra filter for empty wells only
1105  if (what.indexOf('empty') != -1)
1106  {
1107    var tmp = wells;
1108    wells = [];
1109    for (var i = 0; i < tmp.length; i++)
1110    {
1111      if (!tmp[i].rna) wells[wells.length] = tmp[i];
1112    }
1113  }
1114 
1115  Plate.toggleSelected(wells);
1116}
1117
1118// Highlight enable/disable all wells in a column
1119function highlightColumn(column, on)
1120{
1121  Main.addOrRemoveClass(document.getElementById('col.'+column), 'highlight-column', on);
1122  var wells = Plate.getColumn(column);
1123  Plate.setHighlight(wells, 'highlight-column', on);
1124}
1125
1126// Highlight enable/disable all wells in a row
1127function highlightRow(row, on)
1128{
1129  Main.addOrRemoveClass(document.getElementById('row.'+row), 'highlight-row', on);
1130  var wells = Plate.getRow(row);
1131  Plate.setHighlight(wells, 'highlight-row', on);
1132}
1133
1134// Highlight enable/disable all wells in a pool
1135function highlightPool(pool, on)
1136{
1137  Main.addOrRemoveClass(document.getElementById('pool.'+pool), 'highlight-pool', on);
1138  var wells = Plate.getPool(pool);
1139  Plate.setHighlight(wells, 'highlight-pool', on);
1140}
1141
1142/**
1143  Highlight all replicated wells with the same RNA as the given well.
1144*/
1145function highlightReplicated(row, column, on)
1146{
1147  var well = Plate.getWell(row, column);
1148  if (well.rna && well.rna.replicate)
1149  {
1150    // Get center coordinates for the current well
1151    var pos = Main.getElementPosition(well.tag);
1152    var jsPos = new jsPoint(pos.left+pos.width/2, pos.top+pos.height/2);
1153
1154    var replicated = Plate.getWellsByName(well.rna.name);
1155    for (var i = 0; i < replicated.length; i++)
1156    {
1157      var rep = replicated[i];
1158      if (rep != well)
1159      {
1160        Main.addOrRemoveClass(rep.tag, 'highlight-replicated', on);
1161        if (rep.line)
1162        {
1163          // Clear any recent lines
1164          graphics.clearDrawing(rep.line);
1165          rep.line = null;
1166        }
1167        if (on)
1168        {
1169          // We draw a line between the current and replicated well
1170          var rPos = Main.getElementPosition(rep.tag);
1171          rep.line = graphics.drawLine(pen, jsPos, new jsPoint(rPos.left+rPos.width/2, rPos.top+rPos.height/2));
1172        }
1173      }
1174    }
1175  }
1176}
1177
1178
1179function goCreate()
1180{
1181  var submitInfo = {};
1182  var plateInfo = {};
1183  submitInfo.bioplate = plateInfo;
1184 
1185  plateInfo.name = Plate.name;
1186  plateInfo.wells = [];
1187
1188  var wells = Plate.getWells();
1189  var numErrors = 0;
1190  var numWarnings = 0;
1191  var numRna = 0;
1192  var numStratagene = 0;
1193  for (var i = 0; i < wells.length; i++)
1194  {
1195    var well = wells[i];
1196    if (well.warning) numWarnings++;
1197    if (well.hasError())
1198    {
1199      numErrors++;
1200    }
1201    else
1202    {
1203      if (well.rna && well.rna.id)
1204      {
1205        var tmp = {};
1206        tmp.row = well.row;
1207        tmp.column = well.column;
1208        tmp.rna = {};
1209        tmp.rna.id = well.rna.id;
1210        tmp.rna.usedQuantity = well.rna.qc ? QUANTITY_QC : QUANTITY_REGULAR;
1211        plateInfo.wells[plateInfo.wells.length] = tmp;
1212        numRna++;
1213        if (well.rna.stratagene) numStratagene++;
1214      }
1215    }
1216  }
1217
1218  if (numErrors > 0)
1219  {
1220    alert('There are ' + numErrors + ' wells with errors. Please fix them before creating the mRNA plate.');
1221    return;
1222  }
1223
1224  if (numRna == 0)
1225  {
1226    alert('There is no RNA in any wells');
1227    return;
1228  }
1229 
1230  if (numWarnings > 0)
1231  {
1232    if (!confirm('There are ' + numWarnings + ' wells with a warning. Continue anyway?')) return;
1233  }
1234 
1235  if (numRna < 64)
1236  {
1237    if (!confirm('Less than 64 wells have RNA in them. Continue anyway?')) return;
1238  }
1239 
1240  if (numRna == numStratagene)
1241  {
1242    if (!confirm('There are only wells with Stratagene on this plate. Continue anyway?')) return;
1243  }
1244 
1245  Main.addClass(document.getElementById('step.1.section'), 'disabled');
1246  Main.hide('gocancel');
1247  Main.hide('gocreate');
1248
1249  if (debug) Main.debug(JSON.stringify(submitInfo));
1250 
1251  var request = Ajax.getXmlHttpRequest();
1252  var url = '../MRna.servlet?ID=<%=ID%>';
1253  url += '&cmd=CreateMRnaPlate';
1254  request.open("POST", url, false);
1255  request.setRequestHeader("Content-Type", "application/json");
1256  request.send(JSON.stringify(submitInfo));
1257
1258  if (debug) Main.debug(request.responseText);
1259
1260  var response = JSON.parse(request.responseText);
1261  if (response.status != 'ok')
1262  {
1263    setFatalError(response.message);
1264    return false;
1265  }
1266
1267  var msg = '<ul>';
1268  for (var i = 0; i < response.messages.length; i++)
1269  {
1270    msg += '<li>' + response.messages[i];
1271  }
1272  msg += '</ul>';
1273  setInnerHTML('done', msg);
1274  Main.show('done');
1275  Main.show('gorestart');
1276}
1277
1278function toggleInfo(what)
1279{
1280  var frm = document.forms['reggie'];
1281  var show = frm[what].checked;
1282  Main.addOrRemoveClass(document.getElementById('plate'), 'hide-'+what, !show);
1283}
1284
1285</script>
1286<style>
1287
1288/* A well assigned for QC include a background icon as indicator */
1289.well.qc
1290{
1291  background-image: url('../images/mrnaqc.png');
1292  background-position: 95% 5%;
1293  background-repeat: no-repeat;
1294}
1295
1296/* A well which contain replicate RNA is also marked with an icon */
1297.well.replicate
1298{
1299  background-image: url('../images/copy.png');
1300  background-position: 95% 5%;
1301  background-repeat: no-repeat;
1302}
1303
1304/* A well that is both a replicate and QC need to re-arrange the icons a bit */
1305.well.qc.replicate
1306{
1307  background-image: url('../images/mrnaqc.png'), url('../images/copy.png');
1308  background-position: 95% 5%, 95% 55%;
1309  background-repeat: no-repeat;
1310}
1311
1312.well .name
1313{
1314  font-weight: bold;
1315}
1316
1317.well .err-msg, .well .warn-msg
1318{
1319  color: #C80000;
1320  font-style: italic;
1321}
1322
1323.well .missing
1324{
1325  font-style: italic;
1326}
1327
1328.plate.hide-location .location
1329{
1330  display: none;
1331}
1332.plate.hide-quantity .quantity
1333{
1334  display: none;
1335}
1336.plate.hide-volumes .volumes
1337{
1338  display: none;
1339}
1340.plate.hide-ndconc .ndconc
1341{
1342  display: none;
1343}
1344
1345.volume
1346{
1347  color: #C80000;
1348}
1349.water
1350{
1351  color: #0000C8;
1352}
1353#iconSpecialSelect
1354{
1355  cursor: pointer;
1356}
1357</style>
1358</base:head>
1359<base:body onload="init()">
1360  <p:path><p:pathelement 
1361    title="Reggie" href="<%="../index.jsp?ID="+ID%>" 
1362    /><p:pathelement title="Create new mRNA plate" 
1363    /></p:path>
1364  <div id="canvas" class="absolutefull" style="z-index: -1;">
1365  <div class="content">
1366  <%
1367  if (sc.getActiveProjectId() == 0)
1368  {
1369    %>
1370    <div class="messagecontainer note" style="width: 950px; margin-left: 20px; margin-bottom: 20px; margin-right: 0px; font-weight: bold; color: #cc0000;">
1371      No project has been selected. You may proceed with the wizard but
1372      created items will not be shared.
1373    </div>
1374    <%
1375  }
1376  %>
1377 
1378  <form name="reggie" onsubmit="return false;">
1379 
1380  <table class="stepform" id="step.1.section" style="width: auto;">
1381  <tr>
1382    <td rowspan="3" class="stepno">1</td>
1383    <td class="steptitle">Fragmented mRNA plate</td>
1384  </tr>
1385  <tr>
1386    <td class="stepfields">
1387      <table class="bottomborder" style="width: 100%;">
1388      <tr>
1389        <td class="prompt">Name</td>
1390        <td class="input" id="plateName"></td>
1391        <td class="help">Select RNA items to use for the new mRNA plate.</td>
1392      </tr>
1393      <tr style="vertical-align: top;">
1394        <td class="prompt">Show</td>
1395        <td class="input">
1396          <table>
1397          <tr>
1398            <td>
1399              <input type="checkbox" name="location" id="location" onclick="toggleInfo('location')" checked><label for="location">Bioplate location</label><br>
1400              <input type="checkbox" name="quantity" id="quantity" onclick="toggleInfo('quantity')" checked><label for="quantity">Remaining quantity</label><br>
1401            </td>
1402            <td>
1403              <input type="checkbox" name="ndconc" id="ndconc" onclick="toggleInfo('ndconc')"><label for="ndconc">NDConc</label><br>
1404              <input type="checkbox" name="volumes" id="volumes" onclick="toggleInfo('volumes')"><label for="volumes">Used volume+water</label><br>
1405            </td>
1406          </tr>
1407          </table>
1408          <br>
1409        </td>
1410        <td class="help"></td>
1411      </tr>
1412      </table>
1413    </td>
1414  </tr>
1415 
1416  <tr>
1417    <td>
1418      <tbl:toolbar subclass="bottomborder">
1419        <tbl:button 
1420          title="Load from file&hellip;" 
1421          image="<%=home+"/images/file.png"%>" 
1422          onclick="selectFile()" 
1423          tooltip="Load plate design from file"
1424        />
1425       
1426        <tbl:button 
1427          title="Auto-select" 
1428          image="<%=home+"/images/wizard.png"%>" 
1429          onclick="autoSelect()" 
1430          tooltip="Let the wizard auto-select RNA"
1431        />
1432        <tbl:button 
1433          title="Manual select&hellip;" 
1434          image="<%=home+"/images/manual_rna.png"%>" 
1435          onclick="manualSelect()" 
1436          tooltip="Manually select RNA items" 
1437        />
1438        <tbl:button 
1439          title="Stratagene" 
1440          image="<%=home+"/images/stratagene.png"%>" 
1441          onclick="setToStratagene()" 
1442          tooltip="Place stratagene in the selected wells" 
1443        />
1444        <tbl:button 
1445          title="Toggle QC" 
1446          image="<%=home+"/images/mrnaqc.png"%>" 
1447          onclick="toggleQc()" 
1448          tooltip="Select/deselect RNA for QC" 
1449        />
1450        <tbl:button 
1451          title="Cut&hellip;" 
1452          image="<%=home+"/images/cut.png"%>" 
1453          onclick="cutSelected()" 
1454          tooltip="Clear the selected wells" 
1455        />
1456        <tbl:button 
1457          title="Copy" 
1458          image="<%=home+"/images/copy.png"%>" 
1459          onclick="copySelected()" 
1460          tooltip="Make a copy of the selected RNA" 
1461        />
1462        <tbl:button 
1463          title="Paste" 
1464          image="<%=home+"/images/paste.png"%>" 
1465          onclick="pasteToSelected()" 
1466          tooltip="Paste RNA into selected wells" 
1467        />
1468      </tbl:toolbar>
1469        <table class="plate hide-volumes hide-ndconc" style="margin: 1em 1em 0 1em;" id="plate">
1470        <%
1471        int columns = 12;
1472        int rows = 8;
1473        WellCoordinateFormatter rowF = new WellCoordinateFormatter(true);
1474        WellCoordinateFormatter colF = new WellCoordinateFormatter(false);
1475        %>
1476        <tr class="header">
1477          <th>
1478            <base:icon image="<%=home+"/images/select_all.png"%>" 
1479              id="iconSpecialSelect"
1480              tooltip="Select/deselect wells on the plate with specific condition" 
1481            >
1482            <m:menu
1483              id="menuSpecialSelect"
1484              style="display: none; font-weight: normal; text-align: left;">
1485              <m:menuitem 
1486                title="All" 
1487                onclick="specialToggle('all')"
1488                tooltip="Select/deselect all wells on the plate"
1489              />
1490              <m:menuitem 
1491                title="Pools" 
1492                onclick="specialToggle('pools')"
1493                tooltip="Select/deselect all pooled wells on the plate"
1494              />
1495              <m:menuitem 
1496                title="All empty" 
1497                onclick="specialToggle('empty')"
1498                tooltip="Select/deselect all empty wells on the plate"
1499              />
1500              <m:menuitem 
1501                title="Empty in pools" 
1502                onclick="specialToggle('empty-pools')"
1503                tooltip="Select/deselect all empty pooled wells on the plate"
1504              />
1505              <m:menuseparator />
1506              <m:menuitem 
1507                icon="<%=home+"/images/mrnaqc.png"%>"
1508                title="Stratagene" 
1509                onclick="specialToggle('stratagene')"
1510                tooltip="Select/deselect all wells with Stratagene"
1511              />
1512              <m:menuitem 
1513                icon="<%=home+"/images/copy.png"%>"
1514                title="Replicates" 
1515                onclick="specialToggle('replicates')"
1516                tooltip="Select/deselect all wells with replicated RNA"
1517              />
1518              <m:menuitem 
1519                icon="<%=home+"/images/error.png"%>"
1520                title="Error" 
1521                onclick="specialToggle('error')"
1522                tooltip="Select/deselect all wells with an error"
1523              />
1524              <m:menuitem 
1525                icon="<%=home+"/images/warning.png"%>"
1526                title="Warning" 
1527                onclick="specialToggle('warning')"
1528                tooltip="Select/deselect all wells with an error"
1529              />
1530            </m:menu>
1531          </base:icon>
1532        </th>
1533          <%
1534          for (int c = 0; c < columns; ++c)
1535          {
1536            %>
1537            <th class="link" id="col.<%=c%>"
1538              onclick="toggleColumn(<%=c%>)" 
1539              onmouseover="highlightColumn(<%=c%>, true)"
1540              onmouseout="highlightColumn(<%=c%>, false)"
1541              title="Select/deselect all wells in this column"><%=colF.format(c)%></td>
1542            <%
1543          }
1544          %>
1545        </tr>
1546        <tbody>
1547        <%
1548        for (int r = 0; r < rows; ++r)
1549        {
1550          String row = rowF.format(r);
1551          %>
1552          <tr class="row-<%=r%>">
1553            <th class="link" id="row.<%=r%>"
1554              onclick="toggleRow(<%=r%>)"
1555              onmouseover="highlightRow(<%=r%>, true)"
1556              onmouseout="highlightRow(<%=r%>, false)"
1557              title="Select/deselect all wells in this row"><%=row%></th>
1558            <%
1559            for (int c = 0; c < columns; ++c)
1560            {
1561              %>
1562              <td id="well.<%=r%>.<%=c%>" 
1563                onclick="toggleWell(<%=r%>,<%=c%>)"
1564                onmouseenter="highlightReplicated(<%=r%>, <%=c%>, true)" 
1565                onmouseleave="highlightReplicated(<%=r%>, <%=c%>, false)"
1566                title="Select/deselect this well"></td>
1567              <%
1568            }
1569            %>
1570          </tr>
1571          <%
1572        }
1573        %>
1574        </tbody>
1575        <tr>
1576          <th></th>
1577          <%
1578          for (int i = 0; i < columns / 2; ++i)
1579          {
1580            %>
1581            <th colspan="2" class="link" id="pool.<%=i %>"
1582              onclick="togglePool(<%=i%>)" 
1583              onmouseover="highlightPool(<%=i%>, true)"
1584              onmouseout="highlightPool(<%=i%>, false)"
1585              title="Select/deselect all wells in this pool"
1586              ><%=i==0 || i == (columns / 2 - 1) ? "Extra" : "Pool #" + i %></td>
1587            <%
1588          }
1589          %>
1590        </tr>
1591        </table>
1592        <div style="padding-left: 1em; padding-bottom: 0.5em; padding-top: 2px;">
1593          <base:icon image="<%=home+"/images/mrnaqc.png"%>" />=Selected for QC
1594          <base:icon image="<%=home+"/images/copy.png"%>" style="padding-left: 1em;" />=Replicated RNA
1595          <base:icon image="<%=home+"/images/error.png"%>" style="padding-left: 1em;" />=Error that prevent plate creation
1596          <base:icon image="<%=home+"/images/warning.png"%>" style="padding-left: 1em;" />=Warning but plate can be created
1597        </div>
1598    </td>
1599  </tr>
1600  </table>
1601 
1602
1603  <div class="messagecontainer error" id="errorMessage" style="display: none; width: 950px; margin-left: 20px; margin-bottom: 0px;"></div>
1604
1605  <div id="done" class="success" style="display: none; width: 950px; margin-left: 20px; margin-top: 20px;"></div>
1606
1607  <table style="margin-left: 20px; margin-top: 10px;" class="navigation">
1608  <tr>
1609    <td><base:button id="gocancel" title="Cancel" onclick="goRestart(false)" /></td>
1610    <td><base:button id="gocreate" title="Create" image="<%=home+"/images/gonext.png"%>" onclick="goCreate()" /></td>
1611    <td><base:button id="gorestart" title="Restart" image="<%=home+"/images/goback.png"%>" onclick="goRestart(true)" style="display: none;"/></td>
1612  </tr>
1613  </table>
1614  </form>
1615 
1616  <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>
1617 
1618</div>
1619  </div>
1620</base:body>
1621</base:page>
1622<%
1623}
1624finally
1625{
1626  if (dc != null) dc.close();
1627}
1628%>
Note: See TracBrowser for help on using the repository browser.