source: extensions/net.sf.basedb.reggie/branches/ticket-489/resources/sampleproc/histology_score.jsp @ 2125

Last change on this file since 2125 was 2125, checked in by Nicklas Nordborg, 8 years ago

References #489: Histology scoring wizard

Implemented saving of scores. There are still some rough corners and error handling to take care of.

File size: 27.0 KB
Line 
1<%@ page
2  pageEncoding="UTF-8"
3  session="false"
4  import="net.sf.basedb.core.User"
5  import="net.sf.basedb.core.DbControl"
6  import="net.sf.basedb.core.SessionControl"
7  import="net.sf.basedb.core.Application"
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="java.text.SimpleDateFormat"
12  import="java.util.Date"
13%>
14<%@ taglib prefix="base" uri="/WEB-INF/base.tld" %>
15<%@ taglib prefix="p" uri="/WEB-INF/path.tld" %>
16<%@ taglib prefix="tbl" uri="/WEB-INF/table.tld" %>
17<%@ taglib prefix="t" uri="/WEB-INF/tab.tld" %>
18<%
19final SessionControl sc = Base.getExistingSessionControl(request, true);
20final String ID = sc.getId();
21final float scale = Base.getScale(sc);
22final String home = ExtensionsControl.getHomeUrl("net.sf.basedb.reggie");
23DbControl dc = null;
24try
25{
26  dc = sc.newDbControl();
27  final User user = User.getById(dc, sc.getLoggedInUserId());
28  final String today = new SimpleDateFormat("yyyyMMdd").format(new Date());
29  final String name = request.getParameter("name");
30%>
31<base:page type="default" >
32<base:head scripts="ajax.js,tabcontrol.js" styles="path.css,toolbar.css,tabcontrol.css">
33  <link rel="stylesheet" type="text/css" href="../css/reggie.css">
34  <script language="JavaScript" src="../reggie.js" type="text/javascript" charset="UTF-8"></script>
35
36<script language="JavaScript">
37var debug = 0;
38var currentStep = 1;
39var selectedSample;
40var heGlass;
41
42var SCORES = ['ScoreInvasiveCancer', 'ScoreInsituCancer', 'ScoreLymphocytes', 'ScoreNormal', 'ScoreStroma', 'ScoreFat'];
43var FIELDS = ['score_invasive_cancer', 'score_insitu_cancer', 'score_lymphocytes', 'score_normal', 'score_stroma', 'score_fat'];
44
45function init()
46{
47  var frm = document.forms['reggie'];
48 
49  var glassName = '<%=HTML.javaScriptEncode(name)%>'
50  heGlass = getHeGlassForScoring(glassName);
51 
52  if (heGlass != null && heGlass.length > 0)
53  {
54    // Generate HE glass HTML
55    var html = '';
56    for (var glassNo = 0; glassNo < heGlass.length; glassNo++)
57    {
58      var glass = heGlass[glassNo];
59      html += createHeGlassSection(glass);
60    }
61    setInnerHTML('he-glass-container', html);
62    Main.show('he-glass-container');
63   
64    // Fill form with know information
65    var firstGoodSample;
66    for (var glassNo = 0; glassNo < heGlass.length; glassNo++)
67    {
68      var glass = heGlass[glassNo];
69      for (var sampleNo = 0; sampleNo < glass.samples.length; sampleNo++)
70      {
71        var sample = glass.samples[sampleNo];
72       
73        saveOriginalProperties(sample);
74       
75        // Save ID of HE glass since we need that later
76        sample.heGlassId = glass.id;
77       
78        // Save the first GoodStain sample so we can select it later
79        if (sample.GoodStain && firstGoodSample == null)
80        {
81          firstGoodSample = sample;
82        }
83       
84        // Calculate sum of scores
85        var total = calculateTotalScore(sample);
86       
87        // Generate text inside table cell
88        var html = '<div class="sample-name">'+sample.name.replace(/\.he\d+$/, '')+'</div>';
89        html += '<div class="progress" id="'+sample.id+'.progress">' + total + '%</div>';
90       
91        var td = document.getElementById(sample.heGlassId+'-'+sample.well.location);
92        td.innerHTML = html;
93        td.sample = sample;
94        setSampleClassName(sample);
95       
96        td.addEventListener('click', sampleOnClick, false);
97      }
98    }
99   
100    if (firstGoodSample != null)
101    {
102      Main.show('score-container');
103      selectSample(firstGoodSample);
104    }
105    Main.show('gocreate');
106    window.addEventListener('beforeunload', confirmIfModified);
107
108  }
109  else
110  {
111    var msg;
112    if (glassName)
113    {
114      msg = 'Could not find HE glass with name: ' + Main.encodeTags(glassName);
115    }
116    else
117    {
118      msg = 'No HE glass available for scoring.';
119      msg += ' Specify HE glass name above to re-score.';
120    }
121    setInnerHTML('he-glass-container', '<div class="messagecontainer note">'+msg+'</div>');
122    Main.show('he-glass-container');
123  }
124 
125  // Wait a second until loading uncompleted HE glass
126  setTimeout(loadUncompletedHeGlass, 1000);
127 
128}
129
130/**
131  Remember the original properties so that we know if
132  a sample has been modified.
133*/
134function saveOriginalProperties(sample)
135{
136  var o = {};
137  for (var i = 0; i < SCORES.length; i++)
138  {
139    var p = SCORES[i];
140    o[p] = sample[p]; 
141  }
142 
143  o.GoodStain = sample.GoodStain;
144  o.ScoreComplete = sample.ScoreComplete;
145  sample.o = o;
146  sample.isModified = false;
147}
148
149/**
150  Check if a sample has been modified.
151*/
152function isModified(sample, useCache)
153{
154  if (useCache)
155  {
156    return sample.isModified;
157  }
158  var o = sample.o;
159  for (var p in o)
160  {
161    if (o[p] != sample[p]) return true;
162  }
163  return false;
164}
165
166function findHeGlass(glassName, autoFind)
167{
168  var frm = document.forms['reggie'];
169  if (!glassName && autoFind != true)
170  {
171    glassName = frm.findGlassName.value;
172    if (glassName.match(/^\d+$/))
173    {
174      while (glassName.length < 5)
175      {
176        glassName = '0'+glassName;
177      }
178      glassName = 'HE'+glassName;
179    }
180  }
181  var url =  '<%=home%>/sampleproc/histology_score.jsp?ID=<%=ID%>';
182  if (glassName)
183  {
184    url += '&name='+encodeURIComponent(glassName);
185  }
186 
187  location.href = url;
188}
189
190function selectHeGlass()
191{
192  var url = getRoot() + 'biomaterials/bioplates/index.jsp?ID=<%=ID%>&cmd=UpdateContext&mode=selectone';
193  url += '&resetTemporary=1';
194  url += '&tmpfilter:STRING:name='+encodeURIComponent('HE%');
195  url += '&callback=setSelectedHeGlass'
196  Main.openPopup(url, 'SelectHeGlass', 1050, 700);
197}
198
199function setSelectedHeGlass(id, name)
200{
201  findHeGlass(name);
202}
203
204function getHeGlassForScoring(glassName)
205{
206  var frm = document.forms['reggie']; 
207  var request = Ajax.getXmlHttpRequest();
208  try
209  {
210    var msg = glassName ? 'Finding HE glass: '+Main.encodeTags(glassName) : 'Loading next HE glass for scoring...';
211    showLoadingAnimation(msg);
212    var url = '../Histology.servlet?ID=<%=ID%>&cmd=GetHeGlassToScore';
213    if (glassName)
214    {
215      url += '&name='+encodeURIComponent(glassName);
216    }
217    request.open("GET", url, false); 
218    request.send(null);
219  }
220  finally
221  {
222    hideLoadingAnimation();
223  }
224 
225  if (debug) Main.debug(request.responseText);
226  var response = JSON.parse(request.responseText); 
227  if (response.status != 'ok')
228  {
229    setFatalError(response.message);
230    return false;
231  }
232  return response.heGlasses;
233}
234
235
236function createHeGlassSection(glass)
237{
238  var html = '';
239  html += '<div class="he-glass">';
240 
241  html += '<div class="he-name">' + Main.encodeTags(glass.name || '') + '</div>';
242 
243  html += '<div class="he-info">';
244  html += '<span class="he-tray">' +  Main.encodeTags(glass.tray || '') + '</span>; <span class="he-position">' + Main.encodeTags(glass.position || '') + '</span>';
245  html += '<div class="he-comment">' + Main.encodeTags(glass.comments || '') + '</div>';
246  html += '</div>';
247 
248  html += '<table class="he-table">';
249  html += '<tr>';
250  html += '<td class="not-used" id="'+glass.id+'-A1"></td>';
251  html += '<td class="not-used" id="'+glass.id+'-A2"></td>';
252  html += '</tr>';
253  html += '<tr>';
254  html += '<td class="not-used" id="'+glass.id+'-B1"></td>';
255  html += '<td class="not-used" id="'+glass.id+'-B2"></td>';
256  html += '</tr>';
257  html += '<tr>';
258  html += '<td class="not-used" id="'+glass.id+'-C1"></td>';
259  html += '<td class="not-used" id="'+glass.id+'-C2"></td>';
260  html += '</tr>';
261  html += '</table>';
262  html += '</div>';
263
264  return html;
265 
266}
267
268function setSampleClassName(sample)
269{
270  var className = 'used';
271  if (sample.GoodStain)
272  {
273    className += ' good-stain';
274  }
275 
276  if (sample.ScoreTotal == null)
277  {
278    className += ' score-none';
279  }
280  else if (sample.ScoreTotal != 100 || !sample.ScoreComplete)
281  {
282    className += ' score-incomplete';
283  }
284  else
285  {
286    className += ' score-complete';
287  }
288 
289  if (isModified(sample))
290  {
291    className += ' modified';
292  }
293 
294  if (selectedSample && selectedSample.id == sample.id)
295  {
296    className += ' selected';
297  }
298 
299  var td = document.getElementById(sample.heGlassId+'-'+sample.well.location);
300  td.className = className;
301}
302
303function selectSample(sample)
304{
305  var frm = document.forms['reggie'];
306 
307  // Sample name
308  setInnerHTML('sample.name', sample.name);
309 
310  // Scores
311  for (var i = 0; i < SCORES.length; i++)
312  {
313    frm[FIELDS[i]].value = sample[SCORES[i]];
314  }
315 
316  // Total score + score complete
317  var total = calculateTotalScore(sample);
318  setInnerHTML('score_total', total);
319  if (total == 100)
320  {
321    if (sample.numNullScores == 0)
322    {
323      frm.score_complete.disabled = false;
324      frm.score_complete.checked = sample.ScoreComplete;
325      setInputStatus('score_total', '', 'valid');
326    }
327    else
328    {
329      frm.score_complete.disabled = true;
330      frm.score_complete.checked = false;
331      setInputStatus('score_total', 'Enter 0 in empty fields to complete scoring', 'warning');
332    }
333  }
334  else
335  {
336    frm.score_complete.disabled = true;
337    frm.score_complete.checked = false;
338    setInputStatus('score_total', 'Not 100%', 'warning');
339  }
340 
341  // Good stain
342  if (sample.GoodStain)
343  {
344    frm.good_stain.checked = true;
345    frm.good_stain.disabled = true;
346  }
347  else
348  {
349    frm.good_stain.checked = false;
350    frm.good_stain.disabled = false;
351  }
352 
353  // Comments
354  frm.comments.value = sample.comments;
355 
356  // Class name of selected table cell
357  if (selectedSample != null)
358  {
359    var td = document.getElementById(selectedSample.heGlassId+'-'+selectedSample.well.location);
360    Main.removeClass(td, ' selected');
361  }
362 
363  selectedSample = sample;
364  setSampleClassName(sample);
365 
366  frm.score_invasive_cancer.focus();
367}
368
369function sampleOnClick(event)
370{
371  var td = event.currentTarget;
372  selectSample(td.sample);
373}
374
375function checkScores()
376{
377  var frm = document.forms['reggie'];
378
379  for (var i = 0; i < SCORES.length; i++)
380  {
381    selectedSample[SCORES[i]] = toScore(frm[FIELDS[i]].value);
382  }
383 
384  var oldTotal = selectedSample.ScoreTotal;
385  var oldNumNull = selectedSample.numNullScores;
386 
387  var total = calculateTotalScore(selectedSample);
388 
389  setInnerHTML('score_total', total);
390  setInnerHTML(selectedSample.id+'.progress', total + '%');
391 
392  if (total == 100)
393  {
394    if (selectedSample.numNullScores == 0)
395    {
396      // All scores have been entered
397      frm.score_complete.disabled = false;
398      if (oldTotal != total || oldNumNull != selectedSample.numNullScores)
399      {
400        // Only check the 'Score complete' if value has changed
401        frm.score_complete.checked = true;
402        selectedSample.ScoreComplete = true;
403      }
404      setInputStatus('score_total', '', 'valid');
405    }
406    else
407    {
408      frm.score_complete.disabled = true;
409      frm.score_complete.checked = false;
410      selectedSample.ScoreComplete = false;
411      setInputStatus('score_total', 'Enter 0 in empty fields to complete scoring', 'warning');
412    }
413  }
414  else
415  {
416    frm.score_complete.disabled = true;
417    frm.score_complete.checked = false;
418   
419    if (selectedSample.ScoreTotal != null)
420    {
421      selectedSample.ScoreComplete = false;
422      setInputStatus('score_total', 'Not 100%', 'warning');
423    }
424    else
425    {
426      selectedSample.ScoreComplete = null;
427      setInputStatus('score_total', '', '');
428    }
429  }
430
431  setSampleClassName(selectedSample);
432}
433
434function calculateTotalScore(sample)
435{
436  var total = 0;
437  var numNull = 0;
438  for (var i = 0; i < SCORES.length; i++)
439  {
440    var score = sample[SCORES[i]];
441    total += sumScore(score);
442    if (score == null) numNull++;
443  }
444  // Set summed total, null only if all values are null
445  sample.ScoreTotal = total == 0 && numNull == SCORES.length ? null : total;
446  sample.numNullScores = numNull;
447  return total;
448}
449
450function toScore(value)
451{
452  var score = parseInt(value);
453  return isNaN(score) ? null : score;
454}
455
456function sumScore(score)
457{
458  return score || 0;
459}
460
461function scoreCompleteOnClick()
462{
463  var frm = document.forms['reggie'];
464  selectedSample.ScoreComplete = frm.score_complete.checked;
465  setSampleClassName(selectedSample);
466}
467
468function goodStainOnClick()
469{
470  var frm = document.forms['reggie'];
471 
472  // Reset GoodStain on other samples on same location
473  for (var glassNo = 0; glassNo < heGlass.length; glassNo++)
474  {
475    var glass = heGlass[glassNo];
476   
477    for (var sampleNo = 0; sampleNo < glass.samples.length; sampleNo++)
478    {
479      var sample = glass.samples[sampleNo];
480      if (sample.well.location == selectedSample.well.location)
481      {
482        sample.GoodStain = null;
483        setSampleClassName(sample);
484      }
485    }
486  }
487 
488  selectedSample.GoodStain = frm.good_stain.checked ? true : null;
489  frm.good_stain.disabled = true;
490  setSampleClassName(selectedSample);
491}
492
493function commentsOnBlur()
494{
495  var frm = document.forms['reggie'];
496  selectedSample.comments = frm.comments.value;
497}
498
499function loadUncompletedHeGlass()
500{
501  var request = Ajax.getXmlHttpRequest();
502  try
503  {
504    //showLoadingAnimation('Loading next HE glass for scoring...');
505    var url = '../Histology.servlet?ID=<%=ID%>&cmd=GetUncompletedHeGlass';
506    request.open("GET", url, false); 
507    request.send(null);
508  }
509  finally
510  {}
511 
512  if (debug) Main.debug(request.responseText);
513  var response = JSON.parse(request.responseText); 
514  if (response.status == 'ok')
515  {
516    var uncompleted = response.heGlasses;
517   
518    if (uncompleted.length > 0)
519    {
520      // Populate menu item
521      setInnerHTML('uncompletedHeGlass.text', uncompleted.length + ' uncompleted');
522      var html = ''; 
523      for (var glassNo = 0; glassNo < uncompleted.length; glassNo++)
524      {
525        var glass = uncompleted[glassNo];
526     
527        html += '<div class="menuitem enabled" id="glass-'+glass.id+'">';
528        html += Main.encodeTags(glass.name)+' ('+glass.numUncompleteSamples +')</div>';
529      }
530      setInnerHTML('select-uncompleted-heglass-menu', html);
531      Main.show('uncompletedHeGlass');
532    }
533    else
534    {
535      Main.hide('uncompletedHeGlass');
536    }
537  }
538}
539
540function showUncompletedHeGlassMenu(event)
541{
542  var menu = document.getElementById('select-uncompleted-heglass');
543  menu.style.display = 'block';
544 
545  var pos = Main.getElementPosition(document.getElementById('uncompletedHeGlass'));
546  var x = pos.left;
547  var y = pos.top+pos.height;
548
549  menu.style.left = (x)+'px';
550  menu.style.top = (y)+'px';
551  event.stopPropagation();
552}
553
554function uncompletedGlassSelected(event)
555{
556  findHeGlass(event.target.innerHTML);
557}
558
559/**
560  Confirm if leaving the page is ok. If no event is passed this method
561  is called manually and need to display dialog, otherwise the browser
562  is taking care of this automatically.
563*/
564function confirmIfModified(event)
565{
566  var numModified = 0;
567  for (var glassNo = 0; glassNo < heGlass.length; glassNo++)
568  {
569    var glass = heGlass[glassNo];
570    for (var sampleNo = 0; sampleNo < glass.samples.length; sampleNo++)
571    {
572      var sample = glass.samples[sampleNo];
573      if (isModified(sample))
574      {
575        numModified++;
576      }
577    }
578  }
579 
580  var okToContinue = true;
581  if (numModified > 0)
582  {
583    if (event)
584    {
585      event.returnValue = 'There are unsaved modifications. Continue?';
586    }
587    else
588    {
589      if (!confirm('There are unsaved modifications. Continue?'))
590      {
591        okToContinue = false;
592      }
593    }
594  }
595 
596  return okToContinue;
597}
598
599function saveModified()
600{
601  var samples = [];
602  var glassInfo = [];
603 
604  for (var glassNo = 0; glassNo < heGlass.length; glassNo++)
605  {
606    var glass = heGlass[glassNo];
607    var scoreCompleteForGlass = true;
608    for (var sampleNo = 0; sampleNo < glass.samples.length; sampleNo++)
609    {
610      var sample = glass.samples[sampleNo];
611      if (isModified(sample))
612      {
613        samples[samples.length] = sample;
614      }
615     
616      if (sample.GoodStain && sample.ScoreComplete != true || sample.ScoreComplete == false)
617      {
618        scoreCompleteForGlass = false;
619      }
620    }
621   
622    var tmp = {};
623    tmp.id = glass.id;
624    tmp.ScoreComplete = scoreCompleteForGlass;
625    glassInfo[glassInfo.length] = tmp;
626  }
627 
628  if (samples.length == 0)
629  {
630    if (!confirm('Nothing has changed! Continue saving?'))
631    {
632      return;
633    }
634  }
635 
636  Main.hide('score-container');
637  Main.addClass(document.getElementById('he-glass-container'), 'disabled');
638   
639  var submitInfo = {};
640  submitInfo.samples = samples;
641  submitInfo.heGlass = glassInfo;
642 
643  if (debug) Main.debug(JSON.stringify(submitInfo));     
644  var request = Ajax.getXmlHttpRequest();
645 
646  try
647  {
648    showLoadingAnimation('Saving...');
649    var url = '../Histology.servlet?ID=<%=ID%>&cmd=SaveHeScore';
650    request.open("POST", url, false);
651    request.setRequestHeader("Content-Type", "application/json"); 
652    request.send(JSON.stringify(submitInfo));
653  }
654  finally
655  {
656    hideLoadingAnimation();
657  }
658
659  if (debug) Main.debug(request.responseText);
660
661
662  var response = JSON.parse(request.responseText);
663  if (response.status != 'ok')
664  {
665    setFatalError(response.message);
666    return false;
667  }
668 
669  var msg = '<ul>';
670  for (var i = 0; i < response.messages.length; i++)
671  {
672    msg += '<li>' + response.messages[i];
673  }
674  msg += '</ul>';
675  setInnerHTML('done', msg);
676 
677  Main.show('done');
678  Main.show('gonext');
679  Main.hide('gocreate');
680
681}
682
683</script>
684<style>
685
686/* Less wide to make more space for help text */
687.stepfields .input
688{
689  width: 200px;
690}
691
692input.score
693{
694  width: 6em;
695  text-align: right;
696  padding-right: 4px;
697}
698
699#he-glass-container
700{
701  white-space: nowrap;
702  overflow: auto;
703}
704
705.he-glass
706{
707  display: inline-block;
708  border: 1px solid #A0A0A0;
709  margin: 1em;
710  width: 20em;
711  background: #E8E8E8;
712}
713
714.he-name
715{
716  font-weight: bold;
717  background-color: #E0E0E0;
718  border-bottom: 1px solid #A0A0A0;
719  padding: 0.25em;
720}
721
722.he-info
723{
724  background-color: #FFFFFF;
725  border-bottom: 1px solid #A0A0A0;
726  padding: 0.25em;
727  height: 5em;
728  overflow: auto;
729  white-space: normal;
730}
731
732.he-tray:before
733{
734  content: 'Tray: ';
735}
736
737.he-position:before
738{
739  content: 'Position: ';
740}
741
742.he-comment
743{
744  font-style: italic;
745}
746
747
748#score-container
749{
750  clear: both;
751}
752
753.he-table
754{
755  margin-top: 1em;
756  margin-bottom: 1em;
757  margin-left: auto;
758  margin-right: auto;
759  border: 1px solid #A0A0A0;
760}
761
762.he-table td
763{
764  width: 10em;
765  height: 10em;
766  border: 1px solid #A0A0A0;
767  padding: 2px;
768  background: #FFFFFF;
769  background-position: center center;
770  background-repeat: no-repeat;
771  vertical-align: top;
772  text-align: center;
773  font-size: 75%;
774  color: #666666;
775  cursor: pointer;
776}
777
778.he-table td.used:hover
779{
780  border: 2px solid #2288AA;
781  border-radius: 4px;
782  padding: 1px;
783}
784
785.he-table td.not-used
786{
787  background-color: #D0D0D0;
788  background-image: url('../images/not-used.png');
789  cursor: default;
790}
791
792.he-table td.selected
793{
794  background-color: #D8FFFF;
795}
796
797.he-table td.good-stain
798{
799  font-weight: bold;
800  color: #000000;
801}
802
803.he-table td.good-stain.score-none
804{
805  background-image: url('../images/score-none.png');
806}
807
808.he-table td.good-stain.score-incomplete
809{
810  background-image: url('../images/score-incomplete.png');
811}
812
813.he-table td.good-stain.score-complete
814{
815  background-image: url('../images/score-complete.png');
816}
817
818td.modified .sample-name:after
819{
820  content: ' *';
821  color: #2244FF;
822}
823
824/* Hide progress by default */
825.progress
826{
827  display: none;
828}
829
830/* Show progress for GoodStain or total score > 0 */
831td.good-stain .progress, td.score-incomplete .progress, td.score-complete .progress
832{
833  display: block;
834}
835
836td.score-incomplete .progress:before
837{
838  content: '(';
839}
840td.score-incomplete .progress:after
841{
842  content: ')';
843}
844
845.score-align
846{
847  width: 6em;
848  display: inline-block;
849  padding: 3px;
850  text-align: right;
851}
852
853#score_total
854{
855  background-color: #E8E8E8;
856  font-weight: bold;
857  padding-right: 6px;
858}
859
860#select-uncompleted-heglass-menu
861{
862  max-height: 20em;
863  overflow: auto;
864}
865
866#select-uncompleted-heglass .menuitem
867{
868  padding-left: 16px;
869}
870
871#select-uncompleted-heglass .menuitem:hover
872{
873  padding-left: 14px;
874  background-position: 0px 50%;
875}
876</style>
877
878</base:head>
879<base:body onload="init()">
880
881  <p:path><p:pathelement 
882    title="Reggie" href="<%="../index.jsp?ID="+ID%>" 
883    /><p:pathelement title="Register HE glass score" 
884    /></p:path>
885
886  <div class="content" onclick="Main.hide('select-uncompleted-heglass')">
887  <%
888  if (sc.getActiveProjectId() == 0)
889  {
890    %>
891    <div class="messagecontainer note" style="width: 950px; margin-left: 20px; margin-bottom: 20px; margin-right: 0px; font-weight: bold; color: #cc0000;">
892      No project has been selected. You may proceed with the registration but
893      created items will not be shared.
894    </div>
895    <%
896  }
897  %>
898 
899  <div id="select-uncompleted-heglass" class="menu vertical" style="width: 150px; display: none; z-index: 999;"
900    onclick="uncompletedGlassSelected(event)">
901    <div id="select-uncompleted-heglass-menu"></div>
902  </div>
903 
904  <form name="reggie" onsubmit="return false;">
905 
906  <table class="stepform" id="step.1.section">
907  <tr>
908    <td rowspan="3" class="stepno">1</td>
909    <td class="steptitle">HE glass to score</td>
910  </tr>
911  <tr>
912    <td class="stepfields">
913      <tbl:toolbar subclass="bottomborder">
914        <tbl:label>
915        <input type="text" style="width: 12em;" name="findGlassName" 
916          placeholder="Find HE glass" title="Enter a full HE glass name or the last digits in the it's number before the dot"
917          onkeypress="if (event.keyCode==13 && this.value) findHeGlass()"
918          >
919          <base:icon image="<%=home+"/images/gonext.png"%>" onclick="findHeGlass()"></base:icon>
920        </tbl:label>
921       
922     
923        <tbl:button 
924          title="Select HE glass&hellip;" 
925          image="<%=home + "/images/microscope.png"%>" 
926          onclick="selectHeGlass()"
927          tooltip="Manually select a different HE glass"
928        />
929
930        <tbl:button
931          id="uncompletedHeGlass"
932          title="Loading..."
933          image="mini_scroll_down.png"
934          onclick="showUncompletedHeGlassMenu(event)"
935          tooltip="This list contain HE glass with partial scores"
936        />
937
938      </tbl:toolbar>
939     
940      <div id="he-glass-container" style="display: none;">
941       
942      </div>
943
944      <div id="score-container" style="display: none;">
945        <table style="border-collapse: collapse; width: 100%;">
946        <tr valign="top" style="background-color: #E8E8E8; border-top: 1px solid #A0A0A0; border-bottom: 1px solid #A0A0A0;">
947          <td class="prompt" style="padding: 0.25em;">Sample</td>
948          <td class="input" id="sample.name" style="padding: 0.25em; font-weight: bold;"></td>
949          <td class="status"></td>
950          <td class="help"></td>
951        </tr>
952       
953        <tr>
954          <td class="prompt">GoodStain</td>
955          <td class="input"><span class="score-align"><input type="checkbox" name="good_stain" onclick="goodStainOnClick()"
956            title="Mark this checkbox to overtake the GoodStain annotation"
957            ></span></td>
958          <td class="status" id="good_stain.status"></td>
959          <td class="help" rowspan="2">
960            Check to overtake the GoodStain annotation.
961            Disabled if this sample is already annotated.
962          </td>
963        </tr>
964       
965        <tr>
966          <td class="prompt">Scores</td>
967          <td class="input"></td>
968          <td class="status"></td>
969        </tr>
970        <tr>
971          <td class="subprompt">Invasive cancer</td>
972          <td class="input"><input type="text" class="score" name="score_invasive_cancer"
973            onkeypress="focusOnEnter(event, 'score_insitu_cancer'); return Numbers.integerOnly(event)"
974            onblur="checkScores()"
975            >%</td>
976          <td class="status" id="score_invasive_cancer.status"></td>
977          <td class="help" rowspan="2">
978            Enter the percentage for each cell type.
979            They must sum up to 100% before scoring can be compeleted.
980          </td>
981        </tr>   
982
983        <tr>
984          <td class="subprompt">In situ cancer</td>
985          <td class="input"><input type="text" class="score" name="score_insitu_cancer"
986            onkeypress="focusOnEnter(event, 'score_lymphocytes'); return Numbers.integerOnly(event)"
987            onblur="checkScores()"
988            >%</td>
989          <td class="status" id="score_insitu_cancer.status"></td>
990        </tr>   
991        <tr>
992          <td class="subprompt">Lymphocytes</td>
993          <td class="input"><input type="text" class="score" name="score_lymphocytes"
994            onkeypress="focusOnEnter(event, 'score_normal'); return Numbers.integerOnly(event)"
995            onblur="checkScores()"
996            >%</td>
997          <td class="status" id="score_lymphocytes.status"></td>
998          <td class="help"></td>
999        </tr>   
1000        <tr>
1001          <td class="subprompt">Normal</td>
1002          <td class="input"><input type="text" class="score" name="score_normal"
1003            onkeypress="focusOnEnter(event, 'score_stroma'); return Numbers.integerOnly(event)"
1004            onblur="checkScores()"
1005            >%</td>
1006          <td class="status" id="score_normal.status"></td>
1007          <td class="help"></td>
1008        </tr>   
1009        <tr>
1010          <td class="subprompt">Stroma</td>
1011          <td class="input"><input type="text" class="score" name="score_stroma"
1012            onkeypress="focusOnEnter(event, 'score_fat'); return Numbers.integerOnly(event)"
1013            onblur="checkScores()"
1014            >%</td>
1015          <td class="status" id="score_stroma.status"></td>
1016          <td class="help"></td>
1017        </tr>   
1018        <tr>
1019          <td class="subprompt">Fat</td>
1020          <td class="input"><input type="text" class="score" name="score_fat"
1021            onkeypress="focusOnEnter(event, 'comments'); return Numbers.integerOnly(event)"
1022            onblur="checkScores()"
1023            >%</td>
1024          <td class="status" id="score_fat.status"></td>
1025          <td class="help"></td>
1026        </tr>
1027        <tr>
1028          <td class="subprompt" style="font-weight: bold; background-color: #E8E8E8;">Total</td>
1029          <td class="input" style="padding: 0;"><span class="score-align" id="score_total"></span>%</td>
1030          <td class="status" id="score_total.status"></td>
1031          <td class="help"><span class="message" id="score_total.message"></span></td>
1032        </tr>
1033       
1034        <tr>
1035          <td class="subprompt">Score complete</td>
1036          <td class="input"><span class="score-align"><input type="checkbox" name="score_complete" 
1037            onclick="scoreCompleteOnClick()"
1038            title="Uncheck if scoring is not complete"></span></td>
1039          <td class="status" id="score_complete.status"></td>
1040          <td class="help">
1041            Uncheck if scoring is not complete. Disabled if some scores
1042            are missing or the total score is not 100%.
1043          </td>
1044        </tr>
1045       
1046        <tr>
1047          <td class="prompt" colspan="3">Comments<br>
1048            <textarea rows="3" style="width: 97%;" name="comments" onblur="commentsOnBlur()"></textarea>
1049          </td>
1050          <td class="help"></td>
1051        </tr>
1052        </table>
1053      </div>   
1054
1055    </td>
1056  </tr>
1057  </table>
1058 
1059
1060  <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>
1061 
1062  <div class="messagecontainer error" id="errorMessage" style="display: none; width: 950px; margin-left: 20px; margin-bottom: 0px;"></div>
1063 
1064  <div id="done" class="success" style="display: none; width: 950px; margin-left: 20px; margin-top: 20px;"></div>
1065 
1066  <table style="margin-left: 20px; margin-top: 10px;" class="navigation" id="navigation">
1067    <tr>
1068      <td><base:button id="gocancel" title="Cancel" onclick="goRestart(false)" style="display: none;" /></td>
1069      <td><base:button id="gonext" title="Next HE glass set" image="<%=home+"/images/gonext.png"%>" onclick="findHeGlass(null, true)" style="display: none;" /></td>
1070      <td><base:button id="gocreate" title="Save" image="<%=home+"/images/gonext.png"%>" onclick="saveModified()" style="display: none;" /></td>
1071      <td><base:button id="gorestart" title="Restart" image="<%=home+"/images/goback.png"%>" onclick="goRestart(true)" style="display: none;"/></td>
1072      <td id="gonext.message" class="message"></td>
1073    </tr>
1074  </table>
1075  </form>
1076  </div>
1077 
1078</base:body>
1079</base:page>
1080<%
1081}
1082finally
1083{
1084  if (dc != null) dc.close();
1085}
1086%>
Note: See TracBrowser for help on using the repository browser.