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

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

References #424: Select RNA items for library preparation

It should now be possible to use this wizard for creating a plate with mRNA items. There are currently two main options for selecting RNA:

  • Manually using the regular BASE list interface. Unfortunately, it is not possible to filter away RNA that already has mRNA child items.


  • File import using a tab-separated file. The file should have 3 or four columns: name of RNA, work plate row (A-H), work plate column (1-12), optional QC flag


The automatic RNA selection remains to be implemented.

A lot of error checking, etc. has been implemented. Eg. checking for enough remaining quantity, etc. but may it may have to be fine-tuned.

There is also still some code cleanup to be done, but this can probably be made more efficiently when some of the other wizards are in place since there may be some common patterns.

Before the wizard can be used a RNA extract item with the name 'Stratagene' must be created by hand. This will be done by the installation wizard in the future. NOTE! This item can interfere with the RNAQC wizards so they must also be checked/fixed!

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