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

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

References #1570: Use JSON for data transport in AJAX calls

Implemented this for various plate/well releated AJAX calls.

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