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