source: trunk/www/biomaterials/wizards/move_biomaterial.jsp @ 5541

Last change on this file since 5541 was 5541, checked in by Nicklas Nordborg, 12 years ago

References #1564: Move biomaterial on plates

  • Added support for using a predefined plate mapping when moving biomaterial.
  • Display mapped well coordinates on the destination plate.
File size: 24.3 KB
Line 
1<%-- $Id$
2  ------------------------------------------------------------------
3  Copyright (C) 2010 Nicklas Nordborg
4
5  This file is part of BASE - BioArray Software Environment.
6  Available at http://base.thep.lu.se/
7
8  BASE is free software; you can redistribute it and/or
9  modify it under the terms of the GNU General Public License
10  as published by the Free Software Foundation; either version 3
11  of the License, or (at your option) any later version.
12
13  BASE is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  GNU General Public License for more details.
17
18  You should have received a copy of the GNU General Public License
19  along with BASE. If not, see <http://www.gnu.org/licenses/>.
20  ------------------------------------------------------------------
21
22  @author Nicklas
23--%>
24<%@page import="net.sf.basedb.core.BioPlateEventType"%>
25<%@ page pageEncoding="UTF-8" session="false"
26  import="net.sf.basedb.core.BioPlate"
27  import="net.sf.basedb.core.BioPlateEvent"
28  import="net.sf.basedb.core.MeasuredBioMaterial"
29  import="net.sf.basedb.core.Hardware"
30  import="net.sf.basedb.core.Protocol"
31  import="net.sf.basedb.core.DbControl"
32  import="net.sf.basedb.core.Item"
33  import="net.sf.basedb.core.ItemContext"
34  import="net.sf.basedb.core.ItemQuery"
35  import="net.sf.basedb.core.SessionControl"
36  import="net.sf.basedb.core.query.Restrictions"
37  import="net.sf.basedb.core.query.Hql"
38  import="net.sf.basedb.util.Values"
39  import="net.sf.basedb.util.formatter.Formatter"
40  import="net.sf.basedb.clients.web.formatter.FormatterFactory"
41  import="net.sf.basedb.clients.web.formatter.FormatterSettings"
42  import="net.sf.basedb.clients.web.Base"
43  import="net.sf.basedb.clients.web.util.HTML"
44  import="java.util.List"
45  import="java.util.Date"
46  import="java.util.Collections"
47%>
48<%@ taglib prefix="base" uri="/WEB-INF/base.tld" %>
49<%@ taglib prefix="tbl" uri="/WEB-INF/table.tld" %>
50<%
51final SessionControl sc = Base.getExistingSessionControl(pageContext, true);
52final String ID = sc.getId();
53final float scale = Base.getScale(sc);
54final int sourcePlateId = Values.getInt(request.getParameter("sourceplate_id"));
55final ItemContext cc = sc.getCurrentContext(Item.BIOPLATEEVENT, BioPlateEventType.MOVE);
56final DbControl dc = sc.newDbControl();
57try
58{
59  BioPlate sourcePlate = BioPlate.getById(dc, sourcePlateId);
60 
61  // Load recently used items
62  List<Hardware> recentHardware = (List<Hardware>)cc.getRecent(dc, Item.HARDWARE);
63  List<Protocol> recentProtocols = (List<Protocol>)cc.getRecent(dc, Item.PROTOCOL);
64 
65  Item itemType = Item.SAMPLE;
66 
67  final String clazz = "class=\"text\"";
68  final String requiredClazz = "class=\"text required\"";
69  final Formatter<Date> dateFormatter = FormatterFactory.getDateFormatter(sc);
70  final String dateFormat = FormatterSettings.getDateFormat(sc);
71  final String jsDateFormat = HTML.javaScriptEncode(dateFormat);
72  final String htmlDateFormat = HTML.encodeTags(dateFormat);
73  final boolean showSourceCoordinates = Values.getBoolean(sc.getUserClientSetting("move-biomaterial.show-source-coordinates"), true);
74  %>
75  <base:page type="popup" title="Move biomaterial">
76  <base:head scripts="ajax.js,plate.js,js-draw.js" styles="plate.css,toolbar.css">
77    <script language="javascript">
78 
79    // For drawing
80    var graphics;
81    var pen;
82    var selectedPen;
83   
84    // Source and destination plates
85    var sourcePlate;
86    var destPlate;
87   
88    // We can select one well on each plate
89    var selectedSourceWell;
90    var selectedDestWell;
91
92    function init()
93    {
94      // Initialize graphics
95      graphics = new jsGraphics(document.getElementById('canvas'));
96      pen = new jsPen();
97      selectedPen = new jsPen(new jsColor('445577'), 2);
98      setBioPlateCallback(<%=sourcePlateId%>, '<%=HTML.javaScriptEncode(sourcePlate.getName())%>', true);
99    }
100
101    /**
102      Select the source well that is clicked on. The currently selected well
103      is de-selected. If the clicked well is the same as the currently
104      selected well no new item is selected. If a destination well is already
105      selected a link is made between the source and destination wells.
106    */
107    function sourceWellOnClick(row, column)
108    {
109      var well = sourcePlate.getWell(row, column);
110      if (!well) return;
111
112      // De-select the currently selected source well
113      if (selectedSourceWell)
114      {
115        selectedSourceWell.setSelected(false);
116        if (well == selectedSourceWell)
117        {
118          // Re-draw link with regular pen (eg. same as onmouseover)
119          selectedSourceWell.drawLink(graphics, pen, true);
120          selectedSourceWell = null;
121          return;
122        }
123        else
124        {
125          selectedSourceWell.hideLink(graphics);
126        }
127      }
128     
129      // Select the new source well and draw link to destination well
130      selectedSourceWell = well;
131      selectedSourceWell.setSelected(true);
132      selectedSourceWell.drawLink(graphics, selectedPen, true);
133
134      // Map the source and destination wells
135      if (selectedSourceWell && selectedDestWell)
136      {
137        mapSelectedWells();
138      }
139    }
140   
141    /**
142      Draw a link between the mapped source and destination wells.
143    */
144    function sourceWellOnMouseOver(row, column)
145    {
146      var well = sourcePlate.getWell(row, column);
147      if (!well) return;
148      well.drawLink(graphics, pen, false);
149    }
150   
151    /**
152      Hide the link between the mapped source and destination
153      wells, unless one of them is selected.
154    */
155    function sourceWellOnMouseOut(row, column)
156    {
157      var well = sourcePlate.getWell(row, column);
158      if (!well) return;
159      if (!well.selected && !(well.mappedWell && well.mappedWell.selected))
160      {
161        well.hideLink(graphics);
162      }
163    }
164   
165    function destWellOnClick(row, column)
166    {
167      var well = destPlate.getWell(row, column);
168
169      // De-select the currently selected well
170      if (selectedDestWell)
171      {
172        selectedDestWell.setSelected(false);
173        if (well == selectedDestWell)
174        {
175          // Re-draw link with regular pen (eg. same as onmouseover)
176          selectedDestWell.drawLink(graphics, pen, true);
177          selectedDestWell = null;
178          return;
179        }
180        else
181        {
182          selectedDestWell.hideLink(graphics);
183        }
184      }
185     
186      selectedDestWell = well;
187      selectedDestWell.setSelected(true);
188      selectedDestWell.drawLink(graphics, selectedPen, true);
189
190      if (selectedSourceWell && selectedDestWell)
191      {
192        mapSelectedWells();
193      }
194    }
195   
196    function destWellOnMouseOver(row, column)
197    {
198      var well = destPlate.getWell(row, column);
199      if (!well) return;
200      well.drawLink(graphics, pen, false);
201    }
202   
203    function destWellOnMouseOut(row, column)
204    {
205      var well = destPlate.getWell(row, column);
206      if (!well) return;
207      if (!well.selected && !(well.mappedWell && well.mappedWell.selected))
208      {
209        well.hideLink(graphics);
210      }
211    }
212
213    /**
214      Map the selected source and destination wells. Hide and
215      redraw links as needed.
216    */
217    function mapSelectedWells()
218    {
219      // Hide any links that are currently displayed
220      selectedSourceWell.hideLink(graphics);
221      selectedDestWell.hideLink(graphics);
222     
223      // Map to the new well and draw link
224      if (selectedSourceWell.mappedWell != selectedDestWell)
225      {
226        selectedSourceWell.mapToWell(selectedDestWell);
227        selectedSourceWell.drawLink(graphics, pen, true);
228      }
229      else
230      {
231        selectedSourceWell.unmapWell();
232      }
233     
234      // De-select everything
235      selectedSourceWell.setSelected(false);
236      selectedDestWell.setSelected(false);
237      selectedSourceWell = null;
238      selectedDestWell = null;
239    }
240
241   
242    /**
243      Remove all mappings that have been made so far.
244    */
245    function clearMapping()
246    {
247      if (!destPlate)
248      {
249        alert('No destination plate has been selected');
250        return;
251      }
252      if (!confirm('This will remove all placed biomaterial. Continue?')) return;
253      sourcePlate.unmapAll();
254    }
255   
256    /**
257      Automatically move remaining biomaterial to the destination plate filling rows first.
258      Biomaterial and wells that have already been mapped are skipped.
259    */
260    function placeByRow()
261    {
262      if (!destPlate)
263      {
264        alert('No destination plate has been selected');
265        return;
266      }
267      var srcRow = 0;
268      var srcCol = 0;
269      for (var destRow = 0; destRow < destPlate.rows; destRow++)
270      {
271        for (var destCol = 0; destCol < destPlate.columns; destCol++)
272        {
273          var destWell = destPlate.getWell(destRow, destCol);
274          if (!destWell.mappedWell && !destWell.locked)
275          {
276            var mapped = false;
277            var srcWell = sourcePlate.getWell(srcRow, srcCol);
278            while (srcWell && !mapped)
279            {
280              if (srcWell.id && !srcWell.locked && !srcWell.mappedWell)
281              {
282                srcWell.mapToWell(destWell);
283                mapped = true;
284              }
285              else
286              {
287                srcCol++;
288                if (srcCol >= sourcePlate.columns)
289                {
290                  srcCol = 0;
291                  srcRow++;
292                }
293                srcWell = sourcePlate.getWell(srcRow, srcCol);
294              }
295            }
296          }
297        }
298      }
299    }
300 
301    /**
302      Automatically move remaining biomaterial to the destination plate filling columns first.
303      Biomaterial and wells that have already been mapped are skipped.
304    */
305    function placeByColumn()
306    {
307      if (!destPlate)
308      {
309        alert('No destination plate has been selected');
310        return;
311      }
312      var srcRow = 0;
313      var srcCol = 0;
314      for (var destCol = 0; destCol < destPlate.columns; destCol++)
315      {
316        for (var destRow = 0; destRow < destPlate.rows; destRow++)
317        {
318          var destWell = destPlate.getWell(destRow, destCol);
319          if (!destWell.mappedWell && !destWell.locked)
320          {
321            var mapped = false;
322            var srcWell = sourcePlate.getWell(srcRow, srcCol);
323            while (srcWell && !mapped)
324            {
325              if (srcWell.id && !srcWell.locked && !srcWell.mappedWell)
326              {
327                srcWell.mapToWell(destWell);
328                mapped = true;
329              }
330              else
331              {
332                srcRow++;
333                if (srcRow >= sourcePlate.rows)
334                {
335                  srcCol++;
336                  srcRow = 0;
337                }
338                srcWell = sourcePlate.getWell(srcRow, srcCol);
339              }
340            }
341          }
342        }
343      }
344    }
345
346   
347    function selectBioPlateOnClick()
348    {
349      if (destPlate && !confirm('This will reset all moved biomaterial. Continue?')) return;
350     
351      var url = '../bioplates/index.jsp?ID=<%=ID%>&cmd=UpdateContext&mode=selectone&callback=setBioPlateCallback';
352      url += '&resetTemporary=1&tmpfilter:INT:bioPlateType.bioMaterialType=|<%=itemType.getValue()%>'
353      url += '&exclude='+sourcePlate.id;
354      Main.openPopup(url, 'SelectBioPlate', 1000, 700);
355    }
356
357    function setBioPlateCallback(bioPlateId, name, isSourcePlate)
358    {
359      if (!isSourcePlate && bioPlateId == sourcePlate.id)
360      {
361        alert('It is not possible to use the same plate as both source and destination plate.');
362        return;
363      }
364     
365      var request = Ajax.getXmlHttpRequest();
366      var url = '../bioplates/ajax.jsp?ID=<%=ID%>&cmd=GetFullPlateInfo&item_id=' + bioPlateId;
367      request.open("GET", url, false);
368      // NOTE! 'false' causes code to wait for the response. aka. 'Synchronous AJAX' or SJAX.
369      request.send(null);
370      var response = Ajax.parseResponse(request.responseText);
371      if (response.isError())
372      {
373        alert(response.getErrorMessage());
374        return false;
375      }
376
377      // Get plate and well information from the AJAX response
378      var records = response.getElements();
379      var plateInfo = records[0];
380      var rows = parseInt(plateInfo['rows']);
381      var columns = parseInt(plateInfo['columns']);
382     
383      var bigPlate = rows > 12 || columns > 18;
384      var plateClass = bigPlate ? 'plate bigplate' : 'plate';
385
386      // Remove existing mapping
387      if (sourcePlate) sourcePlate.unmapAll();
388
389      // Create plate and wells
390      var prefix = isSourcePlate ? 'source' : 'dest';
391      var plate = new Plate(prefix, plateInfo['id'], plateInfo['name'], rows, columns, isSourcePlate);
392      for (var i = 1; i < records.length; i++)
393      {
394        var wellInfo = records[i];
395        var row = parseInt(wellInfo['well.row']);
396        var col = parseInt(wellInfo['well.column']);
397        var well = plate.getWell(row, col);
398        well.id = wellInfo['bm.id'];
399        well.name = wellInfo['bm.name'];
400        well.locked = isSourcePlate ? wellInfo['well.can-clear'] == '0' : wellInfo['well.can-add'] == '0' || well.id;
401      }
402     
403      // Create html table representing the bioplate
404      var html = '<table class="'+plateClass+'" cellspacing="0" cellpadding="0" onmouseout="event.cancelBubble=true">';
405      html += '<tr><td></td>';
406      for (var c = 0; c < plate.columns; c++)
407      {
408        html += '<td class="columnheader">' + (c+1) + '</td>';
409      }
410      html += '</tr>';
411      for (var r = 0; r < plate.rows; r++)
412      {
413        html += '<tr><td class="rowheader">' + Plates.toAlphaCoordinate[r] + '</td>';
414        for (var c = 0; c < plate.columns; c++)
415        {
416          var well = plate.getWell(r, c);
417          var cls = 'well';
418          var onclick = '';
419          var onmouseover = '';
420          var onmouseout = '';
421          var title = well.name ? Main.encodeTags(well.name) : '';
422          if (isSourcePlate)
423          {
424            // We can only move a biomaterial if the well is not empty or locked
425            if (well.id)
426            {
427              if (well.locked)
428              {
429                cls += ' filled locked';
430              }
431              else
432              {
433                cls += ' filled editable';
434                onclick = ' onclick="sourceWellOnClick('+r+','+c+')"';
435                onmouseover = ' onmouseover=sourceWellOnMouseOver('+r+','+c+')';
436                onmouseout = ' onmouseout=sourceWellOnMouseOut('+r+','+c+')';
437              }
438            }
439            else
440            {
441              cls += ' empty';
442            }
443          }
444          else
445          {
446            // We only add biomaterial to destination well if it is not locked
447            if (well.locked)
448            {
449              cls += ' unmappable';
450            }
451            else
452            {
453              cls += ' empty editable';
454              onclick = ' onclick="destWellOnClick('+r+','+c+')"';
455              onmouseover = ' onmouseover=destWellOnMouseOver('+r+','+c+')';
456              onmouseout = ' onmouseout=destWellOnMouseOut('+r+','+c+')';
457            }
458          }
459          html += '<td id="'+prefix+'.'+r+'.'+c+'" class="' + cls + '"' + onclick + onmouseover + onmouseout+' title="'+title+'">';
460          html += '<div class="info" id="'+prefix+'.'+r+'.'+c+'.info"></div></td>';
461        }
462        html += '</tr>';
463      }
464      html += '</table>';
465      if (isSourcePlate)
466      {
467        document.getElementById('plate.src').innerHTML = html;
468        document.getElementById('plate.src.name').innerHTML = Main.encodeTags(name);
469        sourcePlate = plate;
470      }
471      else
472      {
473        document.getElementById('plate.dest').innerHTML = html;
474        document.getElementById('plate.dest.name').innerHTML = Main.encodeTags(name);
475        destPlate = plate;
476        Main.showHide('plate.dest.options', !bigPlate);
477        showSourceCoordinatesOnClick();
478      }
479    }
480   
481    /**
482      Save the event.
483    */
484    function doMoveBioMaterial()
485    {
486      if (!destPlate)
487      {
488        alert('No destination plate has been selected');
489        return;
490      }
491      var frm = document.forms['main'];
492      if (Main.trimString(frm.name.value) == '')
493      {
494        alert("You must enter a name for the event.");
495        frm.name.focus();
496        return;
497      }
498     
499      frm.destplate_id.value = destPlate.id;
500      frm.rows.value = destPlate.rows;
501      frm.columns.value = destPlate.columns;
502     
503      var numMapped = 0;
504      for (var row = 0; row < destPlate.rows; row++)
505      {
506        for (var column = 0; column < destPlate.columns; column++)
507        {
508          var well = destPlate.getWell(row, column);
509         
510          if (well.mappedWell)
511          {
512            Forms.createHidden(frm, 'well.' + row + '.' + column, well.mappedWell.id);
513            numMapped++;
514          }
515        }
516      }
517     
518      if (numMapped == 0)
519      {
520        alert('No wells have been mapped.');
521        return;
522      }
523     
524      frm.submit();
525    }
526   
527
528    function selectHardwareOnClick()
529    {
530      var frm = document.forms['main'];
531      var url = '../../admin/hardware/index.jsp?ID=<%=ID%>&cmd=UpdateContext&mode=selectone&callback=setHardwareCallback';
532      if (frm.hardware_id.length > 1)
533      {
534        var id = Math.abs(parseInt(frm.hardware_id[1].value));       
535        url += '&item_id='+id;
536      }
537      url += '&resetTemporary=1';
538      Main.openPopup(url, 'SelectHardware', 1000, 700);
539    }
540    function setHardwareCallback(id, name)
541    {
542      var frm = document.forms['main'];
543      var list = frm.hardware_id;
544      if (list.length < 2 || list[1].value == '0') // >
545      {
546        Forms.addListOption(list, 1, new Option());
547      }
548      list[1].value = id;
549      list[1].text = name;
550      list.selectedIndex = 1;
551    }
552 
553    function selectProtocolOnClick()
554    {
555      var frm = document.forms['main'];
556      var url = '../../admin/protocols/index.jsp?ID=<%=ID%>&cmd=UpdateContext&mode=selectone&callback=setProtocolCallback';
557      if (frm.protocol_id.length > 1)
558      {
559        var id = Math.abs(parseInt(frm.protocol_id[1].value));       
560        url += '&item_id='+id;
561      }
562      url += '&resetTemporary=1';
563      Main.openPopup(url, 'SelectProtocol', 1000, 700);
564    }
565    function setProtocolCallback(id, name)
566    {
567      var frm = document.forms['main'];
568      var list = frm.protocol_id;
569      if (list.length < 2 || list[1].value == '0') // >
570      {
571        Forms.addListOption(list, 1, new Option());
572      }
573      list[1].value = id;
574      list[1].text = name;
575      list.selectedIndex = 1;
576    }
577   
578    function selectPlateMappingOnClick()
579    {
580      if (!destPlate)
581      {
582        alert('No destination plate has been selected');
583        return;
584      }
585      var url = '../../lims/platemappings/index.jsp?ID=<%=ID%>&cmd=UpdateContext&mode=selectone&callback=setPlateMappingCallback';
586      url += '&resetTemporary=1';
587      url += '&tmpfilter:INT:sourceGeometry.rows='+sourcePlate.rows;
588      url += '&tmpfilter:INT:sourceGeometry.columns='+sourcePlate.columns;
589      url += '&tmpfilter:INT:sourceCount=1';
590      url += '&tmpfilter:INT:destinationGeometry.rows='+destPlate.rows;
591      url += '&tmpfilter:INT:destinationGeometry.columns='+destPlate.columns;
592      url += '&tmpfilter:INT:destinationCount=1';
593      Main.openPopup(url, 'SelectPlateMapping', 1000, 700);
594    }
595   
596    function setPlateMappingCallback(plateMappingId, name)
597    {
598      var request = Ajax.getXmlHttpRequest();
599      var url = '../../lims/platemappings/ajax.jsp?ID=<%=ID%>&cmd=GetMappingDetails&item_id=' + plateMappingId;
600      request.open("GET", url, false);
601      request.send(null);
602      var response = Ajax.parseResponse(request.responseText);
603      if (response.isError())
604      {
605        alert(response.getErrorMessage());
606        return false;
607      }
608     
609      var records = response.getElements();
610      var mappingInfo = records[0];
611      if (mappingInfo['source.plates'] != '1' || mappingInfo['source.rows'] != sourcePlate.rows || mappingInfo['source.columns'] != sourcePlate.columns)
612      {
613        if (!confirm("The selected mapping doesn't match the geometry of the source plate.\nContinue mapping overlapping positions?")) return;
614      }
615      else if (mappingInfo['destination.plates'] != '1' || mappingInfo['destination.rows'] != destPlate.rows || mappingInfo['destination.columns'] != destPlate.columns)
616      {
617        if (!confirm("The selected mapping doesn't match the geometry of the destination plate.\nContinue mapping overlapping positions?")) return;
618      }
619     
620      var mappings = records[1];
621      var numMapped = 0;
622      for (var i = 0; i < mappings.length; i++)
623      {
624        var mapping = mappings[i].split(',');
625        var srcWell = sourcePlate.getWell(parseInt(mapping[1]), parseInt(mapping[2]));
626        var destWell = destPlate.getWell(parseInt(mapping[4]), parseInt(mapping[5]));
627        if (srcWell && destWell)
628        {
629          if (!destWell.mappedWell && !destWell.locked && srcWell.id && !srcWell.locked && !srcWell.mappedWell)
630          {
631            srcWell.mapToWell(destWell);
632            numMapped++;
633          }
634        }
635      }
636    }
637   
638    function showSourceCoordinatesOnClick()
639    {
640      var frm = document.forms['main'];
641      Main.addOrRemoveClass(document.getElementById('plate.dest'), 'noinfo', !frm.showSourceCoordinates.checked);
642    }
643    </script>
644  </base:head>
645  <base:body onload="init()">
646    <div id="canvas"></div>
647    <h3>Move biomaterial to plate</h3>
648    <div class="boxedbottom" style="height: <%=(int)(scale*500)%>px; padding: 0px;">
649      <form name="main" action="index.jsp" method="post">
650      <input type="hidden" name="ID" value="<%=ID%>">
651      <input type="hidden" name="cmd" value="MoveBioMaterial">
652      <input type="hidden" name="sourceplate_id" value="<%=sourcePlateId%>">
653      <input type="hidden" name="destplate_id" value="">
654      <input type="hidden" name="rows" value="">
655      <input type="hidden" name="columns" value=""> 
656     
657      <table cellspacing="0" border="0" width="100%" style="background: #e0e0e0; padding-bottom: 6px;">
658      <tr valign="top">
659      <td>
660        <table class="form" cellspacing="0">
661        <tr>
662          <td class="prompt" style="width: 90px;">Event name</td>
663          <td><input <%=requiredClazz%> type="text" name="name" 
664            value="Move biomaterial" 
665            size="40" maxlength="<%=BioPlateEvent.MAX_NAME_LENGTH%>"></td>
666        </tr>
667        <tr>
668          <td class="prompt">Event date</td>
669          <td>
670            <table border="0" cellspacing="0" cellpadding="0">
671            <tr>
672            <td>
673              <input <%=clazz%> type="text" name="event_date" 
674                value="<%=HTML.encodeTags(dateFormatter.format(new Date()))%>" 
675                size="20" maxlength="20" title="Enter date in format: <%=htmlDateFormat%>">
676              &nbsp;
677            </td>
678            <td>
679            <base:button 
680              onclick="<%="Dates.selectDate('Event date', 'main', 'event_date', null, '"+jsDateFormat+"')"%>"
681              image="calendar.png"
682              title="Calendar&hellip;" 
683              tooltip="Select a date from a calendar" 
684            />
685            </td>
686            </tr>
687            </table>
688          </td>
689        </tr>
690        <tr>
691          <td class="prompt">Protocol</td>
692          <td>
693            <base:select 
694              id="protocol_id"
695              clazz="selectionlist"
696              required="false"
697              current="<%=null%>"
698              recent="<%=recentProtocols%>"
699              onselect="selectProtocolOnClick()"
700            />
701          </td>
702        </tr>
703        <tr>
704          <td class="prompt">Hardware</td>
705          <td>
706            <base:select 
707              id="hardware_id"
708              clazz="selectionlist"
709              required="false"
710              current="<%=null%>"
711              recent="<%=recentHardware%>"
712              onselect="selectHardwareOnClick()"
713            />
714          </td>
715        </tr>
716        </table>
717      </td>
718      <td>
719        <b>Description</b><br>
720        <textarea <%=clazz%> rows="4" cols="40" name="description" wrap="virtual"
721          ></textarea>
722        <a href="javascript:Main.zoom('Description', 'main', 'description')"
723          title="Edit in larger window"><base:icon image="zoom.gif" /></a>
724      </td>
725    </tr>
726    </table>
727
728    <tbl:toolbar id="toolbar.mappings" style="border-left: 0px; border-right: 0px;">
729      <tbl:button title="Select plate&hellip;" 
730          onclick="javascript:selectBioPlateOnClick()" 
731          image="move_to_plate.png" 
732          tooltip="Select the destination plate"
733        />
734        <tbl:button title="Clear" 
735          onclick="clearMapping()" 
736          image="cancel.gif" 
737          tooltip="Clear all mapped wells"
738        />
739        <tbl:button title="Place by row" 
740          onclick="placeByRow()" 
741          image="place_by_row.png" 
742          tooltip="Place remaining items; start with rows"
743        />
744        <tbl:button title="Place by column" 
745          onclick="placeByColumn()" 
746          image="place_by_column.png" 
747          tooltip="Place remaining items; start with columns"
748        />
749        <tbl:button title="Predefined mapping&hellip;" 
750          onclick="selectPlateMappingOnClick()" 
751          image="star.png" 
752          tooltip="Select a predefined plate mapping"
753        />
754      </tbl:toolbar>
755 
756      <table cellspacing="0" cellpadding="0" border="0" width="100%" style="padding: 4px;">
757      <tr valign="top">
758        <td style="width: 50%;">
759          <div style="max-height: <%=(int)(scale*350)%>px; overflow: auto;">
760            <b>Source plate:</b> <span id="plate.src.name"></span>
761            <div id="plate.src"></div>
762          </div>
763        </td>
764        <td style="width: 50%;">
765          <div style="max-height: <%=(int)(scale*350)%>px; overflow: auto;">
766            <b>Destination plate:</b> <span id="plate.dest.name"><i>not selected</i></span>
767            <div id="plate.dest"></div>
768            <div id="plate.dest.options" style="display: none;">
769            <input type="checkbox" name="showSourceCoordinates" 
770              <%=showSourceCoordinates ? "checked" : ""%> value="1"
771              onclick="showSourceCoordinatesOnClick()">Show source coordinates
772            </div>
773          </div>
774        </td>
775      </tr>
776      </table>
777    </div>
778    </form>
779
780    <table align="center">
781    <tr>
782      <td width="50%"><base:button onclick="doMoveBioMaterial()" title="Save" /></td>
783      <td width="50%"><base:button onclick="window.close()" title="Cancel" /></td>
784    </tr>
785    </table>
786   
787  </base:body>
788  </base:page>
789  <%
790}
791finally
792{
793  if (dc != null) dc.close();
794}
795%>
Note: See TracBrowser for help on using the repository browser.