extensions/net.sf.basedb.meludi/trunk/resources/libprep/inspect_start_plate.js

Code
Comments
Other
Rev Date Author Line
3652 08 Dec 15 olle 1 var InspectStartPlate = function()
3652 08 Dec 15 olle 2 {
3652 08 Dec 15 olle 3   var inspectstartplate = {};
3652 08 Dec 15 olle 4   var barcodesByName = [];
3652 08 Dec 15 olle 5   
3652 08 Dec 15 olle 6   var EXTERNAL_DNA_NAME = 'External.d';
3652 08 Dec 15 olle 7   var debug = 0;
3652 08 Dec 15 olle 8   
3652 08 Dec 15 olle 9   var currentSelected;
3652 08 Dec 15 olle 10   var names = [];
3652 08 Dec 15 olle 11   var wells = [];
3652 08 Dec 15 olle 12   var protocolMap = {};
3652 08 Dec 15 olle 13   var kitNum = 0;
3652 08 Dec 15 olle 14   var selectedKitName;
3652 08 Dec 15 olle 15
3652 08 Dec 15 olle 16   var graphics;
3652 08 Dec 15 olle 17   var pen;
3652 08 Dec 15 olle 18   
3652 08 Dec 15 olle 19   var quantitiesAreValid = false;
3652 08 Dec 15 olle 20   var plateNameIsValid = false;
3652 08 Dec 15 olle 21   var subtypeDna;
3652 08 Dec 15 olle 22   var subtypeDnaNormalized;
3652 08 Dec 15 olle 23   var MINIMAL_DNA_VOLUME = 1.0; //µl
3652 08 Dec 15 olle 24   var THIN_SPACE = ' ';
3652 08 Dec 15 olle 25   
3652 08 Dec 15 olle 26   var jsonRowIndex = {"A": 0, "B": 1, "C": 2, "D": 3, "E": 4, "F": 5, "G": 6, "H": 7};
3652 08 Dec 15 olle 27   var jsonColIndex = {"1": 0, "2": 1, "3": 2, "4": 3, "5": 4, "6": 5, "7": 6, "8": 7, "9": 8, "10": 9, "11": 10, "12": 11};
3652 08 Dec 15 olle 28   var jsonRowLetter = {0: "A", 1: "B", 2: "C", 3: "D", 4: "E", 5: "F", 6: "G", 7: "H"};
3652 08 Dec 15 olle 29   var jsonColNumber = {0: "1", 1: "2", 2: "3", 3: "4", 4: "5", 5: "6", 6: "7", 7: "8", 8: "9", 9: "10", 10: "11", 11: "12"};
3652 08 Dec 15 olle 30
3652 08 Dec 15 olle 31   // Page initialization
3652 08 Dec 15 olle 32   inspectstartplate.initPage = function()
3652 08 Dec 15 olle 33   {
3652 08 Dec 15 olle 34     // Step 1
3652 08 Dec 15 olle 35     Events.addEventHandler('step-1', 'wizard-validate', inspectstartplate.validateStep1);
3652 08 Dec 15 olle 36
3652 08 Dec 15 olle 37     // Step 2
3652 08 Dec 15 olle 38     Events.addEventHandler('step-2', 'wizard-initialize', inspectstartplate.initializeStep2);
3652 08 Dec 15 olle 39     Events.addEventHandler('step-2', 'wizard-validate', inspectstartplate.validateStep2);
3652 08 Dec 15 olle 40
3652 08 Dec 15 olle 41 /*
3652 08 Dec 15 olle 42     Events.addEventHandler('plateName', 'change', inspectstartplate.plateNameOnChange);
3652 08 Dec 15 olle 43     Events.addEventHandler('pool_schema', 'change', inspectstartplate.poolSchemaOnChange);
3652 08 Dec 15 olle 44     Events.addEventHandler('barcode_variant', 'change', inspectstartplate.barcodeVariantOnChange);
3652 08 Dec 15 olle 45 */
3652 08 Dec 15 olle 46     Events.addEventHandler('min_vol_dna', 'change', inspectstartplate.minVolDnaOnChange);
3652 08 Dec 15 olle 47     Events.addEventHandler('min_vol_dna', 'keypress', Events.numberOnly);
3652 08 Dec 15 olle 48     
3652 08 Dec 15 olle 49     //Events.addEventHandler('warning_quantity', 'change', inspectstartplate.warningLevelOnChange);
3652 08 Dec 15 olle 50     Events.addEventHandler('warning_quality_score', 'change', inspectstartplate.warningLevelOnChange);
3652 08 Dec 15 olle 51     //Events.addEventHandler('warning_quantity', 'keypress', Events.numberOnly);
3652 08 Dec 15 olle 52     Events.addEventHandler('warning_quality_score', 'keypress', Events.numberOnly);
3652 08 Dec 15 olle 53     
3652 08 Dec 15 olle 54     Events.addEventHandler('location', 'click', inspectstartplate.toggleInfo);
3652 08 Dec 15 olle 55     Events.addEventHandler('quantity', 'click', inspectstartplate.toggleInfo);
3652 08 Dec 15 olle 56     Events.addEventHandler('quality-score', 'click', inspectstartplate.toggleInfo);
3652 08 Dec 15 olle 57     Events.addEventHandler('qubitconc', 'click', inspectstartplate.toggleInfo);
3652 08 Dec 15 olle 58     Events.addEventHandler('volumes', 'click', inspectstartplate.toggleInfo);
3652 08 Dec 15 olle 59 /*
3652 08 Dec 15 olle 60     Events.addEventHandler('qiacube-date', 'click', inspectstartplate.toggleInfo);
3652 08 Dec 15 olle 61 */
3652 08 Dec 15 olle 62     
3652 08 Dec 15 olle 63     Events.addEventHandler('pool-row', 'click', inspectstartplate.togglePool);
3652 08 Dec 15 olle 64     Events.addEventHandler('pool-row', 'mouseover', inspectstartplate.highlightPool);
3652 08 Dec 15 olle 65     Events.addEventHandler('pool-row', 'mouseout', inspectstartplate.highlightPool);
3652 08 Dec 15 olle 66
3652 08 Dec 15 olle 67     Buttons.addClickHandler('downloadLibPrepFile', inspectstartplate.downloadLibPrepFile);
3652 08 Dec 15 olle 68
3652 08 Dec 15 olle 69     Events.addEventHandler('iconSpecialSelect', 'click', inspectstartplate.toggleSpecialSelect);
3652 08 Dec 15 olle 70     Events.addEventHandler('plate', 'mouseup', inspectstartplate.contextEvent);
3652 08 Dec 15 olle 71     Events.addEventHandler('plate', 'contextmenu', inspectstartplate.contextEvent);
3652 08 Dec 15 olle 72     Events.addEventHandler('mnuComment', 'click', inspectstartplate.commentSelected);
3652 08 Dec 15 olle 73     Events.addEventHandler('mnuCaseSummary', 'click', inspectstartplate.showCaseSummary);
3652 08 Dec 15 olle 74
3652 08 Dec 15 olle 75     Events.addEventHandler('flaggedDna', 'click', inspectstartplate.showFlaggedDna);
3652 08 Dec 15 olle 76
3685 12 Jan 16 olle 77     Events.addEventHandler('listview', 'click', inspectstartplate.viewProtocol);
3685 12 Jan 16 olle 78     Events.addEventHandler('plateview', 'click', inspectstartplate.viewProtocol);
3652 08 Dec 15 olle 79
3652 08 Dec 15 olle 80     // Navigation
3652 08 Dec 15 olle 81     Buttons.addClickHandler('gocancel', Wizard.cancelWizard);
3652 08 Dec 15 olle 82     Buttons.addClickHandler('gonext', Wizard.goNextOnClick);
3652 08 Dec 15 olle 83     Buttons.addClickHandler('gocreate', inspectstartplate.createProtocol);
3652 08 Dec 15 olle 84
3652 08 Dec 15 olle 85 /*    
3652 08 Dec 15 olle 86     // Final registration
3652 08 Dec 15 olle 87     Events.addEventHandler('wizard', 'wizard-submit', inspectstartplate.submit);
3652 08 Dec 15 olle 88 */
3652 08 Dec 15 olle 89
3652 08 Dec 15 olle 90     var isNeoPrep = Data.int('page-data', 'is-neoprep');
3652 08 Dec 15 olle 91
3652 08 Dec 15 olle 92     var url = '../Dna.servlet?ID='+App.getSessionId();
3652 08 Dec 15 olle 93     url += '&cmd=GetStartPlates';
3652 08 Dec 15 olle 94     url += '&bioPlateType=' + (isNeoPrep ? 'NEOPREP' : 'DNA');
3652 08 Dec 15 olle 95     url += '&bioPlatePrefix=' + 'LP';
3652 08 Dec 15 olle 96     url += '&orderDesc=true';
3652 08 Dec 15 olle 97     Wizard.showLoadingAnimation('Loading '+(isNeoPrep ? 'NeoPrep' : 'DNA') + ' plates');
3652 08 Dec 15 olle 98     Wizard.asyncJsonRequest(url, inspectstartplate.initializeStep1);
3652 08 Dec 15 olle 99   }
3652 08 Dec 15 olle 100
3652 08 Dec 15 olle 101   inspectstartplate.initializeStep1 = function(response)
3652 08 Dec 15 olle 102   {
3652 08 Dec 15 olle 103     var frm = document.forms['meludi'];
3652 08 Dec 15 olle 104     var jsonPlates = response.bioplates;
3652 08 Dec 15 olle 105
3652 08 Dec 15 olle 106     var startPlate = frm.startPlate;
3652 08 Dec 15 olle 107     if (jsonPlates.length > 0)
3652 08 Dec 15 olle 108     {
3652 08 Dec 15 olle 109       for (var i=0; i < jsonPlates.length; i++)
3652 08 Dec 15 olle 110       {
3652 08 Dec 15 olle 111         var plate = jsonPlates[i];
3652 08 Dec 15 olle 112         var name = (i+1) + ': ' + Strings.encodeTags(plate.name);
3678 18 Dec 15 olle 113         if (plate.numMeludiItems || plate.numExtraItems)
3652 08 Dec 15 olle 114         {
3652 08 Dec 15 olle 115           name += ' -- (';
3652 08 Dec 15 olle 116           name += plate.numMeludiItems;
3652 08 Dec 15 olle 117           name += ' + ' + plate.numExtraItems;
3652 08 Dec 15 olle 118           name += ')';
3652 08 Dec 15 olle 119         }
3652 08 Dec 15 olle 120         if (plate.registrationDate)
3652 08 Dec 15 olle 121         {
3652 08 Dec 15 olle 122           name += ' -- [' + inspectstartplate.asDate(plate.registrationDate) + ']';
3652 08 Dec 15 olle 123         }
3652 08 Dec 15 olle 124         var selected = (i == 0);
3652 08 Dec 15 olle 125         var option = new Option(name, plate.id, selected, selected);
3652 08 Dec 15 olle 126         option.plate = plate;
3652 08 Dec 15 olle 127         startPlate.options[startPlate.length] = option;
3652 08 Dec 15 olle 128       }
3652 08 Dec 15 olle 129       startPlate.options[0].selected = true;
3652 08 Dec 15 olle 130     }
3652 08 Dec 15 olle 131     else
3652 08 Dec 15 olle 132     {
3652 08 Dec 15 olle 133       Wizard.setFatalError('No start plates available.');
3652 08 Dec 15 olle 134       return;
3652 08 Dec 15 olle 135     }
3652 08 Dec 15 olle 136     Doc.show('step-1');
3652 08 Dec 15 olle 137     Doc.show('gocancel');
3652 08 Dec 15 olle 138     Doc.show('gonext');
3652 08 Dec 15 olle 139     Doc.hide('gocreate');
3652 08 Dec 15 olle 140     Doc.hide('extractSourceItems');
3652 08 Dec 15 olle 141   }
3652 08 Dec 15 olle 142
3652 08 Dec 15 olle 143   inspectstartplate.validateStep1 = function(event)
3652 08 Dec 15 olle 144   {
3652 08 Dec 15 olle 145     var frm = document.forms['meludi'];
3652 08 Dec 15 olle 146     var startPlate = null;
3652 08 Dec 15 olle 147     for (var i = 0; i < frm.startPlate.length; i++)
3652 08 Dec 15 olle 148     {
3652 08 Dec 15 olle 149       if (frm.startPlate[i].selected)
3652 08 Dec 15 olle 150       {
3652 08 Dec 15 olle 151         startPlate = frm.startPlate[i];
3652 08 Dec 15 olle 152       }
3652 08 Dec 15 olle 153     }
3652 08 Dec 15 olle 154     if (startPlate == null)
3652 08 Dec 15 olle 155     {
3652 08 Dec 15 olle 156       event.preventDefault();
3652 08 Dec 15 olle 157     }
3652 08 Dec 15 olle 158   }
3652 08 Dec 15 olle 159   
3652 08 Dec 15 olle 160   inspectstartplate.initializeStep2 = function(event)
3652 08 Dec 15 olle 161   {
3652 08 Dec 15 olle 162     var frm = document.forms['meludi'];
3652 08 Dec 15 olle 163     var isNeoPrep = Data.int('page-data', 'is-neoprep');
3652 08 Dec 15 olle 164
3652 08 Dec 15 olle 165     var jsonPlate = null;
3652 08 Dec 15 olle 166     for (var i = 0; i < frm.startPlate.length; i++)
3652 08 Dec 15 olle 167     {
3652 08 Dec 15 olle 168       if (frm.startPlate[i].selected)
3652 08 Dec 15 olle 169       {
3652 08 Dec 15 olle 170         jsonPlate = frm.startPlate[i];
3652 08 Dec 15 olle 171       }
3652 08 Dec 15 olle 172     }
3652 08 Dec 15 olle 173     if (jsonPlate == null)
3652 08 Dec 15 olle 174     {
3652 08 Dec 15 olle 175       event.preventDefault();
3652 08 Dec 15 olle 176     }
3652 08 Dec 15 olle 177     var startPlate = jsonPlate.plate;
3652 08 Dec 15 olle 178
3652 08 Dec 15 olle 179     frm.startPlate.disabled = true;
3652 08 Dec 15 olle 180
3652 08 Dec 15 olle 181     Wizard.setCurrentStep(2);
3652 08 Dec 15 olle 182     Doc.show('step-2');
3652 08 Dec 15 olle 183     Doc.show('gocancel');
3652 08 Dec 15 olle 184     Doc.hide('gonext');
3652 08 Dec 15 olle 185
3652 08 Dec 15 olle 186     Plate.name = startPlate.name;
3652 08 Dec 15 olle 187     var protocolName = startPlate.protocolName;
3652 08 Dec 15 olle 188     var kitName = startPlate.kitName;
3652 08 Dec 15 olle 189     var comment = startPlate.comments;
3652 08 Dec 15 olle 190     var wellsInfo = startPlate.wells;
3652 08 Dec 15 olle 191
3652 08 Dec 15 olle 192     frm.plateName.value = Strings.encodeTags(Plate.name);
3652 08 Dec 15 olle 193     frm.plateName.disabled = true;
3652 08 Dec 15 olle 194     plateNameIsValid = true;
3652 08 Dec 15 olle 195     Wizard.setInputStatus('plateName', 'valid');
3652 08 Dec 15 olle 196
3652 08 Dec 15 olle 197     frm.libraryPreparationProtocol.value = protocolName;
3652 08 Dec 15 olle 198     frm.libraryPreparationProtocol.disabled = true;
3652 08 Dec 15 olle 199     //
3652 08 Dec 15 olle 200     frm.tsLibPrepKit.value = kitName;
3652 08 Dec 15 olle 201     frm.tsLibPrepKit.disabled = true;
3652 08 Dec 15 olle 202     frm.hiddenLibPrepKitId.value = startPlate.kitId;
3652 08 Dec 15 olle 203
3652 08 Dec 15 olle 204     frm.comments.value = comment;
3652 08 Dec 15 olle 205     frm.comments.disabled = true;
3652 08 Dec 15 olle 206     
3652 08 Dec 15 olle 207     // Place pre-selected DNA on plate
3652 08 Dec 15 olle 208     inspectstartplate.quantityOnChange();
3652 08 Dec 15 olle 209     inspectstartplate.warningLevelOnChange();
3652 08 Dec 15 olle 210     
3652 08 Dec 15 olle 211     // Init plate, pool schema and barcode variants
3652 08 Dec 15 olle 212     graphics = new jsGraphics(Doc.element('canvas'));
3652 08 Dec 15 olle 213     pen = new jsPen(new jsColor('#2288AA'), 2);
3652 08 Dec 15 olle 214     var columns = isNeoPrep ? 2 : 12;
3652 08 Dec 15 olle 215     var rows = 8;
3652 08 Dec 15 olle 216     // Disable pool schema menu
3652 08 Dec 15 olle 217     frm.pool_schema.disabled = true;
3652 08 Dec 15 olle 218     var schema = PoolSchema.initList(frm.pool_schema, null, isNeoPrep ? 'neoprep' : 'manual');
3652 08 Dec 15 olle 219     Plate.init(rows, columns, schema, WellPainter);
3652 08 Dec 15 olle 220     Events.sendChangeEvent(frm.pool_schema);
3652 08 Dec 15 olle 221     // Set default for showing info for plate well
3652 08 Dec 15 olle 222     inspectstartplate.setDefaultInfo('location');
3652 08 Dec 15 olle 223     inspectstartplate.setDefaultInfo('volumes');
3652 08 Dec 15 olle 224     inspectstartplate.setDefaultInfo('quality-score');
3652 08 Dec 15 olle 225     inspectstartplate.setDefaultInfo('qubitconc');
3652 08 Dec 15 olle 226
3693 15 Jan 16 olle 227     // Fill plate wells with well data for selected start plate
3693 15 Jan 16 olle 228     for (var column = 0; column < 12; column++)
3652 08 Dec 15 olle 229     {
3652 08 Dec 15 olle 230       for (var row = 0; row < 8; row++)
3652 08 Dec 15 olle 231       {
3652 08 Dec 15 olle 232         var wellStr = inspectstartplate.wellRowColumnToWellStr(row, column);
3693 15 Jan 16 olle 233         // Get well info from start plate
3652 08 Dec 15 olle 234         var wellInfo = wellsInfo[wellStr];
3652 08 Dec 15 olle 235         if (wellInfo)
3652 08 Dec 15 olle 236         {        
3652 08 Dec 15 olle 237           var well = Plate.getWell(row, column);
3667 15 Dec 15 olle 238           var parentName = wellInfo.extract.origName;
3652 08 Dec 15 olle 239           well.extract = wellInfo.extract;
3693 15 Jan 16 olle 240           var dnaId = wellInfo.extract.id;
3652 08 Dec 15 olle 241           // Create a new DNA object
3693 15 Jan 16 olle 242           //var dna = Dna.createByName(name);
3693 15 Jan 16 olle 243           var dnaExt = '.fpa';
3693 15 Jan 16 olle 244           if (column >= 6)
3693 15 Jan 16 olle 245           {
3693 15 Jan 16 olle 246             dnaExt = '.fpb';
3693 15 Jan 16 olle 247           }
3693 15 Jan 16 olle 248           var dna = Dna.createByParentName(parentName, parentName + dnaExt, dnaId);
3652 08 Dec 15 olle 249           Dna.unflag(dna);
3652 08 Dec 15 olle 250           well.setExtract(dna);
3652 08 Dec 15 olle 251           well.selected = false;
3652 08 Dec 15 olle 252         }
3652 08 Dec 15 olle 253       }
3652 08 Dec 15 olle 254     }  
3652 08 Dec 15 olle 255     Plate.checkReplicates();
3652 08 Dec 15 olle 256     Plate.paint(Plate.getWells());
3652 08 Dec 15 olle 257     inspectstartplate.updateNumFlaggedDna();
3652 08 Dec 15 olle 258     names = [];
3652 08 Dec 15 olle 259     //
3652 08 Dec 15 olle 260     Doc.show('step-3');
3652 08 Dec 15 olle 261     Doc.show('gocancel');
3652 08 Dec 15 olle 262     Doc.show('gocreate');
3652 08 Dec 15 olle 263     Wizard.setNoConfirmOnFirstStep(false);
3652 08 Dec 15 olle 264     Wizard.keepSessionAlive();
3652 08 Dec 15 olle 265   }
3652 08 Dec 15 olle 266
3652 08 Dec 15 olle 267   inspectstartplate.wellStrToRow = function(wellStr)
3652 08 Dec 15 olle 268   {
3652 08 Dec 15 olle 269     // Get first letter
3652 08 Dec 15 olle 270     var rowStr = wellStr.substring(0,1);
3652 08 Dec 15 olle 271     var row = jsonRowIndex[rowStr];
3652 08 Dec 15 olle 272     return row;
3652 08 Dec 15 olle 273   }
3652 08 Dec 15 olle 274
3652 08 Dec 15 olle 275   inspectstartplate.wellStrToCol = function(wellStr)
3652 08 Dec 15 olle 276   {
3652 08 Dec 15 olle 277     // Get column string;
3652 08 Dec 15 olle 278     var colStr = wellStr.substring(1,3);
3652 08 Dec 15 olle 279     var col = jsonColIndex[colStr];
3652 08 Dec 15 olle 280     return col;
3652 08 Dec 15 olle 281   }
3652 08 Dec 15 olle 282
3652 08 Dec 15 olle 283   inspectstartplate.wellRowColumnToWellStr = function(row, column)
3652 08 Dec 15 olle 284   {
3652 08 Dec 15 olle 285     // Get well string (row letter + column number, 1-based)
3652 08 Dec 15 olle 286     var wellStr = jsonRowLetter[row] + jsonColNumber[column];
3652 08 Dec 15 olle 287     return wellStr;
3652 08 Dec 15 olle 288   }
3652 08 Dec 15 olle 289
3652 08 Dec 15 olle 290   inspectstartplate.plateNameOnChange = function(event)
3652 08 Dec 15 olle 291   {
3652 08 Dec 15 olle 292     var frm = document.forms['meludi'];
3652 08 Dec 15 olle 293     plateNameIsValid = false;
3652 08 Dec 15 olle 294     
3652 08 Dec 15 olle 295     var name = frm.plateName.value;
3652 08 Dec 15 olle 296     if (!name || name == '')
3652 08 Dec 15 olle 297     {
3652 08 Dec 15 olle 298       Wizard.setInputStatus('plateName', 'invalid', 'Missing name');
3652 08 Dec 15 olle 299       return;
3652 08 Dec 15 olle 300     }
3652 08 Dec 15 olle 301     if (name.indexOf("LP") != 0)
3652 08 Dec 15 olle 302     {
3652 08 Dec 15 olle 303       Wizard.setInputStatus('plateName', 'invalid', 'Plate name must start with prefix "LP"');
3652 08 Dec 15 olle 304       return;
3652 08 Dec 15 olle 305     }
3652 08 Dec 15 olle 306     if (name.length != 7)
3652 08 Dec 15 olle 307     {
3652 08 Dec 15 olle 308       Wizard.setInputStatus('plateName', 'invalid', 'Plate name must consist of "LP" + 5 digits');
3652 08 Dec 15 olle 309       return;
3652 08 Dec 15 olle 310     }
3652 08 Dec 15 olle 311     
3652 08 Dec 15 olle 312     // Check if name exists
3652 08 Dec 15 olle 313     var url = '../Extraction.servlet?ID='+App.getSessionId();
3652 08 Dec 15 olle 314     url += '&cmd=CheckIfStartPlateNameUsed';
3652 08 Dec 15 olle 315     url += '&startPlateName=' + encodeURIComponent(name);
3652 08 Dec 15 olle 316     
3652 08 Dec 15 olle 317     Wizard.showLoadingAnimation('Loading information about plate...');
3652 08 Dec 15 olle 318     Wizard.asyncJsonRequest(url, inspectstartplate.plateInfoLoaded);
3652 08 Dec 15 olle 319   }
3652 08 Dec 15 olle 320
3652 08 Dec 15 olle 321   inspectstartplate.plateInfoLoaded = function(response)
3652 08 Dec 15 olle 322   {
3652 08 Dec 15 olle 323     var frm = document.forms['meludi'];  
3652 08 Dec 15 olle 324     var plateInfo = response.startplate;
3652 08 Dec 15 olle 325     if (plateInfo)
3652 08 Dec 15 olle 326     {
3652 08 Dec 15 olle 327       var plateName = plateInfo.name;
3652 08 Dec 15 olle 328       var plateId = plateInfo.id;
3652 08 Dec 15 olle 329
3652 08 Dec 15 olle 330       if (plateId)
3652 08 Dec 15 olle 331       {
3652 08 Dec 15 olle 332         plateNameIsValid = false;
3652 08 Dec 15 olle 333         Wizard.setInputStatus('plateName', 'invalid', 'Plate already exists with name "' + plateName + '" (ID = ' + plateId + ')');
3652 08 Dec 15 olle 334         return;
3652 08 Dec 15 olle 335       }
3652 08 Dec 15 olle 336     }
3652 08 Dec 15 olle 337     plateNameIsValid = true;
3685 12 Jan 16 olle 338     Plate.name = plateInfo.name;
3652 08 Dec 15 olle 339     
3652 08 Dec 15 olle 340     Wizard.setInputStatus('plateName', 'valid');
3652 08 Dec 15 olle 341   }
3652 08 Dec 15 olle 342
3652 08 Dec 15 olle 343   inspectstartplate.quantityOnChange = function(event)
3652 08 Dec 15 olle 344   {
3652 08 Dec 15 olle 345     var frm = document.forms['meludi'];
3652 08 Dec 15 olle 346     quantitiesAreValid = false;
3652 08 Dec 15 olle 347
3652 08 Dec 15 olle 348 /*    
3652 08 Dec 15 olle 349     var qRegular = parseFloat(frm.quantity_regular.value);
3652 08 Dec 15 olle 350     if (!(qRegular > 0))
3652 08 Dec 15 olle 351     {
3652 08 Dec 15 olle 352       Wizard.setInputStatus('quantities', 'invalid', 'Amount must be ≥ 0.');
3652 08 Dec 15 olle 353       return;
3652 08 Dec 15 olle 354     }
3652 08 Dec 15 olle 355 */
3652 08 Dec 15 olle 356 /*
3652 08 Dec 15 olle 357     var qQc = parseFloat(frm.quantity_qc.value);
3652 08 Dec 15 olle 358     if (!(qQc > qRegular))
3652 08 Dec 15 olle 359     {
3652 08 Dec 15 olle 360       Wizard.setInputStatus('quantities', 'invalid', 'Amount QC must be &gt; ' + qRegular + '.');
3652 08 Dec 15 olle 361       return;
3652 08 Dec 15 olle 362     }
3652 08 Dec 15 olle 363 */
3652 08 Dec 15 olle 364     
3652 08 Dec 15 olle 365     quantitiesAreValid = true;
3652 08 Dec 15 olle 366 /*
3652 08 Dec 15 olle 367     QUANTITY_REGULAR = qRegular;
3652 08 Dec 15 olle 368 */
3652 08 Dec 15 olle 369 /*
3652 08 Dec 15 olle 370     QUANTITY_QC = qQc;
3652 08 Dec 15 olle 371 */
3652 08 Dec 15 olle 372
3652 08 Dec 15 olle 373 /*    
3652 08 Dec 15 olle 374     Wizard.setInputStatus('quantities', 'valid');
3652 08 Dec 15 olle 375 */
3652 08 Dec 15 olle 376     if (event) Plate.paint(Plate.getWells());
3652 08 Dec 15 olle 377   }
3652 08 Dec 15 olle 378
3652 08 Dec 15 olle 379   inspectstartplate.minVolDnaOnChange = function(event)
3652 08 Dec 15 olle 380   {
3652 08 Dec 15 olle 381     var frm = document.forms['meludi'];
3652 08 Dec 15 olle 382     quantitiesAreValid = false;
3652 08 Dec 15 olle 383     
3652 08 Dec 15 olle 384     var minVolDna = parseFloat(frm.min_vol_dna.value);
3652 08 Dec 15 olle 385     if (!(minVolDna > 0))
3652 08 Dec 15 olle 386     {
3652 08 Dec 15 olle 387       Wizard.setInputStatus('min_vol_dna', 'invalid', 'Amount must be ≥ 0.');
3652 08 Dec 15 olle 388       return;
3652 08 Dec 15 olle 389     }
3652 08 Dec 15 olle 390     
3652 08 Dec 15 olle 391     quantitiesAreValid = true;
3652 08 Dec 15 olle 392     MINIMAL_DNA_VOLUME = minVolDna;
3652 08 Dec 15 olle 393     
3652 08 Dec 15 olle 394     Wizard.setInputStatus('min_vol_dna', 'valid');
3652 08 Dec 15 olle 395     if (event) Plate.paint(Plate.getWells());
3652 08 Dec 15 olle 396   }
3652 08 Dec 15 olle 397
3652 08 Dec 15 olle 398   inspectstartplate.warningLevelOnChange = function(event)
3652 08 Dec 15 olle 399   {
3652 08 Dec 15 olle 400     var frm = document.forms['meludi'];
3652 08 Dec 15 olle 401
3652 08 Dec 15 olle 402 /*
3652 08 Dec 15 olle 403     var wQuantity = parseFloat(frm.warning_quantity.value);
3652 08 Dec 15 olle 404     if (!(wQuantity > 0))
3652 08 Dec 15 olle 405     {
3652 08 Dec 15 olle 406       Wizard.setInputStatus('warnings', 'invalid', 'Remaining quantity must be ≥ 0.');
3652 08 Dec 15 olle 407       return;
3652 08 Dec 15 olle 408     }
3652 08 Dec 15 olle 409 */
3652 08 Dec 15 olle 410     var wQualityScore = parseFloat(frm.warning_quality_score.value);
3652 08 Dec 15 olle 411
3652 08 Dec 15 olle 412 /*    
3652 08 Dec 15 olle 413     LOW_QUANTITY_WARNING_LIMIT = wQuantity;
3652 08 Dec 15 olle 414 */
3652 08 Dec 15 olle 415     QUALITY_SCORE_WARNING_LIMIT = wQualityScore;
3652 08 Dec 15 olle 416     
3652 08 Dec 15 olle 417     Wizard.setInputStatus('warnings', 'valid');
3652 08 Dec 15 olle 418     if (event) Plate.paint(Plate.getWells());
3652 08 Dec 15 olle 419   }
3652 08 Dec 15 olle 420   
3652 08 Dec 15 olle 421   inspectstartplate.poolSchemaOnChange = function()
3652 08 Dec 15 olle 422   {
3652 08 Dec 15 olle 423     var frm = document.forms['meludi'];
3652 08 Dec 15 olle 424     var schema = PoolSchema.getById(frm.pool_schema.value);
3652 08 Dec 15 olle 425     Plate.setPoolSchema(schema);
3652 08 Dec 15 olle 426     
3652 08 Dec 15 olle 427     var isNeoPrep = Data.int('page-data', 'is-neoprep');
3652 08 Dec 15 olle 428     if (isNeoPrep)
3652 08 Dec 15 olle 429     {
3652 08 Dec 15 olle 430       PoolSchema.buildPoolTableRow(schema, Plate.columns, true, '<td class="barcode-fill barcode-left"></td>', '<th></th><td class="barcode-fill barcode-right"></td>');
3652 08 Dec 15 olle 431       PoolSchema.initVariantList(frm.barcode_variant, schema);
3652 08 Dec 15 olle 432       Events.sendChangeEvent(frm.barcode_variant);
3652 08 Dec 15 olle 433     }
3652 08 Dec 15 olle 434     else
3652 08 Dec 15 olle 435     {
3652 08 Dec 15 olle 436       PoolSchema.buildPoolTableRow(schema, Plate.columns, true);
3652 08 Dec 15 olle 437       Plate.paint(Plate.getWells());
3652 08 Dec 15 olle 438     }
3652 08 Dec 15 olle 439   }
3652 08 Dec 15 olle 440   
3652 08 Dec 15 olle 441   inspectstartplate.barcodeVariantOnChange = function()
3652 08 Dec 15 olle 442   {
3652 08 Dec 15 olle 443     var frm = document.forms['meludi'];
3652 08 Dec 15 olle 444     var schema = PoolSchema.getById(frm.pool_schema.value);
3652 08 Dec 15 olle 445     var barcodeVariant = PoolSchema.getBarcodeVariantByName(schema, frm.barcode_variant.value);
3652 08 Dec 15 olle 446     
3652 08 Dec 15 olle 447     inspectstartplate.assignSchemaDefinedBarcodeVariant(schema, barcodeVariant);
3652 08 Dec 15 olle 448     WellPainter.barcodeVariant = barcodeVariant;
3652 08 Dec 15 olle 449     Plate.paint(Plate.getWells());
3652 08 Dec 15 olle 450   }
3652 08 Dec 15 olle 451
3652 08 Dec 15 olle 452   inspectstartplate.assignSchemaDefinedBarcodeVariant = function(schema, barcodeVariant)
3652 08 Dec 15 olle 453   {
3652 08 Dec 15 olle 454     var wells = Plate.getWells();
3652 08 Dec 15 olle 455     for (var i = 0; i < wells.length; i++)
3652 08 Dec 15 olle 456     {
3652 08 Dec 15 olle 457       var well = wells[i];
3652 08 Dec 15 olle 458
3652 08 Dec 15 olle 459       var indexSet = barcodeVariant ? barcodeVariant.indexSets[well.column] : null;
3652 08 Dec 15 olle 460       var barcode = null;
3652 08 Dec 15 olle 461       if (indexSet)
3652 08 Dec 15 olle 462       {
3652 08 Dec 15 olle 463         var barcodeName = indexSet.barcodes[well.row];
3652 08 Dec 15 olle 464         barcode = barcodesByName[barcodeName];
3652 08 Dec 15 olle 465       }
3652 08 Dec 15 olle 466       well.barcode = barcode;
3652 08 Dec 15 olle 467       well.defaultBarcode = barcode;
3652 08 Dec 15 olle 468       well.duplicate = false;
3652 08 Dec 15 olle 469     }
3652 08 Dec 15 olle 470   }
3652 08 Dec 15 olle 471
3652 08 Dec 15 olle 472   var currentWell;
3652 08 Dec 15 olle 473   var lastSelectedBarcode;
3652 08 Dec 15 olle 474   inspectstartplate.selectBarcode = function(event)
3652 08 Dec 15 olle 475   {
3652 08 Dec 15 olle 476     var row = Data.int(event.currentTarget, 'row');
3652 08 Dec 15 olle 477     var column = Data.int(event.currentTarget, 'col');
3652 08 Dec 15 olle 478
3652 08 Dec 15 olle 479     // Locate the barcode selection div so that the current
3652 08 Dec 15 olle 480     // barcode is positioned next to the current mouse position
3652 08 Dec 15 olle 481     // Initially set it to the right of the mouse so that the
3652 08 Dec 15 olle 482     // center is vertically aligned
3652 08 Dec 15 olle 483     currentWell = Plate.getWell(row, column);
3652 08 Dec 15 olle 484     var scroll = 0;
3652 08 Dec 15 olle 485
3652 08 Dec 15 olle 486     // Reset 'current' selection
3652 08 Dec 15 olle 487     var menu = Doc.element('select-barcode');
3652 08 Dec 15 olle 488     var selectAll = Doc.element('select-barcode-all');
3652 08 Dec 15 olle 489     for (var i = 0; i <  selectAll.childNodes.length; i++)
3652 08 Dec 15 olle 490     {
3652 08 Dec 15 olle 491       Doc.removeClass(selectAll.childNodes[i], 'current');
3652 08 Dec 15 olle 492     }
3652 08 Dec 15 olle 493     menu.style.display = 'block';
3652 08 Dec 15 olle 494
3652 08 Dec 15 olle 495     var x = event.clientX+1;
3652 08 Dec 15 olle 496     var halfHeight = Math.floor(selectAll.offsetHeight/2)
3652 08 Dec 15 olle 497     var y = event.clientY-halfHeight;
3652 08 Dec 15 olle 498     var scroll = 0;
3652 08 Dec 15 olle 499     var barcodeDiv;
3652 08 Dec 15 olle 500     
3652 08 Dec 15 olle 501     var useBarcode = currentWell.barcode || lastSelectedBarcode;
3652 08 Dec 15 olle 502     if (useBarcode)
3652 08 Dec 15 olle 503     {
3652 08 Dec 15 olle 504       var barcodeDiv = Doc.element('bc-'+useBarcode.id);
3652 08 Dec 15 olle 505       if (!currentWell.barcode && barcodeDiv.nextSibling) barcodeDiv = barcodeDiv.nextSibling;
3652 08 Dec 15 olle 506       // Try to scroll the current barcode so that it's baseline is at the center of the div
3652 08 Dec 15 olle 507       scroll = barcodeDiv.offsetTop + barcodeDiv.offsetHeight - halfHeight;
3652 08 Dec 15 olle 508       if (scroll < 0) 
3652 08 Dec 15 olle 509       {
3652 08 Dec 15 olle 510         // We get a negative scroll for the first few elements, shift the
3652 08 Dec 15 olle 511         // entire selection div down instead
3652 08 Dec 15 olle 512         y -= scroll;
3652 08 Dec 15 olle 513         scroll = 0;
3652 08 Dec 15 olle 514       }
3652 08 Dec 15 olle 515       else if (scroll > selectAll.scrollHeight - selectAll.offsetHeight)
3652 08 Dec 15 olle 516       {
3652 08 Dec 15 olle 517         // We get a too large scroll value for the last few elements, shift
3652 08 Dec 15 olle 518         // the entire selection div up instead
3652 08 Dec 15 olle 519         y -= scroll - (selectAll.scrollHeight - selectAll.offsetHeight);
3652 08 Dec 15 olle 520         scroll = selectAll.scrollHeight - selectAll.offsetHeight;
3652 08 Dec 15 olle 521       }
3652 08 Dec 15 olle 522       if (currentWell.barcode)
3652 08 Dec 15 olle 523       {
3652 08 Dec 15 olle 524         Doc.addClass(barcodeDiv, 'current');
3652 08 Dec 15 olle 525       }
3652 08 Dec 15 olle 526     }
3652 08 Dec 15 olle 527     
3652 08 Dec 15 olle 528     // Default barcode
3652 08 Dec 15 olle 529     if (currentWell.defaultBarcode && currentWell.defaultBarcode != currentWell.barcode)
3652 08 Dec 15 olle 530     {
3652 08 Dec 15 olle 531       var selectDefault = Doc.element('select-barcode-default');
3652 08 Dec 15 olle 532       Data.set(selectDefault, 'barcode-name', currentWell.defaultBarcode.name);
3652 08 Dec 15 olle 533       selectDefault.innerHTML = 'Default: ' + Strings.encodeTags(currentWell.defaultBarcode.name);
3652 08 Dec 15 olle 534       Doc.show('select-barcode-default');
3652 08 Dec 15 olle 535       Doc.show('select-barcode-default-separator');
3652 08 Dec 15 olle 536     }
3652 08 Dec 15 olle 537     else
3652 08 Dec 15 olle 538     {
3652 08 Dec 15 olle 539       Doc.hide('select-barcode-default');
3652 08 Dec 15 olle 540       Doc.hide('select-barcode-default-separator');
3652 08 Dec 15 olle 541     }
3652 08 Dec 15 olle 542     
3652 08 Dec 15 olle 543     // Position the selection div
3652 08 Dec 15 olle 544     selectAll.scrollTop = scroll;
3652 08 Dec 15 olle 545     menu.style.left = (x)+'px';
3652 08 Dec 15 olle 546     menu.style.top = (y)+'px';
3652 08 Dec 15 olle 547     event.stopPropagation();
3652 08 Dec 15 olle 548   }
3652 08 Dec 15 olle 549
3652 08 Dec 15 olle 550   inspectstartplate.barcodeSelected = function(event)
3652 08 Dec 15 olle 551   {
3652 08 Dec 15 olle 552     var frm = document.forms['meludi'];
3652 08 Dec 15 olle 553     var schema = PoolSchema.getById(frm.pool_schema.value);
3652 08 Dec 15 olle 554     var target = event.target;
3652 08 Dec 15 olle 555     if (currentWell)
3652 08 Dec 15 olle 556     {
3652 08 Dec 15 olle 557       lastSelectedBarcode = barcodesByName[Data.get(target, 'barcode-name')];
3652 08 Dec 15 olle 558       currentWell.barcode = lastSelectedBarcode;
3652 08 Dec 15 olle 559       var poolNum = schema.getPoolNumForColumn(currentWell.column);
3652 08 Dec 15 olle 560       inspectstartplate.checkDuplicateBarcode(poolNum);
3652 08 Dec 15 olle 561       Plate.paint(Plate.getWells());
3652 08 Dec 15 olle 562     }
3652 08 Dec 15 olle 563     inspectstartplate.hideBarcodeSelection();
3652 08 Dec 15 olle 564   }
3652 08 Dec 15 olle 565
3652 08 Dec 15 olle 566   inspectstartplate.checkDuplicateBarcode = function(poolNum)
3652 08 Dec 15 olle 567   {
3652 08 Dec 15 olle 568     var frm = document.forms['meludi'];
3652 08 Dec 15 olle 569     var schema = PoolSchema.getById(frm.pool_schema.value);
3652 08 Dec 15 olle 570
3652 08 Dec 15 olle 571     var wells = schema.getWellsInPool(Plate, poolNum);
3652 08 Dec 15 olle 572     var wellByBarcodeName = [];
3652 08 Dec 15 olle 573     for (var i = 0; i < wells.length; i++)
3652 08 Dec 15 olle 574     {
3652 08 Dec 15 olle 575       var well = wells[i];
3652 08 Dec 15 olle 576       if (well.barcode)
3652 08 Dec 15 olle 577       {
3652 08 Dec 15 olle 578         if (wellByBarcodeName[well.barcode.name])
3652 08 Dec 15 olle 579         {
3652 08 Dec 15 olle 580           well.duplicate = true;
3652 08 Dec 15 olle 581           wellByBarcodeName[well.barcode.name].duplicate = true;
3652 08 Dec 15 olle 582         }
3652 08 Dec 15 olle 583         else
3652 08 Dec 15 olle 584         {
3652 08 Dec 15 olle 585           wellByBarcodeName[well.barcode.name] = well;
3652 08 Dec 15 olle 586           well.duplicate = false;
3652 08 Dec 15 olle 587         }
3652 08 Dec 15 olle 588       }
3652 08 Dec 15 olle 589     }
3652 08 Dec 15 olle 590   }
3652 08 Dec 15 olle 591
3652 08 Dec 15 olle 592   
3652 08 Dec 15 olle 593   inspectstartplate.hideBarcodeSelection = function()
3652 08 Dec 15 olle 594   {
3652 08 Dec 15 olle 595     Doc.hide('select-barcode');
3652 08 Dec 15 olle 596   }
3652 08 Dec 15 olle 597
3652 08 Dec 15 olle 598   
3652 08 Dec 15 olle 599   /**
3652 08 Dec 15 olle 600     Sets default display of info data for plate wells,
3652 08 Dec 15 olle 601     based on check box values. Assumes the id of the
3652 08 Dec 15 olle 602     check box in question as input.
3652 08 Dec 15 olle 603   */
3652 08 Dec 15 olle 604   inspectstartplate.setDefaultInfo = function(chkbox)
3652 08 Dec 15 olle 605   {
3652 08 Dec 15 olle 606     var frm = document.forms['meludi'];
3652 08 Dec 15 olle 607     var show = frm[chkbox].checked;
3652 08 Dec 15 olle 608     Doc.addOrRemoveClass('plate', 'hide-'+chkbox, !show);
3652 08 Dec 15 olle 609   }
3652 08 Dec 15 olle 610
3652 08 Dec 15 olle 611   inspectstartplate.toggleInfo = function(event)
3652 08 Dec 15 olle 612   {
3652 08 Dec 15 olle 613     var frm = document.forms['meludi'];
3652 08 Dec 15 olle 614     var show = event.currentTarget.checked;
3652 08 Dec 15 olle 615     Doc.addOrRemoveClass('plate', 'hide-'+event.currentTarget.id, !show);
3667 15 Dec 15 olle 616     if (event.currentTarget.id == 'qubitconc')
3667 15 Dec 15 olle 617     {
3667 15 Dec 15 olle 618       Doc.addOrRemoveClass('plate', 'hide-origqubitconc', !show);
3667 15 Dec 15 olle 619       Doc.addOrRemoveClass('plate', 'hide-calcqubitconc', !show);
3667 15 Dec 15 olle 620     }
3652 08 Dec 15 olle 621     // Re-paint well info to show/hide warnings for target class
3652 08 Dec 15 olle 622     Plate.paint(Plate.getWells());
3652 08 Dec 15 olle 623   }
3652 08 Dec 15 olle 624
3652 08 Dec 15 olle 625   /**
3652 08 Dec 15 olle 626     Open a popup dialog for selecting a data files.
3652 08 Dec 15 olle 627   */
3652 08 Dec 15 olle 628   inspectstartplate.selectFile = function()
3652 08 Dec 15 olle 629   {
3652 08 Dec 15 olle 630     Dialogs.openPopup('select_file.jsp?ID='+App.getSessionId(), 'SelectFile', 600, 400);  
3652 08 Dec 15 olle 631   }
3652 08 Dec 15 olle 632
3652 08 Dec 15 olle 633   /**
3652 08 Dec 15 olle 634     Parse a tab-separated data file. The columns must be in the following order:
3652 08 Dec 15 olle 635     0: DNA name
3652 08 Dec 15 olle 636     1: Row letter (A-H)
3652 08 Dec 15 olle 637     2: Column number (1-12)
3652 08 Dec 15 olle 638     3: QC flag (can be empty)
3652 08 Dec 15 olle 639   */
3652 08 Dec 15 olle 640   inspectstartplate.parseDnaFile = function(data)
3652 08 Dec 15 olle 641   {
3652 08 Dec 15 olle 642     var lines = data.split(/[\n\r]+/);
3652 08 Dec 15 olle 643   
3652 08 Dec 15 olle 644     // Load information about all DNA items in a batch (will improve performance)
3652 08 Dec 15 olle 645     var names = [];
3652 08 Dec 15 olle 646     for (var i = 0; i < lines.length; i++)
3652 08 Dec 15 olle 647     {
3652 08 Dec 15 olle 648       var line = lines[i];
3652 08 Dec 15 olle 649       if (line)
3652 08 Dec 15 olle 650       {
3652 08 Dec 15 olle 651         var cols = lines[i].split(/\t/);
3652 08 Dec 15 olle 652         if (cols.length < 3) throw 'On line '+(i+1)+': Too few columns (' + cols.length + ')';
3652 08 Dec 15 olle 653         names[names.length] = cols[0];
3652 08 Dec 15 olle 654       }
3652 08 Dec 15 olle 655     }
3652 08 Dec 15 olle 656     Dna.loadInfoByNames(names);
3652 08 Dec 15 olle 657     
3652 08 Dec 15 olle 658     // Place DNA on the plate
3652 08 Dec 15 olle 659     var duplicates = [];
3652 08 Dec 15 olle 660     for (var i = 0; i < lines.length; i++)
3652 08 Dec 15 olle 661     {
3652 08 Dec 15 olle 662       var line = lines[i];
3652 08 Dec 15 olle 663       if (line)
3652 08 Dec 15 olle 664       {
3652 08 Dec 15 olle 665         var cols = lines[i].split(/\t/);
3652 08 Dec 15 olle 666   
3652 08 Dec 15 olle 667         //var dna = Dna.createByName(cols[0]);
3652 08 Dec 15 olle 668         var row =  Meludi.alphaToWell(cols[1].toUpperCase());
3652 08 Dec 15 olle 669         var col =  parseInt(cols[2], 10)-1;
3652 08 Dec 15 olle 670
3652 08 Dec 15 olle 671         if (col < 6)
3652 08 Dec 15 olle 672         {        
3652 08 Dec 15 olle 673           var well = Plate.getWell(row, col);
3652 08 Dec 15 olle 674           if (!well) throw 'On line '+(i+1)+': Invalid plate coordinate ['+cols[1]+','+cols[2]+']';
3652 08 Dec 15 olle 675   
3652 08 Dec 15 olle 676           var name = cols[0];
3652 08 Dec 15 olle 677           // Create a new DNA object
3652 08 Dec 15 olle 678           var dna = Dna.createByName(name);
3652 08 Dec 15 olle 679           dna.name = name + '.fpa';
3652 08 Dec 15 olle 680           dna.qc = cols.length >= 4 && (cols[3] && cols[3] != '0');
3652 08 Dec 15 olle 681           Dna.unflag(dna);
3652 08 Dec 15 olle 682         
3652 08 Dec 15 olle 683           // Check for duplicate DNA on same position (which is an error)
3652 08 Dec 15 olle 684           var pos = 'c'+col+'r'+row;
3652 08 Dec 15 olle 685           if (duplicates[pos])
3652 08 Dec 15 olle 686           {
3652 08 Dec 15 olle 687             well.addDuplicate(dna);
3652 08 Dec 15 olle 688           }
3652 08 Dec 15 olle 689           else
3652 08 Dec 15 olle 690           {
3652 08 Dec 15 olle 691             duplicates[pos] = dna.name;
3652 08 Dec 15 olle 692             well.setExtract(dna);
3652 08 Dec 15 olle 693           }
3652 08 Dec 15 olle 694
3652 08 Dec 15 olle 695           // Place FPB sample in corresponding well on right side of plate
3652 08 Dec 15 olle 696           well = Plate.getWell(row, col + 6);
3652 08 Dec 15 olle 697           // Create a new DNA object
3652 08 Dec 15 olle 698           dna = Dna.createByName(name);
3652 08 Dec 15 olle 699           dna.name = name + '.fpb';
3652 08 Dec 15 olle 700           dna.qc = cols.length >= 4 && (cols[3] && cols[3] != '0');
3652 08 Dec 15 olle 701           Dna.unflag(dna);
3652 08 Dec 15 olle 702           well.setExtract(dna);
3652 08 Dec 15 olle 703         }
3652 08 Dec 15 olle 704       }
3652 08 Dec 15 olle 705     }
3652 08 Dec 15 olle 706     
3652 08 Dec 15 olle 707     inspectstartplate.updateNumFlaggedDna();
3652 08 Dec 15 olle 708     
3652 08 Dec 15 olle 709     // Check for replicates on the whole plate and repaint it
3652 08 Dec 15 olle 710     Plate.checkReplicates(null, true);
3652 08 Dec 15 olle 711     Plate.paint(Plate.getWells());
3652 08 Dec 15 olle 712   }
3652 08 Dec 15 olle 713   
3652 08 Dec 15 olle 714   /**
3652 08 Dec 15 olle 715     Open a popup dialog for manual selection of DNA.
3652 08 Dec 15 olle 716   */
3652 08 Dec 15 olle 717   inspectstartplate.manualSelect = function(event)
3652 08 Dec 15 olle 718   {
3652 08 Dec 15 olle 719     currentSelected = Plate.getSelected();
3652 08 Dec 15 olle 720     if (currentSelected.length == 0)
3652 08 Dec 15 olle 721     {
3652 08 Dec 15 olle 722       Forms.showNotification(event.currentTarget, 'Please select one or more wells were DNA should be placed.');
3652 08 Dec 15 olle 723       return;
3652 08 Dec 15 olle 724     }
3652 08 Dec 15 olle 725     
3652 08 Dec 15 olle 726     if (subtypeDna == null) subtypeDna = Meludi.getSubtypeInfo('DNA');
3652 08 Dec 15 olle 727 /*
3652 08 Dec 15 olle 728     if (subtypeDnaNormalized == null) subtypeDnaNormalized = Meludi.getSubtypeInfo('DNA_NORMALIZED_ALIQUOT');
3652 08 Dec 15 olle 729 */
3652 08 Dec 15 olle 730   
3652 08 Dec 15 olle 731     var url = '&resetTemporary=1';
3652 08 Dec 15 olle 732 /*
3652 08 Dec 15 olle 733     url += '&tmpfilter:INT:itemSubtype='+subtypeDna.id+'|'+subtypeDnaNormalized.id;
3652 08 Dec 15 olle 734 */
3652 08 Dec 15 olle 735     url += '&tmpfilter:INT:itemSubtype='+subtypeDna.id;
3652 08 Dec 15 olle 736     url += '&tmpfilter:DATE:creationEvent.eventDate='+encodeURIComponent('<>');
3652 08 Dec 15 olle 737     url += '&tmpfilter:FLOAT:remainingQuantity='+encodeURIComponent('>=1');
3652 08 Dec 15 olle 738     url += '&'+encodeURIComponent('tmpfilter:STRING:&childCreationEvents(event.bioMaterial.name)')+'='+encodeURIComponent('<>%.m');
3652 08 Dec 15 olle 739
3652 08 Dec 15 olle 740     Dialogs.selectItem('EXTRACT', 'plate', 1, url);
3652 08 Dec 15 olle 741   }
3652 08 Dec 15 olle 742
3652 08 Dec 15 olle 743   /**
3652 08 Dec 15 olle 744     Callback method for manual selection.
3652 08 Dec 15 olle 745   */
3652 08 Dec 15 olle 746   inspectstartplate.manuallySelected = function(event)
3652 08 Dec 15 olle 747   {
3652 08 Dec 15 olle 748     names[names.length] = event.detail.name;
3652 08 Dec 15 olle 749     
3652 08 Dec 15 olle 750     if (event.detail.remaining == 0 && names.length > 0)
3652 08 Dec 15 olle 751     {
3652 08 Dec 15 olle 752       Dna.loadInfoByNames(names);
3652 08 Dec 15 olle 753
3652 08 Dec 15 olle 754       var wellsArray = [];
3652 08 Dec 15 olle 755       var numItemsPlaced = names.length;
3652 08 Dec 15 olle 756       if (currentSelected.length < names.length)
3652 08 Dec 15 olle 757       {
3652 08 Dec 15 olle 758         numItemsPlaced = currentSelected.length;
3652 08 Dec 15 olle 759       }
3652 08 Dec 15 olle 760       for (var i = 0; i < numItemsPlaced; i++)
3652 08 Dec 15 olle 761       {
3652 08 Dec 15 olle 762         var well = currentSelected[i];
3652 08 Dec 15 olle 763         wellsArray[i] = well;
3652 08 Dec 15 olle 764         var name = names[i];
3652 08 Dec 15 olle 765 //alert("inspect_start_plate.js::manuallySelected(): currentSelected.length = " + currentSelected.length + " names.legnth = " + names.length + " i = " + i + " name = \"" + name + "\" well = " + JSON.stringify(well));        
3652 08 Dec 15 olle 766         // Create a new DNA object
3652 08 Dec 15 olle 767         var dna = Dna.createByName(name);
3652 08 Dec 15 olle 768         dna.name = name + '.fpa';
3652 08 Dec 15 olle 769         Dna.unflag(dna);
3652 08 Dec 15 olle 770         well.setExtract(dna);
3652 08 Dec 15 olle 771         well.selected = false;
3652 08 Dec 15 olle 772         // Place FPB sample in corresponding well on right side of plate
3652 08 Dec 15 olle 773         var row = well.row;
3652 08 Dec 15 olle 774         var column = well.column;
3652 08 Dec 15 olle 775         well = Plate.getWell(row, column + 6);
3652 08 Dec 15 olle 776         wellsArray[i+numItemsPlaced] = well;
3652 08 Dec 15 olle 777         // Create a new DNA object
3652 08 Dec 15 olle 778         dna = Dna.createByName(name);
3652 08 Dec 15 olle 779         dna.name = name + '.fpb';
3652 08 Dec 15 olle 780         Dna.unflag(dna);
3652 08 Dec 15 olle 781         well.setExtract(dna);
3652 08 Dec 15 olle 782         well.selected = false;
3652 08 Dec 15 olle 783       }
3652 08 Dec 15 olle 784       Plate.checkReplicates();
3652 08 Dec 15 olle 785 /*
3652 08 Dec 15 olle 786       Plate.paint(currentSelected);
3652 08 Dec 15 olle 787 */
3652 08 Dec 15 olle 788       Plate.paint(wellsArray);
3652 08 Dec 15 olle 789       inspectstartplate.updateNumFlaggedDna();
3652 08 Dec 15 olle 790       names = [];
3652 08 Dec 15 olle 791     }
3652 08 Dec 15 olle 792   }
3652 08 Dec 15 olle 793
3652 08 Dec 15 olle 794   
3652 08 Dec 15 olle 795   /**
3652 08 Dec 15 olle 796     Let the wizard automatically select among unprocessed DNA items.
3652 08 Dec 15 olle 797   */  
3652 08 Dec 15 olle 798   inspectstartplate.autoSelect = function(event)
3652 08 Dec 15 olle 799   {
3652 08 Dec 15 olle 800     var frm = document.forms['meludi'];
3652 08 Dec 15 olle 801     var wells = Plate.getWells();
3652 08 Dec 15 olle 802     var selected = [];
3652 08 Dec 15 olle 803     var ignore = [];
3652 08 Dec 15 olle 804     var notEmpty = 0;
3652 08 Dec 15 olle 805     
3652 08 Dec 15 olle 806     // Count selected and non-empty wells and keep track of DNA that is already present
3652 08 Dec 15 olle 807     for (var i = 0; i < wells.length; i++)
3652 08 Dec 15 olle 808     {
3652 08 Dec 15 olle 809       var well = wells[i];
3652 08 Dec 15 olle 810       if (well.selected) 
3652 08 Dec 15 olle 811       {
3652 08 Dec 15 olle 812         selected[selected.length] = well;
3652 08 Dec 15 olle 813         if (well.extract && !well.hasError()) notEmpty++;
3652 08 Dec 15 olle 814       }
3652 08 Dec 15 olle 815       if (well.extract && well.extract.id)
3652 08 Dec 15 olle 816       {
3652 08 Dec 15 olle 817         ignore[ignore.length] = well.extract.id;
3652 08 Dec 15 olle 818       }
3652 08 Dec 15 olle 819     }
3652 08 Dec 15 olle 820     // Ignore DNA already flagged
3652 08 Dec 15 olle 821     var flagged = Dna.getFlagged();
3652 08 Dec 15 olle 822     for (var i = 0; i < flagged.length; i++)
3652 08 Dec 15 olle 823     {
3652 08 Dec 15 olle 824       var dna = flagged[i];
3652 08 Dec 15 olle 825       if (dna.id) ignore[ignore.length] = dna.id;
3652 08 Dec 15 olle 826     }
3652 08 Dec 15 olle 827     
3652 08 Dec 15 olle 828     if (selected.length == 0)
3652 08 Dec 15 olle 829     {
3652 08 Dec 15 olle 830       Forms.showNotification(event.currentTarget, 'Please select one or more wells were DNA should be placed.');
3652 08 Dec 15 olle 831       return;
3652 08 Dec 15 olle 832     }
3652 08 Dec 15 olle 833       
3652 08 Dec 15 olle 834     if (notEmpty > 0)
3652 08 Dec 15 olle 835     {
3652 08 Dec 15 olle 836       if (!confirm('Replace DNA in ' + notEmpty + ' wells?'))
3652 08 Dec 15 olle 837       {
3652 08 Dec 15 olle 838         return;
3652 08 Dec 15 olle 839       }
3652 08 Dec 15 olle 840     }
3652 08 Dec 15 olle 841       
3652 08 Dec 15 olle 842     var url = 'auto_select_dna.jsp?ID='+App.getSessionId();
3652 08 Dec 15 olle 843     url += '&numToSelect='+selected.length;
3652 08 Dec 15 olle 844 /*
3652 08 Dec 15 olle 845     url += '&quantity='+encodeURIComponent(frm.quantity_regular.value);
3652 08 Dec 15 olle 846 */
3652 08 Dec 15 olle 847     url += '&ignore='+ignore.join(',');
3652 08 Dec 15 olle 848     Dialogs.openPopup(url, 'AutoSelectDNA', 750, 500);
3652 08 Dec 15 olle 849   }
3652 08 Dec 15 olle 850
3652 08 Dec 15 olle 851   /**
3652 08 Dec 15 olle 852     Callback function for auto-select.
3652 08 Dec 15 olle 853   */  
3652 08 Dec 15 olle 854   inspectstartplate.dnaSelected = function(response)
3652 08 Dec 15 olle 855   {
3652 08 Dec 15 olle 856     // Cache DNA information
3652 08 Dec 15 olle 857     Dna.cacheInfo(response.dna);
3652 08 Dec 15 olle 858     Dna.cacheInfo(response.flagged);
3652 08 Dec 15 olle 859     
3652 08 Dec 15 olle 860     inspectstartplate.updateNumFlaggedDna();
3652 08 Dec 15 olle 861     var selected = Plate.getSelected();
3652 08 Dec 15 olle 862
3652 08 Dec 15 olle 863 /*
3652 08 Dec 15 olle 864     // Get selected DNA names
3652 08 Dec 15 olle 865     for (var i = 0; i < response.dna.length; i++)
3652 08 Dec 15 olle 866     {
3652 08 Dec 15 olle 867       if (i < selected.length)
3652 08 Dec 15 olle 868       {
3652 08 Dec 15 olle 869         names[i] = response.dna[i].name;
3652 08 Dec 15 olle 870       }
3652 08 Dec 15 olle 871     }
3652 08 Dec 15 olle 872     if (names.length > 0)
3652 08 Dec 15 olle 873     {
3652 08 Dec 15 olle 874       Dna.loadInfoByNames(names);
3652 08 Dec 15 olle 875
3652 08 Dec 15 olle 876       for (var i = 0; i < names.length && i < selected.length; i++)
3652 08 Dec 15 olle 877       {
3652 08 Dec 15 olle 878         var well = selected[i];
3652 08 Dec 15 olle 879         var name = names[i];
3652 08 Dec 15 olle 880         
3652 08 Dec 15 olle 881         // Create a new DNA object
3652 08 Dec 15 olle 882         var dna = Dna.createByName(name);
3652 08 Dec 15 olle 883         Dna.unflag(dna);
3652 08 Dec 15 olle 884         well.setExtract(dna);
3652 08 Dec 15 olle 885         well.selected = false;
3652 08 Dec 15 olle 886       }
3652 08 Dec 15 olle 887       
3652 08 Dec 15 olle 888       Plate.checkReplicates();
3652 08 Dec 15 olle 889       Plate.paint(selected);
3652 08 Dec 15 olle 890       inspectstartplate.updateNumFlaggedDna();
3652 08 Dec 15 olle 891       names = [];
3652 08 Dec 15 olle 892     }
3652 08 Dec 15 olle 893 */
3652 08 Dec 15 olle 894
3652 08 Dec 15 olle 895     var wellsArray = [];      
3652 08 Dec 15 olle 896     for (var i = 0; i < response.dna.length; i++)
3652 08 Dec 15 olle 897     {
3652 08 Dec 15 olle 898       if (i < selected.length)
3652 08 Dec 15 olle 899       {
3652 08 Dec 15 olle 900         var well = selected[i];
3652 08 Dec 15 olle 901         wellsArray[i] = well;
3652 08 Dec 15 olle 902         // Create a new DNA object
3652 08 Dec 15 olle 903         var name = response.dna[i].name;
3652 08 Dec 15 olle 904         var dna = Dna.createByName(name);
3652 08 Dec 15 olle 905         dna.name = name + '.fpa';
3652 08 Dec 15 olle 906         //Dna.unflag(dna);
3652 08 Dec 15 olle 907         well.setExtract(dna);
3652 08 Dec 15 olle 908         well.selected = false;
3652 08 Dec 15 olle 909         // Place FPB sample in corresponding well on right side of plate
3652 08 Dec 15 olle 910         var row = well.row;
3652 08 Dec 15 olle 911         var column = well.column;
3652 08 Dec 15 olle 912         well = Plate.getWell(row, column + 6);
3652 08 Dec 15 olle 913         wellsArray[i+selected.length] = well;
3652 08 Dec 15 olle 914         // Create a new DNA object
3652 08 Dec 15 olle 915         dna = Dna.createByName(name);
3652 08 Dec 15 olle 916         dna.name = name + '.fpb';
3652 08 Dec 15 olle 917         //Dna.unflag(dna);
3652 08 Dec 15 olle 918         well.setExtract(dna);
3652 08 Dec 15 olle 919         well.selected = false;
3652 08 Dec 15 olle 920       }
3652 08 Dec 15 olle 921     }
3652 08 Dec 15 olle 922     // Check for replicates on the whole plate and repaint it
3652 08 Dec 15 olle 923     Plate.checkReplicates(null, true);
3652 08 Dec 15 olle 924     Plate.paint(Plate.getWells());
3652 08 Dec 15 olle 925   }
3652 08 Dec 15 olle 926   
3652 08 Dec 15 olle 927   // Update the 'Flagged DNA' information
3652 08 Dec 15 olle 928   inspectstartplate.updateNumFlaggedDna = function()
3652 08 Dec 15 olle 929   {
3652 08 Dec 15 olle 930     var numFlagged = Dna.getFlagged().length;
3652 08 Dec 15 olle 931     if (numFlagged > 0)
3652 08 Dec 15 olle 932     {
3652 08 Dec 15 olle 933       Doc.element('flaggedDna').innerHTML = numFlagged + ' flagged DNA items.';
3652 08 Dec 15 olle 934       Doc.show('flaggedDna');
3652 08 Dec 15 olle 935     }
3652 08 Dec 15 olle 936     else
3652 08 Dec 15 olle 937     {
3652 08 Dec 15 olle 938       Doc.hide('flaggedDna');
3652 08 Dec 15 olle 939     }
3652 08 Dec 15 olle 940   }
3652 08 Dec 15 olle 941
3652 08 Dec 15 olle 942   /**
3652 08 Dec 15 olle 943     Add 'Stratagene' to the selected wells.
3652 08 Dec 15 olle 944   */
3652 08 Dec 15 olle 945   inspectstartplate.setToStratagene = function(event)
3652 08 Dec 15 olle 946   {
3652 08 Dec 15 olle 947     var frm = document.forms['meludi'];
3652 08 Dec 15 olle 948     inspectstartplate.setToSpecial(event, frm.stratagene.value, true);
3652 08 Dec 15 olle 949   }
3652 08 Dec 15 olle 950
3652 08 Dec 15 olle 951
3652 08 Dec 15 olle 952   /**
3652 08 Dec 15 olle 953     Add 'External DNA' to the selected wells.
3652 08 Dec 15 olle 954   */
3652 08 Dec 15 olle 955   inspectstartplate.setToExternal = function(event)
3652 08 Dec 15 olle 956   {
3652 08 Dec 15 olle 957     inspectstartplate.setToSpecial(event, EXTERNAL_DNA_NAME, false);  
3652 08 Dec 15 olle 958   }
3652 08 Dec 15 olle 959   
3652 08 Dec 15 olle 960   /**
3652 08 Dec 15 olle 961     Add special DNA to the selected wells.
3652 08 Dec 15 olle 962   */
3652 08 Dec 15 olle 963   inspectstartplate.setToSpecial = function(event, specialName, qc)
3652 08 Dec 15 olle 964   {
3652 08 Dec 15 olle 965     var wells = Plate.getSelected();
3652 08 Dec 15 olle 966     
3652 08 Dec 15 olle 967     if (wells.length == 0)
3652 08 Dec 15 olle 968     {
3652 08 Dec 15 olle 969       Forms.showNotification(event.currentTarget, 'No wells have been selected');
3652 08 Dec 15 olle 970       return;
3652 08 Dec 15 olle 971     }
3652 08 Dec 15 olle 972     
3652 08 Dec 15 olle 973     // Count non-empty wells
3652 08 Dec 15 olle 974     var count = 0;
3652 08 Dec 15 olle 975     for (var i = 0; i < wells.length; i++)
3652 08 Dec 15 olle 976     {
3652 08 Dec 15 olle 977       var well = wells[i];
3652 08 Dec 15 olle 978       if (well.extract && !well.hasError()) count++;
3652 08 Dec 15 olle 979     }
3652 08 Dec 15 olle 980     
3652 08 Dec 15 olle 981     if (count > 0)
3652 08 Dec 15 olle 982     {
3652 08 Dec 15 olle 983       if (!confirm('Replace DNA in ' + count + ' wells with '+specialName+'?'))
3652 08 Dec 15 olle 984       {
3652 08 Dec 15 olle 985         return;
3652 08 Dec 15 olle 986       }
3652 08 Dec 15 olle 987     }
3652 08 Dec 15 olle 988     
3652 08 Dec 15 olle 989     var info = Dna.infoByName(specialName);
3652 08 Dec 15 olle 990     if (!info.id)
3652 08 Dec 15 olle 991     {
3652 08 Dec 15 olle 992       alert('Could not find any DNA with name=\''+specialName+'\'. Please check that it exists on the server.');
3652 08 Dec 15 olle 993       return;
3652 08 Dec 15 olle 994     }
3652 08 Dec 15 olle 995     
3652 08 Dec 15 olle 996     for (var i = 0; i < wells.length; i++)
3652 08 Dec 15 olle 997     {
3652 08 Dec 15 olle 998       var well = wells[i];
3652 08 Dec 15 olle 999       var dna = Dna.createByInfo(info);
3652 08 Dec 15 olle 1000       dna.qc = qc;
3652 08 Dec 15 olle 1001       well.setExtract(dna);
3652 08 Dec 15 olle 1002       well.selected = false;
3652 08 Dec 15 olle 1003     }
3652 08 Dec 15 olle 1004     
3652 08 Dec 15 olle 1005     Plate.paint(wells);
3652 08 Dec 15 olle 1006     
3652 08 Dec 15 olle 1007     // Check for replicated DNA if some have been replaced with Stratagene
3652 08 Dec 15 olle 1008     if (count > 0) Plate.checkReplicates();
3652 08 Dec 15 olle 1009   }
3652 08 Dec 15 olle 1010   
3652 08 Dec 15 olle 1011   /**
3652 08 Dec 15 olle 1012     Toggle the QC flag for the selected wells. The first non-empty
3652 08 Dec 15 olle 1013     well is toggled and the rest of the wells will use the same new QC
3652 08 Dec 15 olle 1014     value.
3652 08 Dec 15 olle 1015   */
3652 08 Dec 15 olle 1016   inspectstartplate.toggleQc = function(event)
3652 08 Dec 15 olle 1017   {
3652 08 Dec 15 olle 1018     var wells = Plate.getSelected();
3652 08 Dec 15 olle 1019   
3652 08 Dec 15 olle 1020     if (wells.length == 0) 
3652 08 Dec 15 olle 1021     {
3652 08 Dec 15 olle 1022       Forms.showNotification(event.currentTarget, 'No wells have been selected');
3652 08 Dec 15 olle 1023       return;
3652 08 Dec 15 olle 1024     }
3652 08 Dec 15 olle 1025     
3652 08 Dec 15 olle 1026     var gotQc = false;
3652 08 Dec 15 olle 1027     var newQc;
3652 08 Dec 15 olle 1028     var count = 0;
3652 08 Dec 15 olle 1029     for (var i = 0; i < wells.length; i++)
3652 08 Dec 15 olle 1030     {
3652 08 Dec 15 olle 1031       var well = wells[i];
3652 08 Dec 15 olle 1032       if (well.extract)
3652 08 Dec 15 olle 1033       {
3652 08 Dec 15 olle 1034         // Toggle QC flag for the first well with DNA, then use the same flag for the rest
3652 08 Dec 15 olle 1035         if (!gotQc)
3652 08 Dec 15 olle 1036         {
3652 08 Dec 15 olle 1037           gotQc = true;
3652 08 Dec 15 olle 1038           newQc = !well.extract.qc;
3652 08 Dec 15 olle 1039         }
3652 08 Dec 15 olle 1040         well.extract.qc = newQc;
3652 08 Dec 15 olle 1041         count++;
3652 08 Dec 15 olle 1042       }
3652 08 Dec 15 olle 1043     }
3652 08 Dec 15 olle 1044     
3652 08 Dec 15 olle 1045     if (count == 0)
3652 08 Dec 15 olle 1046     {
3652 08 Dec 15 olle 1047       Forms.showNotification(event.currentTarget, 'None of the selected wells contain any DNA');
3652 08 Dec 15 olle 1048     }
3652 08 Dec 15 olle 1049     else
3652 08 Dec 15 olle 1050     {
3652 08 Dec 15 olle 1051       Plate.paint(wells);
3652 08 Dec 15 olle 1052     }
3652 08 Dec 15 olle 1053   }
3652 08 Dec 15 olle 1054
3652 08 Dec 15 olle 1055   // Set a comment on the selected wells
3652 08 Dec 15 olle 1056   inspectstartplate.commentSelected = function(event)
3652 08 Dec 15 olle 1057   {
3652 08 Dec 15 olle 1058     var wells = Plate.getSelected();
3652 08 Dec 15 olle 1059     
3652 08 Dec 15 olle 1060     if (wells.length == 0)
3652 08 Dec 15 olle 1061     {
3652 08 Dec 15 olle 1062       Forms.showNotification(event.currentTarget, 'No wells have been selected');
3652 08 Dec 15 olle 1063       return;
3652 08 Dec 15 olle 1064     }
3652 08 Dec 15 olle 1065     
3652 08 Dec 15 olle 1066     var count = 0;
3652 08 Dec 15 olle 1067     var comment = '';
3652 08 Dec 15 olle 1068     for (var i = 0; i < wells.length; i++)
3652 08 Dec 15 olle 1069     {
3652 08 Dec 15 olle 1070       var well = wells[i];
3652 08 Dec 15 olle 1071       if (well.extract) 
3652 08 Dec 15 olle 1072       {
3652 08 Dec 15 olle 1073         count++;
3652 08 Dec 15 olle 1074         if (well.extract.comment) comment = well.extract.comment;
3652 08 Dec 15 olle 1075       }
3652 08 Dec 15 olle 1076     }
3652 08 Dec 15 olle 1077       
3652 08 Dec 15 olle 1078     if (count == 0)
3652 08 Dec 15 olle 1079     {
3652 08 Dec 15 olle 1080       Forms.showNotification(event.currentTarget, 'None of the selected wells contain any DNA');
3652 08 Dec 15 olle 1081       return;
3652 08 Dec 15 olle 1082     }
3652 08 Dec 15 olle 1083
3652 08 Dec 15 olle 1084     comment = prompt('Comment', comment || '');
3652 08 Dec 15 olle 1085     if (comment == null) return;
3652 08 Dec 15 olle 1086     
3652 08 Dec 15 olle 1087     if (comment == '') comment = null;
3652 08 Dec 15 olle 1088     for (var i = 0; i < wells.length; i++)
3652 08 Dec 15 olle 1089     {
3652 08 Dec 15 olle 1090       var well = wells[i];
3652 08 Dec 15 olle 1091       if (well.extract) well.extract.comment = comment;
3652 08 Dec 15 olle 1092     }
3652 08 Dec 15 olle 1093     Plate.paint(wells);
3652 08 Dec 15 olle 1094   }
3652 08 Dec 15 olle 1095
3652 08 Dec 15 olle 1096   /**
3652 08 Dec 15 olle 1097     Empty the selected wells from DNA. They can later be pasted again.
3652 08 Dec 15 olle 1098   */
3652 08 Dec 15 olle 1099   inspectstartplate.cutSelected = function(event)
3652 08 Dec 15 olle 1100   {
3652 08 Dec 15 olle 1101     var wells = Plate.getSelected();
3652 08 Dec 15 olle 1102     
3652 08 Dec 15 olle 1103     if (wells.length == 0)
3652 08 Dec 15 olle 1104     {
3652 08 Dec 15 olle 1105       Forms.showNotification(event.currentTarget, 'No wells have been selected');
3652 08 Dec 15 olle 1106       return;
3652 08 Dec 15 olle 1107     }
3652 08 Dec 15 olle 1108     
3652 08 Dec 15 olle 1109     var count = 0;
3652 08 Dec 15 olle 1110     var valid = 0;
3652 08 Dec 15 olle 1111     for (var i = 0; i < wells.length; i++)
3652 08 Dec 15 olle 1112     {
3652 08 Dec 15 olle 1113       var well = wells[i];
3652 08 Dec 15 olle 1114       if (well.extract) 
3652 08 Dec 15 olle 1115       {
3652 08 Dec 15 olle 1116         count++;
3652 08 Dec 15 olle 1117         if (!well.hasError()) valid++;
3652 08 Dec 15 olle 1118       }
3652 08 Dec 15 olle 1119     }
3652 08 Dec 15 olle 1120     
3652 08 Dec 15 olle 1121     if (count == 0)
3652 08 Dec 15 olle 1122     {
3652 08 Dec 15 olle 1123       Forms.showNotification(event.currentTarget, 'None of the selected wells contain any DNA');
3652 08 Dec 15 olle 1124       return;
3652 08 Dec 15 olle 1125     }
3652 08 Dec 15 olle 1126     
3652 08 Dec 15 olle 1127     // Ask for confirmation before deleting from valid wells
3652 08 Dec 15 olle 1128     if (valid > 0)
3652 08 Dec 15 olle 1129     {
3652 08 Dec 15 olle 1130       if (!confirm('Clear DNA from ' + count + ' of ' + wells.length + ' selected wells?'))
3652 08 Dec 15 olle 1131       {
3652 08 Dec 15 olle 1132         return;
3652 08 Dec 15 olle 1133       }
3652 08 Dec 15 olle 1134     }
3652 08 Dec 15 olle 1135   
3652 08 Dec 15 olle 1136     inspectstartplate.copySelected();
3652 08 Dec 15 olle 1137 /*
3652 08 Dec 15 olle 1138     for (var i = 0; i < wells.length; i++)
3652 08 Dec 15 olle 1139     {
3652 08 Dec 15 olle 1140       var well = wells[i];
3652 08 Dec 15 olle 1141       well.setExtract(null);
3652 08 Dec 15 olle 1142       well.selected = false;
3652 08 Dec 15 olle 1143     }
3652 08 Dec 15 olle 1144     Plate.paint(wells);
3652 08 Dec 15 olle 1145 */
3652 08 Dec 15 olle 1146     var wellsArray = [];      
3652 08 Dec 15 olle 1147     for (var i = 0; i < wells.length; i++)
3652 08 Dec 15 olle 1148     {
3652 08 Dec 15 olle 1149       var well = wells[i];
3652 08 Dec 15 olle 1150       well.setExtract(null);
3652 08 Dec 15 olle 1151       well.selected = false;
3652 08 Dec 15 olle 1152       wellsArray[i] = well;
3652 08 Dec 15 olle 1153       // Clear FPB sample in corresponding well on right side of plate
3652 08 Dec 15 olle 1154       var row = well.row;
3652 08 Dec 15 olle 1155       var column = well.column;
3652 08 Dec 15 olle 1156       well = Plate.getWell(row, column + 6);
3652 08 Dec 15 olle 1157       well.setExtract(null);
3652 08 Dec 15 olle 1158       well.selected = false;
3652 08 Dec 15 olle 1159       wellsArray[i+wells.length] = well;
3652 08 Dec 15 olle 1160     }
3652 08 Dec 15 olle 1161     Plate.paint(wellsArray);
3652 08 Dec 15 olle 1162     Plate.checkReplicates();
3652 08 Dec 15 olle 1163   }
3652 08 Dec 15 olle 1164   
3652 08 Dec 15 olle 1165   var copy;
3652 08 Dec 15 olle 1166   /**
3652 08 Dec 15 olle 1167     Copy information about the selected wells. 
3652 08 Dec 15 olle 1168   */
3652 08 Dec 15 olle 1169   inspectstartplate.copySelected = function(event)
3652 08 Dec 15 olle 1170   {
3652 08 Dec 15 olle 1171     // Clear existing wells in the copy
3652 08 Dec 15 olle 1172     var repaint = [];
3652 08 Dec 15 olle 1173     if (copy && copy.length > 0)
3652 08 Dec 15 olle 1174     {
3652 08 Dec 15 olle 1175       for (var i = 0; i < copy.length; i++)
3652 08 Dec 15 olle 1176       {
3652 08 Dec 15 olle 1177         var cp = copy[i];
3652 08 Dec 15 olle 1178         cp.well.doneWithCopy();
3652 08 Dec 15 olle 1179         repaint[repaint.length] = cp.well;
3652 08 Dec 15 olle 1180       }
3652 08 Dec 15 olle 1181     }
3652 08 Dec 15 olle 1182     Plate.paint(repaint);
3652 08 Dec 15 olle 1183     
3652 08 Dec 15 olle 1184     // Place selected wells in the copy
3652 08 Dec 15 olle 1185     var wells = Plate.getSelected();
3652 08 Dec 15 olle 1186     copy = [];
3652 08 Dec 15 olle 1187     for (var i = 0; i < wells.length; i++)
3652 08 Dec 15 olle 1188     {
3652 08 Dec 15 olle 1189       var well = wells[i];
3652 08 Dec 15 olle 1190       copy[copy.length] = well.makeCopy();
3652 08 Dec 15 olle 1191       well.selected = false;
3652 08 Dec 15 olle 1192     }
3652 08 Dec 15 olle 1193     Plate.paint(wells);
3652 08 Dec 15 olle 1194   }
3652 08 Dec 15 olle 1195   
3652 08 Dec 15 olle 1196   /**
3652 08 Dec 15 olle 1197     Paste information into the selected wells.
3652 08 Dec 15 olle 1198   */
3652 08 Dec 15 olle 1199   inspectstartplate.pasteToSelected = function(event)
3652 08 Dec 15 olle 1200   {
3652 08 Dec 15 olle 1201     if (!copy || copy.length == 0) 
3652 08 Dec 15 olle 1202     {
3652 08 Dec 15 olle 1203       Forms.showNotification(event.currentTarget, 'Nothing to paste. Please cut or copy wells first.');
3652 08 Dec 15 olle 1204       return;
3652 08 Dec 15 olle 1205     }
3652 08 Dec 15 olle 1206     
3652 08 Dec 15 olle 1207     var wells = Plate.getSelected();
3652 08 Dec 15 olle 1208     // Count non-empty and valid wells
3652 08 Dec 15 olle 1209     var count = 0;
3652 08 Dec 15 olle 1210     for (var i = 0; i < wells.length; i++)
3652 08 Dec 15 olle 1211     {
3652 08 Dec 15 olle 1212       var well = wells[i];
3652 08 Dec 15 olle 1213       if (well.extract && !well.hasError()) count++;
3652 08 Dec 15 olle 1214     }
3652 08 Dec 15 olle 1215     
3652 08 Dec 15 olle 1216     if (count > 0)
3652 08 Dec 15 olle 1217     {
3652 08 Dec 15 olle 1218       if (!confirm('Replace DNA in ' + count + ' wells with copy?'))
3652 08 Dec 15 olle 1219       {
3652 08 Dec 15 olle 1220         return;
3652 08 Dec 15 olle 1221       }
3652 08 Dec 15 olle 1222     }
3652 08 Dec 15 olle 1223     
3652 08 Dec 15 olle 1224     var wi = 0;
3652 08 Dec 15 olle 1225     var ci = 0;
3652 08 Dec 15 olle 1226     var copyEmpty;
3652 08 Dec 15 olle 1227     var askIfEmpty = true;
3652 08 Dec 15 olle 1228     var repaint = [];
3652 08 Dec 15 olle 1229     
3652 08 Dec 15 olle 1230     while (wi < wells.length && ci < copy.length)
3652 08 Dec 15 olle 1231     {
3652 08 Dec 15 olle 1232       var well = wells[wi];
3652 08 Dec 15 olle 1233       var cp = copy[ci];
3652 08 Dec 15 olle 1234       var dna = null;
3652 08 Dec 15 olle 1235       var name = null;
3652 08 Dec 15 olle 1236       cp.well.doneWithCopy();
3652 08 Dec 15 olle 1237       repaint[repaint.length] = cp.well;
3652 08 Dec 15 olle 1238       if (cp.name)
3652 08 Dec 15 olle 1239       {
3652 08 Dec 15 olle 1240         name = cp.name;
3652 08 Dec 15 olle 1241         var suffixIndex = name.indexOf('.fpa');
3652 08 Dec 15 olle 1242         if (suffixIndex >= 0)
3652 08 Dec 15 olle 1243         {
3652 08 Dec 15 olle 1244           name = name.substring(0, suffixIndex);
3652 08 Dec 15 olle 1245         }
3652 08 Dec 15 olle 1246 /*
3652 08 Dec 15 olle 1247         dna = Dna.createByName(cp.name);
3652 08 Dec 15 olle 1248 */
3652 08 Dec 15 olle 1249         dna = Dna.createByName(name);
3652 08 Dec 15 olle 1250         dna.comment = cp.comment;
3652 08 Dec 15 olle 1251       }
3652 08 Dec 15 olle 1252       else
3652 08 Dec 15 olle 1253       {
3652 08 Dec 15 olle 1254         // The copy is from an empty well
3652 08 Dec 15 olle 1255         if (askIfEmpty)
3652 08 Dec 15 olle 1256         {
3652 08 Dec 15 olle 1257           askIfEmpty = false;
3652 08 Dec 15 olle 1258           copyEmpty = confirm('Do you want to copy empty wells? If not, only non-empty well are copied.');
3652 08 Dec 15 olle 1259         }
3652 08 Dec 15 olle 1260       }
3652 08 Dec 15 olle 1261       if (dna != null || copyEmpty)
3652 08 Dec 15 olle 1262       {
3652 08 Dec 15 olle 1263         // FPA
3652 08 Dec 15 olle 1264         if (dna != null)
3652 08 Dec 15 olle 1265         {
3652 08 Dec 15 olle 1266           dna.name += '.fpa'; 
3652 08 Dec 15 olle 1267         }
3652 08 Dec 15 olle 1268         well.setExtract(dna);
3652 08 Dec 15 olle 1269         well.selected = false;
3652 08 Dec 15 olle 1270         repaint[repaint.length] = well;
3652 08 Dec 15 olle 1271         wi++;
3652 08 Dec 15 olle 1272         // FPB sample in corresponding well on right side of plate
3652 08 Dec 15 olle 1273         var row = well.row;
3652 08 Dec 15 olle 1274         var column = well.column;
3652 08 Dec 15 olle 1275         well = Plate.getWell(row, column + 6);
3652 08 Dec 15 olle 1276         dna = null;
3652 08 Dec 15 olle 1277         if (name)
3652 08 Dec 15 olle 1278         {
3652 08 Dec 15 olle 1279           dna = Dna.createByName(name);
3652 08 Dec 15 olle 1280           dna.comment = cp.comment;
3652 08 Dec 15 olle 1281         }
3652 08 Dec 15 olle 1282         if (dna != null)
3652 08 Dec 15 olle 1283         {
3652 08 Dec 15 olle 1284           dna.name += '.fpb'; 
3652 08 Dec 15 olle 1285         }
3652 08 Dec 15 olle 1286         well.setExtract(dna);
3652 08 Dec 15 olle 1287         well.selected = false;
3652 08 Dec 15 olle 1288         repaint[repaint.length] = well;
3652 08 Dec 15 olle 1289       }
3652 08 Dec 15 olle 1290       ci++;
3652 08 Dec 15 olle 1291     }
3652 08 Dec 15 olle 1292     Plate.paint(repaint);
3652 08 Dec 15 olle 1293     copy.splice(0, ci);
3652 08 Dec 15 olle 1294     Plate.checkReplicates();
3652 08 Dec 15 olle 1295   }
3652 08 Dec 15 olle 1296
3652 08 Dec 15 olle 1297   /*
3652 08 Dec 15 olle 1298     If exactly two wells have been selected, switch the DNA in them.
3652 08 Dec 15 olle 1299   */
3652 08 Dec 15 olle 1300   inspectstartplate.switchSelected = function(event)
3652 08 Dec 15 olle 1301   {
3652 08 Dec 15 olle 1302     var wells = Plate.getSelected();
3652 08 Dec 15 olle 1303   
3652 08 Dec 15 olle 1304     if (wells.length != 2)
3652 08 Dec 15 olle 1305     {
3652 08 Dec 15 olle 1306       Forms.showNotification(event.currentTarget, 'Exactly 2 wells must be selected.');
3652 08 Dec 15 olle 1307       return;
3652 08 Dec 15 olle 1308     }
3652 08 Dec 15 olle 1309
3652 08 Dec 15 olle 1310 /*  
3652 08 Dec 15 olle 1311     var dna0 = wells[0].extract;
3652 08 Dec 15 olle 1312     var dna1 = wells[1].extract;
3652 08 Dec 15 olle 1313     
3652 08 Dec 15 olle 1314     wells[0].setExtract(dna1);
3652 08 Dec 15 olle 1315     wells[1].setExtract(dna0);
3652 08 Dec 15 olle 1316     Plate.paint(wells);
3652 08 Dec 15 olle 1317 */
3652 08 Dec 15 olle 1318     var wellsArray = [];
3652 08 Dec 15 olle 1319     // FPA
3652 08 Dec 15 olle 1320     wellsArray[0] = wells[0];
3652 08 Dec 15 olle 1321     wellsArray[1] = wells[1];
3652 08 Dec 15 olle 1322
3652 08 Dec 15 olle 1323     var dna0 = wells[0].extract;
3652 08 Dec 15 olle 1324     var dna1 = wells[1].extract;
3652 08 Dec 15 olle 1325     
3652 08 Dec 15 olle 1326     wells[0].setExtract(dna1);
3652 08 Dec 15 olle 1327     wells[1].setExtract(dna0);
3652 08 Dec 15 olle 1328     // FPB samples in corresponding wells on right side of plate
3652 08 Dec 15 olle 1329     var wellsFpb = [];
3652 08 Dec 15 olle 1330     for (var i=0; i<2; i++)
3652 08 Dec 15 olle 1331     {  
3652 08 Dec 15 olle 1332       var row = wells[i].row;
3652 08 Dec 15 olle 1333       var column = wells[i].column;
3652 08 Dec 15 olle 1334       wellsFpb[i] = Plate.getWell(row, column + 6);
3652 08 Dec 15 olle 1335     }
3652 08 Dec 15 olle 1336     wellsArray[2] = wellsFpb[0];
3652 08 Dec 15 olle 1337     wellsArray[3] = wellsFpb[1];
3652 08 Dec 15 olle 1338
3652 08 Dec 15 olle 1339     dna0 = wellsFpb[0].extract;
3652 08 Dec 15 olle 1340     dna1 = wellsFpb[1].extract;
3652 08 Dec 15 olle 1341     
3652 08 Dec 15 olle 1342     wellsFpb[0].setExtract(dna1);
3652 08 Dec 15 olle 1343     wellsFpb[1].setExtract(dna0);
3652 08 Dec 15 olle 1344     //
3652 08 Dec 15 olle 1345     Plate.paint(wellsArray);
3652 08 Dec 15 olle 1346   }
3652 08 Dec 15 olle 1347
3652 08 Dec 15 olle 1348   // Toggle the 'special select' menu on and off
3652 08 Dec 15 olle 1349   inspectstartplate.toggleSpecialSelect = function(event)
3652 08 Dec 15 olle 1350   {
3652 08 Dec 15 olle 1351     var pos = Doc.getElementPosition('iconSpecialSelect');
3652 08 Dec 15 olle 1352     Menu.toggleTopMenu('menuSpecialSelect', pos.left+pos.width/4, pos.top+pos.height); 
3652 08 Dec 15 olle 1353     event.stopPropagation();
3652 08 Dec 15 olle 1354   }
3652 08 Dec 15 olle 1355   
3652 08 Dec 15 olle 1356   /**
3652 08 Dec 15 olle 1357     Open a pop-up dialog for manual selection of extracts.
3652 08 Dec 15 olle 1358   */
3652 08 Dec 15 olle 1359   inspectstartplate.manualSelectExtract = function(event)
3652 08 Dec 15 olle 1360   {
3652 08 Dec 15 olle 1361     if (subtypeDna == null) subtypeDna = Meludi.getSubtypeInfo('DNA');
3652 08 Dec 15 olle 1362   
3652 08 Dec 15 olle 1363     var url = '&resetTemporary=1';
3652 08 Dec 15 olle 1364     url += '&tmpfilter:INT:itemSubtype='+subtypeDna.id;
3652 08 Dec 15 olle 1365     url += '&tmpfilter:STRING:name='+encodeURIComponent('%.d');
3652 08 Dec 15 olle 1366     url += '&tmpfilter:DATE:creationEvent.eventDate='+encodeURIComponent('');
3652 08 Dec 15 olle 1367     url += '&tmpfilter:FLOAT:remainingQuantity='+encodeURIComponent('>0');
3652 08 Dec 15 olle 1368     url += '&'+encodeURIComponent('tmpfilter:STRING:&childCreationEvents(event.bioMaterial.name)')+'='+encodeURIComponent('');
3652 08 Dec 15 olle 1369
3652 08 Dec 15 olle 1370     Dialogs.selectItem('EXTRACT', 'plate', 1, url);
3652 08 Dec 15 olle 1371   }
3652 08 Dec 15 olle 1372
3652 08 Dec 15 olle 1373   /**
3652 08 Dec 15 olle 1374     Open a pop-up dialog for manual selection of controls.
3652 08 Dec 15 olle 1375   */
3652 08 Dec 15 olle 1376   inspectstartplate.manualSelectControl = function(event)
3652 08 Dec 15 olle 1377   {
3652 08 Dec 15 olle 1378     if (subtypeDna == null) subtypeDna = Meludi.getSubtypeInfo('DNA');
3652 08 Dec 15 olle 1379   
3652 08 Dec 15 olle 1380     var url = '&resetTemporary=1';
3652 08 Dec 15 olle 1381     url += '&tmpfilter:INT:itemSubtype='+subtypeDna.id;
3652 08 Dec 15 olle 1382     url += '&tmpfilter:STRING:name='+encodeURIComponent('Horizon%.d');
3652 08 Dec 15 olle 1383     url += '&tmpfilter:DATE:creationEvent.eventDate='+encodeURIComponent('');
3652 08 Dec 15 olle 1384     url += '&tmpfilter:FLOAT:remainingQuantity='+encodeURIComponent('>0');
3652 08 Dec 15 olle 1385     url += '&'+encodeURIComponent('tmpfilter:STRING:&childCreationEvents(event.bioMaterial.name)')+'='+encodeURIComponent('');
3652 08 Dec 15 olle 1386
3652 08 Dec 15 olle 1387     Dialogs.selectItem('EXTRACT', 'plate', 1, url);
3652 08 Dec 15 olle 1388   }
3652 08 Dec 15 olle 1389
3652 08 Dec 15 olle 1390   var contextDNA = null;
3652 08 Dec 15 olle 1391   var contextX;
3652 08 Dec 15 olle 1392   var contextY;
3652 08 Dec 15 olle 1393   /**
3652 08 Dec 15 olle 1394     Reacts to 'mouseup' and 'contextmenu' events for the bioplate. 
3652 08 Dec 15 olle 1395     This should bring up the cut/copy/paste context menu depending on which
3652 08 Dec 15 olle 1396     mouse button that was clicked.
3652 08 Dec 15 olle 1397   */
3652 08 Dec 15 olle 1398   inspectstartplate.contextEvent = function(event)
3652 08 Dec 15 olle 1399   {
3652 08 Dec 15 olle 1400     var frm = document.forms['meludi'];
3652 08 Dec 15 olle 1401     // Context menu on 'right' mouse button
3652 08 Dec 15 olle 1402     // Can't just check the button since two events are sent ('mouseup' and 'contextmenu')
3652 08 Dec 15 olle 1403     var showContext = event.type == 'contextmenu' && event.button == 2;
3652 08 Dec 15 olle 1404       
3652 08 Dec 15 olle 1405     if (showContext)
3652 08 Dec 15 olle 1406     {
3652 08 Dec 15 olle 1407       event.preventDefault(); // Prevents the default right-click menu from appearing
3652 08 Dec 15 olle 1408       
3652 08 Dec 15 olle 1409       // Get the well that is right-clicked and the DNA that is in it
3652 08 Dec 15 olle 1410       contextDNA = null;
3652 08 Dec 15 olle 1411       var well = event.target;
3652 08 Dec 15 olle 1412       while (well && (!well.id || well.id.indexOf('well') != 0))
3652 08 Dec 15 olle 1413       {
3652 08 Dec 15 olle 1414         well = well.parentNode;
3652 08 Dec 15 olle 1415       }
3652 08 Dec 15 olle 1416       if (well)
3652 08 Dec 15 olle 1417       {
3652 08 Dec 15 olle 1418         var c = well.id.split(/\./);
3652 08 Dec 15 olle 1419         contextDNA = Plate.getWell(parseInt(c[1]), parseInt(c[2])).extract;
3652 08 Dec 15 olle 1420       }
3652 08 Dec 15 olle 1421       // Update the context meny
3652 08 Dec 15 olle 1422       var caseSummaryMenu = Doc.element('mnuCaseSummary');
3652 08 Dec 15 olle 1423       if (contextDNA)
3652 08 Dec 15 olle 1424       {
3652 08 Dec 15 olle 1425         caseSummaryMenu.title = 'Show case summary for ' + Strings.encodeTags(contextDNA.name);
3652 08 Dec 15 olle 1426         Doc.show('sepCaseSummary');
3652 08 Dec 15 olle 1427         Doc.show('mnuCaseSummary');
3652 08 Dec 15 olle 1428       }
3652 08 Dec 15 olle 1429       else
3652 08 Dec 15 olle 1430       {
3652 08 Dec 15 olle 1431         Doc.hide('sepCaseSummary');
3652 08 Dec 15 olle 1432         Doc.hide('mnuCaseSummary');
3652 08 Dec 15 olle 1433       }
3652 08 Dec 15 olle 1434       
3652 08 Dec 15 olle 1435       var menu = Doc.element('menuContext');
3652 08 Dec 15 olle 1436       // 1 pixel offset to avoid losing well focus outline
3652 08 Dec 15 olle 1437       contextX = event.clientX+1;
3652 08 Dec 15 olle 1438       contextY = event.clientY+1;
3652 08 Dec 15 olle 1439       // Need short delay since 'mouseup' are also sent as 'click' events
3652 08 Dec 15 olle 1440       // to the 'document' object which BASE already have a Menu.hideAll()
3652 08 Dec 15 olle 1441       // call which would hide the menu immediately
3652 08 Dec 15 olle 1442       setTimeout(inspectstartplate.showContextMenu, 100);
3652 08 Dec 15 olle 1443     }
3652 08 Dec 15 olle 1444   }
3652 08 Dec 15 olle 1445   
3652 08 Dec 15 olle 1446   inspectstartplate.showContextMenu = function()
3652 08 Dec 15 olle 1447   {
3652 08 Dec 15 olle 1448     Menu.showTopMenu('menuContext', contextX, contextY);
3652 08 Dec 15 olle 1449   }
3652 08 Dec 15 olle 1450
3652 08 Dec 15 olle 1451   inspectstartplate.showCaseSummary = function()
3652 08 Dec 15 olle 1452   {
3652 08 Dec 15 olle 1453     if (!contextDNA) return;
3652 08 Dec 15 olle 1454     var caseName = contextDNA.name;
3652 08 Dec 15 olle 1455     // Remove suffix starting with dot "."
3652 08 Dec 15 olle 1456     var firstDotIndex = caseName.indexOf(".");
3652 08 Dec 15 olle 1457     if (firstDotIndex >= 0)
3652 08 Dec 15 olle 1458     {
3652 08 Dec 15 olle 1459       caseName = caseName.substring(0, firstDotIndex);
3652 08 Dec 15 olle 1460     }
3652 08 Dec 15 olle 1461     var url = '../reports/case_summary.jsp?ID='+App.getSessionId();
3652 08 Dec 15 olle 1462     url += '&caseName='+encodeURIComponent(caseName);
3652 08 Dec 15 olle 1463     url += '&pageType=popup';
3652 08 Dec 15 olle 1464     Dialogs.openPopup(url, 'CaseSummary'+caseName, 1000, 700);
3652 08 Dec 15 olle 1465   }
3652 08 Dec 15 olle 1466   
3652 08 Dec 15 olle 1467   inspectstartplate.showFlaggedDna = function()
3652 08 Dec 15 olle 1468   {
3652 08 Dec 15 olle 1469     currentSelected = Plate.getSelected();
3652 08 Dec 15 olle 1470     currentIndex = 0;
3652 08 Dec 15 olle 1471
3652 08 Dec 15 olle 1472     var flagged = Dna.getFlagged();
3652 08 Dec 15 olle 1473     var url = 'show_flagged_dna.jsp?ID='+App.getSessionId();
3652 08 Dec 15 olle 1474     url += '&numFlagged='+flagged.length;
3652 08 Dec 15 olle 1475     url += '&numSelected='+currentSelected.length;
3652 08 Dec 15 olle 1476     Dialogs.openPopup(url, 'FlaggedDna', 800, 500);
3652 08 Dec 15 olle 1477   }
3652 08 Dec 15 olle 1478
3652 08 Dec 15 olle 1479   
3652 08 Dec 15 olle 1480   //Flag the selected DNA
3652 08 Dec 15 olle 1481   inspectstartplate.flagSelected = function(event)
3652 08 Dec 15 olle 1482   {
3652 08 Dec 15 olle 1483     var flag = Data.get(event.currentTarget, 'flag');
3652 08 Dec 15 olle 1484     var wells = Plate.getSelected();
3652 08 Dec 15 olle 1485     
3652 08 Dec 15 olle 1486     if (wells.length == 0)
3652 08 Dec 15 olle 1487     {
3652 08 Dec 15 olle 1488       Forms.showNotification(event.currentTarget, 'No wells have been selected.');
3652 08 Dec 15 olle 1489       return;
3652 08 Dec 15 olle 1490     }
3652 08 Dec 15 olle 1491     
3652 08 Dec 15 olle 1492     var comment = null;
3652 08 Dec 15 olle 1493     if (flag == 'ManualFlag')
3652 08 Dec 15 olle 1494     {
3652 08 Dec 15 olle 1495       // Check if a comment has been set on any of the DNA
3652 08 Dec 15 olle 1496       for (var i = 0; i < wells.length; i++)
3652 08 Dec 15 olle 1497       {
3652 08 Dec 15 olle 1498         var well = wells[i];
3652 08 Dec 15 olle 1499         if (well.extract && well.extract.info) 
3652 08 Dec 15 olle 1500         {
3652 08 Dec 15 olle 1501           if (well.extract.info.comment) comment = well.extract.info.comment;
3652 08 Dec 15 olle 1502         }
3652 08 Dec 15 olle 1503       }
3652 08 Dec 15 olle 1504       comment = prompt('Comment', comment || '');
3652 08 Dec 15 olle 1505       if (!comment) return;
3652 08 Dec 15 olle 1506     }
3652 08 Dec 15 olle 1507     
3652 08 Dec 15 olle 1508     var count = 0;
3652 08 Dec 15 olle 1509     for (var i = 0; i < wells.length; i++)
3652 08 Dec 15 olle 1510     {
3652 08 Dec 15 olle 1511       var well = wells[i];
3652 08 Dec 15 olle 1512       var dna = well.extract;
3652 08 Dec 15 olle 1513       if (dna && !dna.stratagene && !dna.external)
3652 08 Dec 15 olle 1514       {
3652 08 Dec 15 olle 1515         Dna.flag(dna, flag);
3652 08 Dec 15 olle 1516         dna.info.comment = comment;
3652 08 Dec 15 olle 1517         well.setExtract(null);
3652 08 Dec 15 olle 1518         count++;
3652 08 Dec 15 olle 1519       }
3652 08 Dec 15 olle 1520       well.selected = false;
3652 08 Dec 15 olle 1521     }
3652 08 Dec 15 olle 1522     
3652 08 Dec 15 olle 1523     inspectstartplate.updateNumFlaggedDna();
3652 08 Dec 15 olle 1524     Plate.paint(wells);
3652 08 Dec 15 olle 1525   }
3652 08 Dec 15 olle 1526
3652 08 Dec 15 olle 1527   inspectstartplate.downloadLibPrepFile = function()
3652 08 Dec 15 olle 1528   {
3652 08 Dec 15 olle 1529     var frm = document.forms['meludi'];
3652 08 Dec 15 olle 1530     var isNeoPrep = Data.int('page-data', 'is-neoprep');
3652 08 Dec 15 olle 1531
3652 08 Dec 15 olle 1532     var submitInfo = {};
3652 08 Dec 15 olle 1533     
3652 08 Dec 15 olle 1534     var libraryPreparationProtocolName = '';
3652 08 Dec 15 olle 1535     var libraryPreparationProtocol = frm.libraryPreparationProtocol.value;
3652 08 Dec 15 olle 1536     if (libraryPreparationProtocol)
3652 08 Dec 15 olle 1537     {
3652 08 Dec 15 olle 1538       libraryPreparationProtocolName = protocolMap[libraryPreparationProtocol];
3652 08 Dec 15 olle 1539     }
3652 08 Dec 15 olle 1540     submitInfo.libraryPreparationProtocol = parseInt(libraryPreparationProtocol, 10);
3652 08 Dec 15 olle 1541     submitInfo.libraryPreparationProtocolName = libraryPreparationProtocolName;
3685 12 Jan 16 olle 1542     submitInfo.bioplate = inspectstartplate.fetchBioplateData();
3685 12 Jan 16 olle 1543
3685 12 Jan 16 olle 1544     var url = '../LibPrep.servlet?ID='+App.getSessionId();
3685 12 Jan 16 olle 1545     url += '&cmd=PrepareDownloadLibPrepFile';
3685 12 Jan 16 olle 1546     url += '&referenceName='+encodeURIComponent(frm.plateName.value);
3685 12 Jan 16 olle 1547
3685 12 Jan 16 olle 1548     // POST
3685 12 Jan 16 olle 1549     Wizard.showLoadingAnimation('Performing registration...');
3685 12 Jan 16 olle 1550     Wizard.asyncJsonRequest(url, inspectstartplate.downloadLibPrepFileResults, 'POST', JSON.stringify(submitInfo));
3685 12 Jan 16 olle 1551   }
3685 12 Jan 16 olle 1552
3685 12 Jan 16 olle 1553   inspectstartplate.fetchBioplateData = function()
3685 12 Jan 16 olle 1554   {
3685 12 Jan 16 olle 1555     var frm = document.forms['meludi'];
3685 12 Jan 16 olle 1556     var isNeoPrep = Data.int('page-data', 'is-neoprep');
3652 08 Dec 15 olle 1557     var schema = PoolSchema.getById(frm.pool_schema.value);
3685 12 Jan 16 olle 1558
3685 12 Jan 16 olle 1559     var plateInfo = {};
3685 12 Jan 16 olle 1560     plateInfo.id = Plate.id;
3652 08 Dec 15 olle 1561     plateInfo.name = Plate.name;
3652 08 Dec 15 olle 1562     plateInfo.comments = frm.comments.value;
3652 08 Dec 15 olle 1563     plateInfo.kitName = frm.tsLibPrepKit.value;
3652 08 Dec 15 olle 1564     plateInfo.kitId = frm.hiddenLibPrepKitId.value;
3652 08 Dec 15 olle 1565     plateInfo.plateType = isNeoPrep ? 'NEOPREP' : 'DNA';
3652 08 Dec 15 olle 1566     plateInfo.poolSchema = schema ? schema.id : null;
3652 08 Dec 15 olle 1567     if (isNeoPrep)
3652 08 Dec 15 olle 1568     {
3652 08 Dec 15 olle 1569       plateInfo.barcodeVariant = frm.barcode_variant.value;
3652 08 Dec 15 olle 1570     }
3652 08 Dec 15 olle 1571     plateInfo.wells = [];
3652 08 Dec 15 olle 1572
3652 08 Dec 15 olle 1573     var wells = Plate.getWells();
3652 08 Dec 15 olle 1574     for (var i = 0; i < wells.length; i++)
3652 08 Dec 15 olle 1575     {
3652 08 Dec 15 olle 1576       var well = wells[i];
3652 08 Dec 15 olle 1577       var dna = well.extract;
3667 15 Dec 15 olle 1578       if (dna && dna.info.origId)
3652 08 Dec 15 olle 1579       {
3652 08 Dec 15 olle 1580         var tmp = {};
3652 08 Dec 15 olle 1581         tmp.row = well.row;
3652 08 Dec 15 olle 1582         tmp.column = well.column;
3652 08 Dec 15 olle 1583         tmp.dna = {};
3667 15 Dec 15 olle 1584         tmp.dna.id = dna.info.origId;
3652 08 Dec 15 olle 1585         tmp.dna.usedQuantity = dna.usedQuantity;
3652 08 Dec 15 olle 1586         tmp.dna.dilutionConc = dna.dilutionConc;
3652 08 Dec 15 olle 1587         tmp.dna.qc = dna.qc;
3652 08 Dec 15 olle 1588         tmp.dna.comment = dna.comment;
3652 08 Dec 15 olle 1589         if (well.barcode)
3652 08 Dec 15 olle 1590         {
3652 08 Dec 15 olle 1591           tmp.dna.barcode = well.barcode;
3652 08 Dec 15 olle 1592         }
3652 08 Dec 15 olle 1593         plateInfo.wells[plateInfo.wells.length] = tmp;
3652 08 Dec 15 olle 1594       }
3652 08 Dec 15 olle 1595     }
3685 12 Jan 16 olle 1596     
3685 12 Jan 16 olle 1597     return plateInfo;
3652 08 Dec 15 olle 1598   }
3652 08 Dec 15 olle 1599
3652 08 Dec 15 olle 1600   inspectstartplate.downloadLibPrepFileResults = function(response)
3652 08 Dec 15 olle 1601   {
3652 08 Dec 15 olle 1602     var tmpFilePath = response;
3652 08 Dec 15 olle 1603     var frm = document.forms['meludi'];
3652 08 Dec 15 olle 1604     var url = '../LibPrep.servlet?ID='+App.getSessionId();
3652 08 Dec 15 olle 1605     url += '&cmd=DownloadLibPrepFile';
3652 08 Dec 15 olle 1606     url += '&referenceName='+encodeURIComponent(frm.plateName.value);
3652 08 Dec 15 olle 1607     url += '&tmpFilePath='+encodeURIComponent(tmpFilePath);
3652 08 Dec 15 olle 1608     window.open(url);
3652 08 Dec 15 olle 1609   }
3652 08 Dec 15 olle 1610
3685 12 Jan 16 olle 1611   inspectstartplate.viewProtocol = function(event)
3685 12 Jan 16 olle 1612   {
3685 12 Jan 16 olle 1613     var frm = document.forms['meludi2'];
3685 12 Jan 16 olle 1614     var bioplateData = inspectstartplate.fetchBioplateData();
3685 12 Jan 16 olle 1615     var submitInfo = inspectstartplate.fetchSubmitInfo();
3685 12 Jan 16 olle 1616
3685 12 Jan 16 olle 1617     // Save values in hidden input fields for retrieval after HTML request
3685 12 Jan 16 olle 1618     var submitInfoJsonStr = JSON.stringify(submitInfo, inspectstartplate.circular_reference_remover);
3685 12 Jan 16 olle 1619     // Enable garbage collection
3685 12 Jan 16 olle 1620     circular_reference_cache = null;
3685 12 Jan 16 olle 1621     frm.hiddenSubmitInfo.value = submitInfoJsonStr;
3685 12 Jan 16 olle 1622     frm.hiddenNumItems.value = submitInfo.items.length;
3685 12 Jan 16 olle 1623     frm.view.value = Data.get(event.currentTarget, 'protocol-type');
3685 12 Jan 16 olle 1624     frm.bioplateName.value = bioplateData.name;
3685 12 Jan 16 olle 1625     frm.bioplateDescription.value = bioplateData.comments;
3685 12 Jan 16 olle 1626     frm.bioplateKitName.value = bioplateData.kitName;
3685 12 Jan 16 olle 1627
3685 12 Jan 16 olle 1628     // Calling frm.submit() will change jsp file to libprep_plate_protocol2.jsp
3685 12 Jan 16 olle 1629     frm.submit();
3685 12 Jan 16 olle 1630   }
3685 12 Jan 16 olle 1631
3652 08 Dec 15 olle 1632   inspectstartplate.createProtocol = function()
3652 08 Dec 15 olle 1633   {
3652 08 Dec 15 olle 1634     var frm = document.forms['meludi'];
3685 12 Jan 16 olle 1635     var submitInfo = inspectstartplate.fetchSubmitInfo();
3685 12 Jan 16 olle 1636
3685 12 Jan 16 olle 1637     // Save values in hidden input fields for retrieval after HTML request
3685 12 Jan 16 olle 1638     var submitInfoJsonStr = JSON.stringify(submitInfo, inspectstartplate.circular_reference_remover);
3685 12 Jan 16 olle 1639     // Enable garbage collection
3685 12 Jan 16 olle 1640     circular_reference_cache = null;
3685 12 Jan 16 olle 1641     frm.hiddenSubmitInfo.value = submitInfoJsonStr;
3685 12 Jan 16 olle 1642     frm.hiddenNumItems.value = submitInfo.items.length;
3685 12 Jan 16 olle 1643
3685 12 Jan 16 olle 1644     // Calling frm.submit() will change jsp file to libprep_dilution_protocol2.jsp
3685 12 Jan 16 olle 1645     frm.submit();
3685 12 Jan 16 olle 1646   }
3685 12 Jan 16 olle 1647
3685 12 Jan 16 olle 1648   inspectstartplate.fetchSubmitInfo = function()
3685 12 Jan 16 olle 1649   {
3685 12 Jan 16 olle 1650     var frm = document.forms['meludi'];
3652 08 Dec 15 olle 1651     var submitInfo = {};
3652 08 Dec 15 olle 1652     submitInfo.items = [];
3652 08 Dec 15 olle 1653
3652 08 Dec 15 olle 1654     submitInfo.docMode = 'report';
3652 08 Dec 15 olle 1655     // Get list of selected extract source items
3652 08 Dec 15 olle 1656     var selItemsList = [];
3652 08 Dec 15 olle 1657     for (var column = 0; column < 6; column++)
3652 08 Dec 15 olle 1658     {
3652 08 Dec 15 olle 1659       for (var row = 0; row < 8; row++)
3652 08 Dec 15 olle 1660       {
3652 08 Dec 15 olle 1661         var well = Plate.getWell(row, column);
3652 08 Dec 15 olle 1662         var dna = well.extract;
3652 08 Dec 15 olle 1663         if (dna != null)
3652 08 Dec 15 olle 1664         {        
3685 12 Jan 16 olle 1665           dna.bioWell = well;
3652 08 Dec 15 olle 1666           dna.fpaPos = inspectstartplate.wellRowColumnToWellStr(row, column); 
3652 08 Dec 15 olle 1667           dna.fpbPos = inspectstartplate.wellRowColumnToWellStr(row, column + 6); 
3652 08 Dec 15 olle 1668           selItemsList[selItemsList.length] = dna;
3652 08 Dec 15 olle 1669         }
3652 08 Dec 15 olle 1670       }
3652 08 Dec 15 olle 1671     }
3652 08 Dec 15 olle 1672     var numItems = selItemsList.length;
3652 08 Dec 15 olle 1673     var totNumItems = numItems;
3652 08 Dec 15 olle 1674     for (var i = 0; i < totNumItems; i++)
3652 08 Dec 15 olle 1675     {
3652 08 Dec 15 olle 1676       var item = null;
3652 08 Dec 15 olle 1677       item = selItemsList[i];
3652 08 Dec 15 olle 1678       submitInfo.items[submitInfo.items.length] = item;
3652 08 Dec 15 olle 1679     }
3652 08 Dec 15 olle 1680
3652 08 Dec 15 olle 1681     // Library preparation dilution
3652 08 Dec 15 olle 1682     var libraryPreparationProtocolName = '';
3652 08 Dec 15 olle 1683     var libraryPreparationProtocol = frm.libraryPreparationProtocol.value;
3652 08 Dec 15 olle 1684     if (libraryPreparationProtocol)
3652 08 Dec 15 olle 1685     {
3652 08 Dec 15 olle 1686       libraryPreparationProtocolName = protocolMap[libraryPreparationProtocol];
3652 08 Dec 15 olle 1687     }
3652 08 Dec 15 olle 1688     submitInfo.libraryPreparationProtocol = parseInt(libraryPreparationProtocol, 10);
3652 08 Dec 15 olle 1689     submitInfo.libraryPreparationProtocolName = libraryPreparationProtocolName;
3652 08 Dec 15 olle 1690     submitInfo.startPlateName = frm.plateName.value;
3652 08 Dec 15 olle 1691     var now = new Date();
3652 08 Dec 15 olle 1692     var dilutionProtocolDate = inspectstartplate.formatDate(now);
3652 08 Dec 15 olle 1693     submitInfo.dilutionProtocolDate = dilutionProtocolDate;
3652 08 Dec 15 olle 1694
3685 12 Jan 16 olle 1695     return submitInfo;
3685 12 Jan 16 olle 1696   }
3685 12 Jan 16 olle 1697   
3685 12 Jan 16 olle 1698 var circular_reference_cache = [];
3652 08 Dec 15 olle 1699
3685 12 Jan 16 olle 1700   inspectstartplate.circular_reference_remover = function(key, value)
3685 12 Jan 16 olle 1701   {
3685 12 Jan 16 olle 1702     if (typeof value === 'object' && value !== null)
3685 12 Jan 16 olle 1703     {
3685 12 Jan 16 olle 1704       if (circular_reference_cache == null)
3685 12 Jan 16 olle 1705       {
3685 12 Jan 16 olle 1706         circular_reference_cache = [];
3685 12 Jan 16 olle 1707       }
3685 12 Jan 16 olle 1708       if (circular_reference_cache.indexOf(value) !== -1)
3685 12 Jan 16 olle 1709       {
3685 12 Jan 16 olle 1710         // Circular reference found, discard key
3685 12 Jan 16 olle 1711         return;
3685 12 Jan 16 olle 1712       }
3685 12 Jan 16 olle 1713       // Store value in collection
3685 12 Jan 16 olle 1714       circular_reference_cache.push(value);
3685 12 Jan 16 olle 1715     }
3685 12 Jan 16 olle 1716     return value;
3652 08 Dec 15 olle 1717   }
3685 12 Jan 16 olle 1718
3652 08 Dec 15 olle 1719   inspectstartplate.initElements = function(element, autoInit)
3652 08 Dec 15 olle 1720   {
3652 08 Dec 15 olle 1721     if (autoInit == 'plate-col')
3652 08 Dec 15 olle 1722     {
3652 08 Dec 15 olle 1723       Events.addEventHandler(element, 'click', inspectstartplate.toggleColumn);
3652 08 Dec 15 olle 1724       Events.addEventHandler(element, 'mouseover', inspectstartplate.highlightColumn);
3652 08 Dec 15 olle 1725       Events.addEventHandler(element, 'mouseout', inspectstartplate.highlightColumn);
3652 08 Dec 15 olle 1726     }
3652 08 Dec 15 olle 1727     else if (autoInit == 'plate-row')
3652 08 Dec 15 olle 1728     {
3652 08 Dec 15 olle 1729       Events.addEventHandler(element, 'click', inspectstartplate.toggleRow);
3652 08 Dec 15 olle 1730       Events.addEventHandler(element, 'mouseover', inspectstartplate.highlightRow);
3652 08 Dec 15 olle 1731       Events.addEventHandler(element, 'mouseout', inspectstartplate.highlightRow);
3652 08 Dec 15 olle 1732     }
3652 08 Dec 15 olle 1733     else if (autoInit == 'plate-well')
3652 08 Dec 15 olle 1734     {
3652 08 Dec 15 olle 1735       Events.addEventHandler(element, 'click', inspectstartplate.toggleWell);
3652 08 Dec 15 olle 1736       Events.addEventHandler(element, 'mouseover', inspectstartplate.highlightReplicated);
3652 08 Dec 15 olle 1737       Events.addEventHandler(element, 'mouseout', inspectstartplate.highlightReplicated);
3652 08 Dec 15 olle 1738     }
3652 08 Dec 15 olle 1739     else if (autoInit == 'special-select')
3652 08 Dec 15 olle 1740     {
3652 08 Dec 15 olle 1741       Events.addEventHandler(element, 'click', inspectstartplate.specialToggle)
3652 08 Dec 15 olle 1742     }
3652 08 Dec 15 olle 1743   }
3652 08 Dec 15 olle 1744
3652 08 Dec 15 olle 1745   // Restrict wells to left side of plate
3652 08 Dec 15 olle 1746   inspectstartplate.restrictWells = function(wellsInput)
3652 08 Dec 15 olle 1747   {
3652 08 Dec 15 olle 1748     var wells = [];
3652 08 Dec 15 olle 1749     for (var i = 0; i < wellsInput.length; i++)
3652 08 Dec 15 olle 1750     {
3652 08 Dec 15 olle 1751       well = wellsInput[i];
3652 08 Dec 15 olle 1752       if (well.column < 6)
3652 08 Dec 15 olle 1753       {
3652 08 Dec 15 olle 1754         wells[wells.length] = well;
3652 08 Dec 15 olle 1755       }
3652 08 Dec 15 olle 1756     }
3652 08 Dec 15 olle 1757     return wells;
3652 08 Dec 15 olle 1758   }
3652 08 Dec 15 olle 1759
3652 08 Dec 15 olle 1760   // Toggle the selected status of a single well
3652 08 Dec 15 olle 1761   inspectstartplate.toggleWell = function(event)
3652 08 Dec 15 olle 1762   {
3652 08 Dec 15 olle 1763     var row = Data.int(event.currentTarget, 'row');
3652 08 Dec 15 olle 1764     var column = Data.int(event.currentTarget, 'col');
3652 08 Dec 15 olle 1765     if (column >= 6)
3652 08 Dec 15 olle 1766     {
3652 08 Dec 15 olle 1767       return;
3652 08 Dec 15 olle 1768     }
3652 08 Dec 15 olle 1769     var well = Plate.getWell(row, column);
3652 08 Dec 15 olle 1770     Plate.toggleSelected([well]);
3652 08 Dec 15 olle 1771   }
3652 08 Dec 15 olle 1772
3652 08 Dec 15 olle 1773   // Toggle the selected status of a complete row
3652 08 Dec 15 olle 1774   inspectstartplate.toggleRow = function(event)
3652 08 Dec 15 olle 1775   {
3652 08 Dec 15 olle 1776     var row = Data.int(event.currentTarget, 'row');
3652 08 Dec 15 olle 1777 /*
3652 08 Dec 15 olle 1778     Plate.toggleSelected(Plate.getRow(row));
3652 08 Dec 15 olle 1779 */
3652 08 Dec 15 olle 1780     var wells = inspectstartplate.restrictWells(Plate.getRow(row));
3652 08 Dec 15 olle 1781     Plate.toggleSelected(wells);
3652 08 Dec 15 olle 1782   }
3652 08 Dec 15 olle 1783
3652 08 Dec 15 olle 1784   // Toggle the selected status of a complete column
3652 08 Dec 15 olle 1785   inspectstartplate.toggleColumn = function(event)
3652 08 Dec 15 olle 1786   {
3652 08 Dec 15 olle 1787     var column = Data.int(event.currentTarget, 'col');
3652 08 Dec 15 olle 1788     if (column >= 6)
3652 08 Dec 15 olle 1789     {
3652 08 Dec 15 olle 1790       return;
3652 08 Dec 15 olle 1791     }
3652 08 Dec 15 olle 1792     Plate.toggleSelected(Plate.getColumn(column));
3652 08 Dec 15 olle 1793   }
3652 08 Dec 15 olle 1794   
3652 08 Dec 15 olle 1795   // Toggle the selected status of a pool
3652 08 Dec 15 olle 1796   inspectstartplate.togglePool = function(event)
3652 08 Dec 15 olle 1797   {
3652 08 Dec 15 olle 1798     var pool = Data.int(event.target, 'pool-num');
3652 08 Dec 15 olle 1799 /*
3652 08 Dec 15 olle 1800     if (!isNaN(pool)) Plate.toggleSelected(Plate.getPool(pool));
3652 08 Dec 15 olle 1801 */
3652 08 Dec 15 olle 1802     if (!isNaN(pool) && pool < 1)
3652 08 Dec 15 olle 1803     {
3652 08 Dec 15 olle 1804       Plate.toggleSelected(Plate.getPool(pool));
3652 08 Dec 15 olle 1805     }
3652 08 Dec 15 olle 1806   }
3652 08 Dec 15 olle 1807   
3652 08 Dec 15 olle 1808   // Highlight enable/disable all wells in a column
3652 08 Dec 15 olle 1809   inspectstartplate.highlightColumn = function(event)
3652 08 Dec 15 olle 1810   {
3652 08 Dec 15 olle 1811     var column = Data.int(event.currentTarget, 'col');
3652 08 Dec 15 olle 1812     if (column >= 6)
3652 08 Dec 15 olle 1813     {
3652 08 Dec 15 olle 1814       return;
3652 08 Dec 15 olle 1815     }
3652 08 Dec 15 olle 1816     var on = event.type == 'mouseover';
3652 08 Dec 15 olle 1817     
3652 08 Dec 15 olle 1818     Doc.addOrRemoveClass(event.currentTarget, 'highlight-column', on);
3652 08 Dec 15 olle 1819     var wells = Plate.getColumn(column);
3652 08 Dec 15 olle 1820     Plate.setHighlight(wells, 'highlight-column', on);
3652 08 Dec 15 olle 1821   }
3652 08 Dec 15 olle 1822
3652 08 Dec 15 olle 1823   // Highlight enable/disable all wells in a row
3652 08 Dec 15 olle 1824   inspectstartplate.highlightRow = function(event)
3652 08 Dec 15 olle 1825   {
3652 08 Dec 15 olle 1826     var row = Data.int(event.currentTarget, 'row');
3652 08 Dec 15 olle 1827     var on = event.type == 'mouseover';
3652 08 Dec 15 olle 1828     
3652 08 Dec 15 olle 1829     Doc.addOrRemoveClass(event.currentTarget, 'highlight-row', on);
3652 08 Dec 15 olle 1830 /*
3652 08 Dec 15 olle 1831     var wells = Plate.getRow(row);
3652 08 Dec 15 olle 1832 */
3652 08 Dec 15 olle 1833     var wells = inspectstartplate.restrictWells(Plate.getRow(row));
3652 08 Dec 15 olle 1834     Plate.setHighlight(wells, 'highlight-row', on);
3652 08 Dec 15 olle 1835   }
3652 08 Dec 15 olle 1836   
3652 08 Dec 15 olle 1837   // Highligt enable/disable all wells in a pool
3652 08 Dec 15 olle 1838   inspectstartplate.highlightPool = function(event)
3652 08 Dec 15 olle 1839   {
3652 08 Dec 15 olle 1840     var pool = Data.int(event.target, 'pool-num');
3652 08 Dec 15 olle 1841     var on = event.type == 'mouseover';
3652 08 Dec 15 olle 1842 /*
3652 08 Dec 15 olle 1843     if (!isNaN(pool))
3652 08 Dec 15 olle 1844 */
3652 08 Dec 15 olle 1845     if (!isNaN(pool) && pool < 1)
3652 08 Dec 15 olle 1846     {
3652 08 Dec 15 olle 1847       Doc.addOrRemoveClass(event.target, 'highlight-pool', on);
3652 08 Dec 15 olle 1848       var wells = Plate.getPool(pool);
3652 08 Dec 15 olle 1849       Plate.setHighlight(wells, 'highlight-pool', on);
3652 08 Dec 15 olle 1850     }
3652 08 Dec 15 olle 1851   }
3652 08 Dec 15 olle 1852
3652 08 Dec 15 olle 1853   /**
3652 08 Dec 15 olle 1854     Highlight all replicated wells with the same DNA as the given well.
3652 08 Dec 15 olle 1855   */
3652 08 Dec 15 olle 1856   inspectstartplate.highlightReplicated = function(event)
3652 08 Dec 15 olle 1857   {
3652 08 Dec 15 olle 1858     var column = Data.int(event.currentTarget, 'col');
3652 08 Dec 15 olle 1859     if (column >= 6)
3652 08 Dec 15 olle 1860     {
3652 08 Dec 15 olle 1861       return;
3652 08 Dec 15 olle 1862     }
3652 08 Dec 15 olle 1863     var row = Data.int(event.currentTarget, 'row');
3652 08 Dec 15 olle 1864     var on = event.type == 'mouseover';
3652 08 Dec 15 olle 1865     
3652 08 Dec 15 olle 1866     var well = Plate.getWell(row, column);
3652 08 Dec 15 olle 1867     if (well.extract && well.replicate)
3652 08 Dec 15 olle 1868     {
3652 08 Dec 15 olle 1869       // Get center coordinates for the current well
3652 08 Dec 15 olle 1870       var pos = Doc.getElementPosition(well.tag);
3652 08 Dec 15 olle 1871       var jsPos = new jsPoint(pos.left+pos.width/2, pos.top+pos.height/2);
3652 08 Dec 15 olle 1872   
3652 08 Dec 15 olle 1873       var replicated = Plate.getWellsByName(well.extract.name);
3652 08 Dec 15 olle 1874       for (var i = 0; i < replicated.length; i++)
3652 08 Dec 15 olle 1875       {
3652 08 Dec 15 olle 1876         var rep = replicated[i];
3652 08 Dec 15 olle 1877         if (rep != well)
3652 08 Dec 15 olle 1878         {
3652 08 Dec 15 olle 1879           Doc.addOrRemoveClass(rep.tag, 'highlight-replicated', on);
3652 08 Dec 15 olle 1880           if (rep.line)
3652 08 Dec 15 olle 1881           {
3652 08 Dec 15 olle 1882             // Clear any recent lines
3652 08 Dec 15 olle 1883             graphics.clearDrawing(rep.line);
3652 08 Dec 15 olle 1884             rep.line = null;
3652 08 Dec 15 olle 1885           }
3652 08 Dec 15 olle 1886           if (on)
3652 08 Dec 15 olle 1887           {
3652 08 Dec 15 olle 1888             // We draw a line between the current and replicated well
3652 08 Dec 15 olle 1889             var rPos = Doc.getElementPosition(rep.tag);
3652 08 Dec 15 olle 1890             rep.line = graphics.drawLine(pen, jsPos, new jsPoint(rPos.left+rPos.width/2, rPos.top+rPos.height/2));
3652 08 Dec 15 olle 1891           }
3652 08 Dec 15 olle 1892         }
3652 08 Dec 15 olle 1893       }
3652 08 Dec 15 olle 1894     }
3652 08 Dec 15 olle 1895   }
3652 08 Dec 15 olle 1896
3652 08 Dec 15 olle 1897   // Some special toogle operations
3652 08 Dec 15 olle 1898   inspectstartplate.specialToggle = function(event)
3652 08 Dec 15 olle 1899   {
3652 08 Dec 15 olle 1900     var what = Data.get(event.currentTarget, 'special');
3652 08 Dec 15 olle 1901     var wells = [];
3652 08 Dec 15 olle 1902     if (what == 'all' || what == 'empty' || what == 'none')
3652 08 Dec 15 olle 1903     {
3652 08 Dec 15 olle 1904       // All wells or all empty (will be filtered later)
3652 08 Dec 15 olle 1905       wells = Plate.getWells();
3652 08 Dec 15 olle 1906     }
3652 08 Dec 15 olle 1907     else if (what == 'pools' || what == 'empty-pools')
3652 08 Dec 15 olle 1908     {
3652 08 Dec 15 olle 1909       // All primary pools or all empty in the primary pools (will be filtered later)
3652 08 Dec 15 olle 1910       for (var i = 0; i < Plate.poolSchema.numPools; i++)
3652 08 Dec 15 olle 1911       {
3652 08 Dec 15 olle 1912         wells = wells.concat(Plate.getPool(i));
3652 08 Dec 15 olle 1913       }
3652 08 Dec 15 olle 1914     }
3652 08 Dec 15 olle 1915     else if (what == 'stratagene')
3652 08 Dec 15 olle 1916     {
3652 08 Dec 15 olle 1917       // All wells with 'Stratagene'
3652 08 Dec 15 olle 1918       var tmp = Plate.getWells();
3652 08 Dec 15 olle 1919       for (var i = 0; i < tmp.length; i++)
3652 08 Dec 15 olle 1920       {
3652 08 Dec 15 olle 1921         var well = tmp[i];
3652 08 Dec 15 olle 1922         if (well.extract && well.extract.stratagene) wells[wells.length] = well;
3652 08 Dec 15 olle 1923       }
3652 08 Dec 15 olle 1924     }
3652 08 Dec 15 olle 1925     else if (what == 'external')
3652 08 Dec 15 olle 1926     {
3652 08 Dec 15 olle 1927       // All wells with 'External DNA'
3652 08 Dec 15 olle 1928       var tmp = Plate.getWells();
3652 08 Dec 15 olle 1929       for (var i = 0; i < tmp.length; i++)
3652 08 Dec 15 olle 1930       {
3652 08 Dec 15 olle 1931         var well = tmp[i];
3652 08 Dec 15 olle 1932         if (well.extract && well.extract.external) wells[wells.length] = well;
3652 08 Dec 15 olle 1933       }
3652 08 Dec 15 olle 1934     }
3652 08 Dec 15 olle 1935     else if (what == 'replicates')
3652 08 Dec 15 olle 1936     {
3652 08 Dec 15 olle 1937       // All wells with replicated DNA
3652 08 Dec 15 olle 1938       var tmp = Plate.getWells();
3652 08 Dec 15 olle 1939       for (var i = 0; i < tmp.length; i++)
3652 08 Dec 15 olle 1940       {
3652 08 Dec 15 olle 1941         var well = tmp[i];
3652 08 Dec 15 olle 1942         if (well.extract && well.replicate) wells[wells.length] = well;
3652 08 Dec 15 olle 1943       }
3652 08 Dec 15 olle 1944     }
3652 08 Dec 15 olle 1945     else if (what == 'error')
3652 08 Dec 15 olle 1946     {
3652 08 Dec 15 olle 1947       // All wells with an error
3652 08 Dec 15 olle 1948       var tmp = Plate.getWells();
3652 08 Dec 15 olle 1949       for (var i = 0; i < tmp.length; i++)
3652 08 Dec 15 olle 1950       {
3652 08 Dec 15 olle 1951         var well = tmp[i];
3652 08 Dec 15 olle 1952         if (well.hasError()) wells[wells.length] = well;
3652 08 Dec 15 olle 1953       }
3652 08 Dec 15 olle 1954     }
3652 08 Dec 15 olle 1955     else if (what == 'warning')
3652 08 Dec 15 olle 1956     {
3652 08 Dec 15 olle 1957       // All wells with a warning
3652 08 Dec 15 olle 1958       var tmp = Plate.getWells();
3652 08 Dec 15 olle 1959       for (var i = 0; i < tmp.length; i++)
3652 08 Dec 15 olle 1960       {
3652 08 Dec 15 olle 1961         var well = tmp[i];
3652 08 Dec 15 olle 1962         if (well.warning) wells[wells.length] = well;
3652 08 Dec 15 olle 1963       }
3652 08 Dec 15 olle 1964     }
3652 08 Dec 15 olle 1965     
3652 08 Dec 15 olle 1966     // Extra filter for empty wells only
3652 08 Dec 15 olle 1967     if (what.indexOf('empty') != -1)
3652 08 Dec 15 olle 1968     {
3652 08 Dec 15 olle 1969       var tmp = wells;
3652 08 Dec 15 olle 1970       wells = [];
3652 08 Dec 15 olle 1971       for (var i = 0; i < tmp.length; i++)
3652 08 Dec 15 olle 1972       {
3652 08 Dec 15 olle 1973         if (!tmp[i].extract) wells[wells.length] = tmp[i];
3652 08 Dec 15 olle 1974       }
3652 08 Dec 15 olle 1975     }
3652 08 Dec 15 olle 1976     
3652 08 Dec 15 olle 1977     if (what == 'none')
3652 08 Dec 15 olle 1978     {
3652 08 Dec 15 olle 1979       Plate.setSelected(wells, false);
3652 08 Dec 15 olle 1980     }
3652 08 Dec 15 olle 1981     else
3652 08 Dec 15 olle 1982     {
3652 08 Dec 15 olle 1983       Plate.toggleSelected(wells);
3652 08 Dec 15 olle 1984     }
3652 08 Dec 15 olle 1985   }
3652 08 Dec 15 olle 1986
3652 08 Dec 15 olle 1987   // Format value as a date in format yyyy-mm-dd
3652 08 Dec 15 olle 1988   inspectstartplate.asDate = function(value)
3652 08 Dec 15 olle 1989   {
3652 08 Dec 15 olle 1990     if (!value) return '';
3652 08 Dec 15 olle 1991     if (value.length == 8)
3652 08 Dec 15 olle 1992     {
3652 08 Dec 15 olle 1993       value = value.substr(0, 4) + '-' + value.substr(4, 2) + '-' + value.substr(6, 2);
3652 08 Dec 15 olle 1994     }
3652 08 Dec 15 olle 1995     return value;
3652 08 Dec 15 olle 1996   }
3652 08 Dec 15 olle 1997
3652 08 Dec 15 olle 1998   // Format date value in format yyyy-mm-dd
3652 08 Dec 15 olle 1999   inspectstartplate.formatDate = function(date)
3652 08 Dec 15 olle 2000   {
3652 08 Dec 15 olle 2001     if (!date) return '';
3652 08 Dec 15 olle 2002     var year = date.getFullYear();
3652 08 Dec 15 olle 2003     var month = (date.getMonth() + 1);
3652 08 Dec 15 olle 2004     var day = date.getDate();
3652 08 Dec 15 olle 2005     var monthStr = '' + month;
3652 08 Dec 15 olle 2006     if (month < 10)
3652 08 Dec 15 olle 2007     {
3652 08 Dec 15 olle 2008       monthStr = '0' + month;
3652 08 Dec 15 olle 2009     }
3652 08 Dec 15 olle 2010     var dayStr = '' + day;
3652 08 Dec 15 olle 2011     if (day < 10)
3652 08 Dec 15 olle 2012     {
3652 08 Dec 15 olle 2013       dayStr = '0' + day;
3652 08 Dec 15 olle 2014     }
3652 08 Dec 15 olle 2015     var dateStr = '' + year + '-' + monthStr + '-' + dayStr;
3652 08 Dec 15 olle 2016     return dateStr;
3652 08 Dec 15 olle 2017   }
3652 08 Dec 15 olle 2018
3652 08 Dec 15 olle 2019   return inspectstartplate;
3652 08 Dec 15 olle 2020 }();
3652 08 Dec 15 olle 2021
3652 08 Dec 15 olle 2022 Doc.onLoad(InspectStartPlate.initPage);
3652 08 Dec 15 olle 2023 Doc.addElementInitializer(InspectStartPlate.initElements);
3652 08 Dec 15 olle 2024
3652 08 Dec 15 olle 2025
3652 08 Dec 15 olle 2026 var Dna = function()
3652 08 Dec 15 olle 2027 {
3652 08 Dec 15 olle 2028   var dna = {};
3652 08 Dec 15 olle 2029   var flagged = [];
3652 08 Dec 15 olle 2030   var info = [];
3652 08 Dec 15 olle 2031   
3652 08 Dec 15 olle 2032   /**
3652 08 Dec 15 olle 2033     Create a new DNA object by name. More information
3652 08 Dec 15 olle 2034     about the DNA is automatically loaded from the database.
3652 08 Dec 15 olle 2035   */
3652 08 Dec 15 olle 2036   dna.createByName = function(name)
3652 08 Dec 15 olle 2037   {
3652 08 Dec 15 olle 2038     var tmp = {};
3652 08 Dec 15 olle 2039     tmp.name = name;
3652 08 Dec 15 olle 2040     tmp.stratagene = Meludi.isStratagene(name)
3652 08 Dec 15 olle 2041     tmp.external = Meludi.isExternal(name);
3652 08 Dec 15 olle 2042     tmp.info = dna.infoByName(name);
3667 15 Dec 15 olle 2043 //alert("inspect_start_plate.js::dna.createByName(name): name = " + name + " info = " + JSON.stringify(tmp.info));
3652 08 Dec 15 olle 2044     tmp.id = tmp.info.id;
3652 08 Dec 15 olle 2045     return tmp;
3652 08 Dec 15 olle 2046   }
3652 08 Dec 15 olle 2047   
3652 08 Dec 15 olle 2048   /**
3667 15 Dec 15 olle 2049     Create a new DNA object by parent name. More information
3667 15 Dec 15 olle 2050     about the DNA is automatically loaded from the database.
3667 15 Dec 15 olle 2051   */
3693 15 Jan 16 olle 2052   dna.createByParentName = function(parentName, name, id)
3667 15 Dec 15 olle 2053   {
3693 15 Jan 16 olle 2054 //alert("inspect_start_plate.js::dna.createByParentName(parentName, name, id): parentName = " + parentName + " name = " + name + " id = " + id);
3667 15 Dec 15 olle 2055     var tmp = {};
3667 15 Dec 15 olle 2056     tmp.name = name;
3693 15 Jan 16 olle 2057     tmp.id = id;
3667 15 Dec 15 olle 2058     tmp.stratagene = Meludi.isStratagene(parentName)
3667 15 Dec 15 olle 2059     tmp.external = Meludi.isExternal(parentName);
3667 15 Dec 15 olle 2060     var parentDna = dna.infoByName(parentName);
3667 15 Dec 15 olle 2061     // Copy some info to original info
3667 15 Dec 15 olle 2062     var info = {};
3667 15 Dec 15 olle 2063     info.origBioWell = parentDna.bioWell;
3667 15 Dec 15 olle 2064     info.origQubitConc = parentDna.QubitConc;
3667 15 Dec 15 olle 2065     info.origDeltaCt = parentDna.deltaCt;
3667 15 Dec 15 olle 2066     info.origId = parentDna.id;
3667 15 Dec 15 olle 2067     info.origName = parentDna.name;
3679 18 Dec 15 olle 2068     info.origDescription = parentDna.comment;
3667 15 Dec 15 olle 2069     // Reset info for created item
3667 15 Dec 15 olle 2070     info.bioWell = null;
3667 15 Dec 15 olle 2071     info.QubitConc = null;
3667 15 Dec 15 olle 2072     info.deltaCt = null;
3667 15 Dec 15 olle 2073     info.id = null;
3667 15 Dec 15 olle 2074     // Set tmp.info to new JSONObject info
3667 15 Dec 15 olle 2075     tmp.info = info;
3667 15 Dec 15 olle 2076     return tmp;
3667 15 Dec 15 olle 2077   }
3667 15 Dec 15 olle 2078   
3667 15 Dec 15 olle 2079   /**
3652 08 Dec 15 olle 2080     Create a new DNA object by info object.
3652 08 Dec 15 olle 2081   */
3652 08 Dec 15 olle 2082   dna.createByInfo = function(info)
3652 08 Dec 15 olle 2083   {
3652 08 Dec 15 olle 2084     var tmp = {};
3652 08 Dec 15 olle 2085     tmp.name = info.name;
3652 08 Dec 15 olle 2086     tmp.stratagene = Meludi.isStratagene(tmp.name);
3652 08 Dec 15 olle 2087     tmp.external = Meludi.isExternal(tmp.name);
3652 08 Dec 15 olle 2088     tmp.id = info.id;
3652 08 Dec 15 olle 2089     tmp.info = info;
3652 08 Dec 15 olle 2090     return tmp;
3652 08 Dec 15 olle 2091   }
3652 08 Dec 15 olle 2092   
3652 08 Dec 15 olle 2093   /**
3652 08 Dec 15 olle 2094     Get information about a DNA item with a given name.
3652 08 Dec 15 olle 2095   */
3652 08 Dec 15 olle 2096   dna.infoByName = function(name)
3652 08 Dec 15 olle 2097   {
3652 08 Dec 15 olle 2098     var key = 'N'+name;
3652 08 Dec 15 olle 2099     if (!info[key])
3652 08 Dec 15 olle 2100     {
3652 08 Dec 15 olle 2101       dna.loadInfoByNames([name]);
3652 08 Dec 15 olle 2102       if (!info[key]) info[key] = {};
3652 08 Dec 15 olle 2103     }
3652 08 Dec 15 olle 2104     return info[key];
3652 08 Dec 15 olle 2105   }
3652 08 Dec 15 olle 2106
3652 08 Dec 15 olle 2107   /**
3652 08 Dec 15 olle 2108     Load and cache DNA information for all DNA items with a name in the
3652 08 Dec 15 olle 2109     given list.
3652 08 Dec 15 olle 2110   */
3652 08 Dec 15 olle 2111   dna.loadInfoByNames = function(names)
3652 08 Dec 15 olle 2112   {
3652 08 Dec 15 olle 2113     var newNames = [];
3652 08 Dec 15 olle 2114     for (var i = 0; i < names.length; i++)
3652 08 Dec 15 olle 2115     {
3652 08 Dec 15 olle 2116       if (!info['N'+names[i]]) newNames[newNames.length] = names[i];
3652 08 Dec 15 olle 2117     }
3652 08 Dec 15 olle 2118     
3652 08 Dec 15 olle 2119     var submitInfo = {};
3652 08 Dec 15 olle 2120     submitInfo.names = newNames;
3652 08 Dec 15 olle 2121     
3652 08 Dec 15 olle 2122     if (newNames.length > 0)
3652 08 Dec 15 olle 2123     {
3652 08 Dec 15 olle 2124       var url = '../Dna.servlet?ID='+App.getSessionId();
3652 08 Dec 15 olle 2125       url += '&cmd=GetDnaInfoFromNames';  
3652 08 Dec 15 olle 2126       var response = Wizard.syncJsonRequest(url, 'POST', JSON.stringify(submitInfo));
3652 08 Dec 15 olle 2127       dna.cacheInfo(response.dna);
3652 08 Dec 15 olle 2128     }
3652 08 Dec 15 olle 2129   }
3652 08 Dec 15 olle 2130   
3652 08 Dec 15 olle 2131   dna.cacheInfo = function(dnaList)
3652 08 Dec 15 olle 2132   {
3652 08 Dec 15 olle 2133     for (var i = 0; i < dnaList.length; i++)
3652 08 Dec 15 olle 2134     {
3652 08 Dec 15 olle 2135       var r = dnaList[i];
3652 08 Dec 15 olle 2136       info['N'+r.name] = r;
3652 08 Dec 15 olle 2137       info['I'+r.id] = r;
3652 08 Dec 15 olle 2138       if (r.flag) flagged[flagged.length] = r;
3652 08 Dec 15 olle 2139     }
3652 08 Dec 15 olle 2140   }
3652 08 Dec 15 olle 2141
3652 08 Dec 15 olle 2142   dna.unflag = function(r)
3652 08 Dec 15 olle 2143   {
3652 08 Dec 15 olle 2144     if (!r.info || !r.info.flag) return false;
3652 08 Dec 15 olle 2145
3652 08 Dec 15 olle 2146     r.info.flag = null;
3652 08 Dec 15 olle 2147     for (var i = 0; i < flagged.length; i++)
3652 08 Dec 15 olle 2148     {
3652 08 Dec 15 olle 2149       if (r.id == flagged[i].id)
3652 08 Dec 15 olle 2150       {
3652 08 Dec 15 olle 2151         flagged.splice(i, 1);
3652 08 Dec 15 olle 2152         break;
3652 08 Dec 15 olle 2153       }
3652 08 Dec 15 olle 2154     }
3652 08 Dec 15 olle 2155     return true;
3652 08 Dec 15 olle 2156   }
3652 08 Dec 15 olle 2157   
3652 08 Dec 15 olle 2158   dna.flag = function(r, flag)
3652 08 Dec 15 olle 2159   {
3652 08 Dec 15 olle 2160     if (!r.info || r.info.flag) return false;
3652 08 Dec 15 olle 2161     r.info.flag = flag;
3652 08 Dec 15 olle 2162     flagged[flagged.length] = r.info;
3652 08 Dec 15 olle 2163   }
3652 08 Dec 15 olle 2164   
3652 08 Dec 15 olle 2165   dna.getFlagged = function()
3652 08 Dec 15 olle 2166   {
3652 08 Dec 15 olle 2167     return flagged;
3652 08 Dec 15 olle 2168   }
3652 08 Dec 15 olle 2169   
3652 08 Dec 15 olle 2170   return dna;
3652 08 Dec 15 olle 2171 }();
3652 08 Dec 15 olle 2172
3652 08 Dec 15 olle 2173
3652 08 Dec 15 olle 2174
3652 08 Dec 15 olle 2175 var WellPainter = function()
3652 08 Dec 15 olle 2176 {
3652 08 Dec 15 olle 2177   var painter = {};
3652 08 Dec 15 olle 2178   
3652 08 Dec 15 olle 2179   // Add class indicators for replicates and QC assigned wells
3652 08 Dec 15 olle 2180   painter.getClassNameForWell = function(well)
3652 08 Dec 15 olle 2181   {
3652 08 Dec 15 olle 2182     var cls = '';
3652 08 Dec 15 olle 2183     if (well.extract)
3652 08 Dec 15 olle 2184     {
3652 08 Dec 15 olle 2185       if (well.replicate) cls += ' replicate';
3652 08 Dec 15 olle 2186       if (well.extract.qc) cls += ' qc';
3652 08 Dec 15 olle 2187     }
3652 08 Dec 15 olle 2188     if (well.column == Plate.columns-1) cls += ' last-child';
3652 08 Dec 15 olle 2189     
3652 08 Dec 15 olle 2190     return cls;
3652 08 Dec 15 olle 2191   }
3652 08 Dec 15 olle 2192   
3652 08 Dec 15 olle 2193   painter.getWellText = function(well)
3652 08 Dec 15 olle 2194   {
3652 08 Dec 15 olle 2195     var frm = document.forms['meludi'];
3652 08 Dec 15 olle 2196     var text = '';
3652 08 Dec 15 olle 2197     if (well.duplicates)
3652 08 Dec 15 olle 2198     {
3652 08 Dec 15 olle 2199       well.setError('Duplicate DNA in this location');
3652 08 Dec 15 olle 2200       text += '<div class="name">'+Strings.encodeTags(well.duplicates.join(', '))+'</div>';
3652 08 Dec 15 olle 2201     }
3652 08 Dec 15 olle 2202     else if (well.extract)
3652 08 Dec 15 olle 2203     {
3652 08 Dec 15 olle 2204       // The well contains DNA
3652 08 Dec 15 olle 2205       var dna = well.extract;
3652 08 Dec 15 olle 2206       var info = dna.info;
3652 08 Dec 15 olle 2207       // --- DNA aliquot name
3652 08 Dec 15 olle 2208       text += '<div class="name">'+Strings.encodeTags(dna.name)+'</div>';
3667 15 Dec 15 olle 2209 //alert("inspect_start_plate.js::getWellText(): info = " + JSON.stringify(info));
3652 08 Dec 15 olle 2210       
3652 08 Dec 15 olle 2211       var warningMsg = [];
3652 08 Dec 15 olle 2212       // --- Bioplate location
3667 15 Dec 15 olle 2213       if (info.origBioWell)
3652 08 Dec 15 olle 2214       {
3667 15 Dec 15 olle 2215         var origDnaWell = info.origBioWell;
3667 15 Dec 15 olle 2216         text += '<div class="location">'+Strings.encodeTags(origDnaWell.bioPlate.name+'['+origDnaWell.location)+']</div>';
3652 08 Dec 15 olle 2217       }
3652 08 Dec 15 olle 2218       else if (info.preNormalized)
3652 08 Dec 15 olle 2219       {
3652 08 Dec 15 olle 2220         text += '<div class="location">PreNormalized</div>';
3652 08 Dec 15 olle 2221       }
3652 08 Dec 15 olle 2222       else if (!dna.stratagene && !dna.external)
3652 08 Dec 15 olle 2223       {
3652 08 Dec 15 olle 2224         if (!painter.hasClass('plate', 'hide-location'))
3652 08 Dec 15 olle 2225         {
3652 08 Dec 15 olle 2226           warningMsg[warningMsg.length] = 'No location';
3652 08 Dec 15 olle 2227         }
3652 08 Dec 15 olle 2228       }
3652 08 Dec 15 olle 2229
3667 15 Dec 15 olle 2230       if (info && info.origId && !dna.stratagene && !dna.external)
3652 08 Dec 15 olle 2231       {
3652 08 Dec 15 olle 2232         // Calculations for each aliquot
3667 15 Dec 15 olle 2233         var origDeltaCt = info.origDeltaCt;
3667 15 Dec 15 olle 2234         var dilutionFactor = painter.fetchDilutionFactor(origDeltaCt);
3652 08 Dec 15 olle 2235         var VOL_ALIQUOT = 10.0; // µl
3652 08 Dec 15 olle 2236         var volDNA = VOL_ALIQUOT/dilutionFactor;
3652 08 Dec 15 olle 2237         var water = VOL_ALIQUOT - volDNA;
3652 08 Dec 15 olle 2238         // Prepare for future modification of solution volume depending on other parameters
3652 08 Dec 15 olle 2239         var volAliquotSolution = VOL_ALIQUOT;
3652 08 Dec 15 olle 2240         var volDnaInSolution = volAliquotSolution/dilutionFactor;
3652 08 Dec 15 olle 2241         var waterInSolution = volAliquotSolution - volDnaInSolution;
3652 08 Dec 15 olle 2242         var removedVolume = 2 * volDnaInSolution; // µl
3667 15 Dec 15 olle 2243         var origConc = info.origQubitConc; // ng/µl
3667 15 Dec 15 olle 2244         var calcConc = origConc/dilutionFactor;
3652 08 Dec 15 olle 2245         //var usedQuantityPerAliquout = Math.ceil(VOL_ALIQUOT*origConc/dilutionFactor/1000); // µg
3652 08 Dec 15 olle 2246         //var usedQuantityPerAliquout = VOL_ALIQUOT*origConc/dilutionFactor/1000; // µg
3652 08 Dec 15 olle 2247         //var usedQuantity = volDNA*origConc; // ng
3652 08 Dec 15 olle 2248         var usedQuantity = volDnaInSolution*origConc; // ng
3652 08 Dec 15 olle 2249         dna.usedQuantity = dna.qc ? QUANTITY_QC : usedQuantity/1000; // µg
3667 15 Dec 15 olle 2250 //alert("inspect_start_plate.js::painter.getWellText(): name = " + dna.name + " removedVolume = " + removedVolume + " origDeltaCt = " + origDeltaCt + " dilutionFactor = " + dilutionFactor + " origConc = " + origConc + " usedQuantity = " + usedQuantity + " ng");
3652 08 Dec 15 olle 2251
3652 08 Dec 15 olle 2252 /*        
3652 08 Dec 15 olle 2253         dna.usedQuantity = dna.qc ? QUANTITY_QC : QUANTITY_REGULAR; // µg
3652 08 Dec 15 olle 2254         dna.dilutionConc = 1000 * dna.usedQuantity / TOTAL_VOLUME; // ng/µl
3652 08 Dec 15 olle 2255
3667 15 Dec 15 olle 2256         var volDNA = Math.ceil(10000*dna.usedQuantity/info.origQubitConc) / 10; // µl, rounded to 1 decimal
3652 08 Dec 15 olle 2257         var water = TOTAL_VOLUME - volDNA;
3652 08 Dec 15 olle 2258 */        
3652 08 Dec 15 olle 2259
3652 08 Dec 15 olle 2260         var MINIMAL_DNA_VOLUME = frm.min_vol_dna.value;
3682 04 Jan 16 olle 2261         if (volDnaInSolution < MINIMAL_DNA_VOLUME)
3652 08 Dec 15 olle 2262         {
3652 08 Dec 15 olle 2263 /*
3652 08 Dec 15 olle 2264           // Large mix since we do not want to take less than 1µl
3652 08 Dec 15 olle 2265           volDNA = MINIMAL_DNA_VOLUME;
3667 15 Dec 15 olle 2266           dna.usedQuantity = volDNA * info.origQubitConc / 1000; // µg
3652 08 Dec 15 olle 2267           var totalVolume = 1000 * dna.usedQuantity / dna.dilutionConc; // µl
3652 08 Dec 15 olle 2268           water = totalVolume - volDNA;
3652 08 Dec 15 olle 2269           warningMsg[warningMsg.length] = 'Large mix';
3652 08 Dec 15 olle 2270 */
3682 04 Jan 16 olle 2271           warningMsg[warningMsg.length] = 'DNA vol ' + Numbers.formatNumber(volDnaInSolution, 2) + 'µl < ' + MINIMAL_DNA_VOLUME + 'µl';
3652 08 Dec 15 olle 2272         }
3652 08 Dec 15 olle 2273
3652 08 Dec 15 olle 2274         // Store dilution data
3652 08 Dec 15 olle 2275         info.dilutionFactor = dilutionFactor;
3652 08 Dec 15 olle 2276         info.volAliquotSolution = volAliquotSolution;
3652 08 Dec 15 olle 2277         info.volDnaInSolution = volDnaInSolution;
3652 08 Dec 15 olle 2278         info.waterInSolution = waterInSolution;
3652 08 Dec 15 olle 2279 /*        
3652 08 Dec 15 olle 2280         if (info.remainingQuantity != null)
3652 08 Dec 15 olle 2281         {
3652 08 Dec 15 olle 2282           //text += '<div class="quantity">'+Numbers.formatNumber(info.remainingQuantity, 2) + 'µg</div>';
3652 08 Dec 15 olle 2283           var quantityLeft = 1000.0*info.remainingQuantity - 2*usedQuantity; // ng
3652 08 Dec 15 olle 2284 //alert("select_dna.js::painter.getWellText(): name = " + dna.name + " info.remainingQuantity = " + info.remainingQuantity + " µg usedQuantity = " + usedQuantity + " ng quantityLeft = " + quantityLeft + " ng");
3652 08 Dec 15 olle 2285           //text += '<div class="quantity">'+Numbers.formatNumber(quantityLeft, 2) + 'µg '+Numbers.formatNumber(volDNA, 1)+'µl</div>';
3652 08 Dec 15 olle 2286           text += '<div class="quantity">'+Numbers.formatNumber(usedQuantity, 2) + 'ng '+Numbers.formatNumber(volDNA, 1)+'µl</div>';
3652 08 Dec 15 olle 2287
3652 08 Dec 15 olle 2288           // Must have at least 1.1µg or 1.22µg (if default values are used)
3652 08 Dec 15 olle 2289           var remainLimit = dna.qc ? QUANTITY_QC : QUANTITY_REGULAR;
3652 08 Dec 15 olle 2290 */
3652 08 Dec 15 olle 2291 /*
3652 08 Dec 15 olle 2292           if (info.remainingQuantity < remainLimit)
3652 08 Dec 15 olle 2293           {
3652 08 Dec 15 olle 2294             well.setError('Not enough DNA');
3652 08 Dec 15 olle 2295           }
3652 08 Dec 15 olle 2296           // Warning if near the limit
3652 08 Dec 15 olle 2297           if (info.remainingQuantity < LOW_QUANTITY_WARNING_LIMIT && !info.preNormalized)
3652 08 Dec 15 olle 2298           {
3652 08 Dec 15 olle 2299             warningMsg[warningMsg.length] = 'Low quantity';
3652 08 Dec 15 olle 2300           }
3652 08 Dec 15 olle 2301 */
3652 08 Dec 15 olle 2302 /*
3652 08 Dec 15 olle 2303           if (quantityLeft < 1000.0*remainLimit)
3652 08 Dec 15 olle 2304           {
3652 08 Dec 15 olle 2305             well.setError('Not enough DNA');
3652 08 Dec 15 olle 2306           }
3652 08 Dec 15 olle 2307           // Warning if near the limit
3652 08 Dec 15 olle 2308           if (quantityLeft < 1000.0*LOW_QUANTITY_WARNING_LIMIT && !info.preNormalized)
3652 08 Dec 15 olle 2309           {
3652 08 Dec 15 olle 2310             warningMsg[warningMsg.length] = 'Low quantity';
3652 08 Dec 15 olle 2311           }
3652 08 Dec 15 olle 2312 */
3652 08 Dec 15 olle 2313 /*
3652 08 Dec 15 olle 2314         }
3652 08 Dec 15 olle 2315         else
3652 08 Dec 15 olle 2316         {
3652 08 Dec 15 olle 2317           warningMsg[warningMsg.length] = 'No quantity';
3652 08 Dec 15 olle 2318         }
3652 08 Dec 15 olle 2319 */
3652 08 Dec 15 olle 2320         // --- Used volume+water
3667 15 Dec 15 olle 2321         if (info.origQubitConc != null)
3652 08 Dec 15 olle 2322         {
3652 08 Dec 15 olle 2323           text += '<div class="volumes"><span class="volume">'+Numbers.formatNumber(volDNA, 2)+'</span> + <span class="water">'+Numbers.formatNumber(water, 2)+'µl</span></div>';
3652 08 Dec 15 olle 2324         }
3652 08 Dec 15 olle 2325         // --- ΔCt
3667 15 Dec 15 olle 2326         if (info.origDeltaCt != null)
3652 08 Dec 15 olle 2327         {
3667 15 Dec 15 olle 2328           text += '<div class="quality-score">ΔCt='+Numbers.formatNumber(info.origDeltaCt, 2) + '</div>';
3667 15 Dec 15 olle 2329           if (info.origDeltaCt > QUALITY_SCORE_WARNING_LIMIT)
3652 08 Dec 15 olle 2330           {
3652 08 Dec 15 olle 2331             if (!painter.hasClass('plate', 'hide-quality-score'))
3652 08 Dec 15 olle 2332             {
3652 08 Dec 15 olle 2333               warningMsg[warningMsg.length] = 'High ΔCt value';
3652 08 Dec 15 olle 2334             }
3652 08 Dec 15 olle 2335           }
3652 08 Dec 15 olle 2336         }
3652 08 Dec 15 olle 2337         else
3652 08 Dec 15 olle 2338         {
3652 08 Dec 15 olle 2339           if (!painter.hasClass('plate', 'hide-quality-score'))
3652 08 Dec 15 olle 2340           {
3652 08 Dec 15 olle 2341             warningMsg[warningMsg.length] = 'No ΔCt value';
3652 08 Dec 15 olle 2342           }
3652 08 Dec 15 olle 2343         }
3652 08 Dec 15 olle 2344         // --- QubitConc
3667 15 Dec 15 olle 2345         if (info.origQubitConc)
3652 08 Dec 15 olle 2346         {
3667 15 Dec 15 olle 2347           text += '<div class="origqubitconc">'+Numbers.formatNumber(info.origQubitConc, 2) + 'ng/µl (orig.)</div>';
3667 15 Dec 15 olle 2348           text += '<div class="calcqubitconc">'+Numbers.formatNumber(calcConc, 2) + 'ng/µl (calc.)</div>';
3652 08 Dec 15 olle 2349         }
3652 08 Dec 15 olle 2350         else
3652 08 Dec 15 olle 2351         {
3667 15 Dec 15 olle 2352           if (!painter.hasClass('plate', 'hide-origqubitconc'))
3652 08 Dec 15 olle 2353           {
3652 08 Dec 15 olle 2354             warningMsg[warningMsg.length] = 'No QubitConc value';
3652 08 Dec 15 olle 2355           }
3652 08 Dec 15 olle 2356         }
3652 08 Dec 15 olle 2357 /*
3652 08 Dec 15 olle 2358         if (info.QiacubeDate)
3652 08 Dec 15 olle 2359         {
3652 08 Dec 15 olle 2360           text += '<div class="qiacube-date">'+info.QiacubeDate+'</div>';
3652 08 Dec 15 olle 2361         }
3652 08 Dec 15 olle 2362         else if (info.DilutionDate)
3652 08 Dec 15 olle 2363         {
3652 08 Dec 15 olle 2364           text += '<div class="dilution-date">'+info.DilutionDate+'</div>';
3652 08 Dec 15 olle 2365         }
3652 08 Dec 15 olle 2366         else
3652 08 Dec 15 olle 2367         {
3652 08 Dec 15 olle 2368           warningMsg[warningMsg.length] = info.preNormalized ? 'No DilutionDate value' : 'No QiacubeDate value';
3652 08 Dec 15 olle 2369         }
3652 08 Dec 15 olle 2370 */
3652 08 Dec 15 olle 2371         if (info.AutoProcessing)
3652 08 Dec 15 olle 2372         {
3652 08 Dec 15 olle 2373           warningMsg[warningMsg.length] = info.AutoProcessing;
3652 08 Dec 15 olle 2374         }
3652 08 Dec 15 olle 2375 /*
3652 08 Dec 15 olle 2376         dna.usedQuantity = dna.qc ? QUANTITY_QC : QUANTITY_REGULAR; // µg
3652 08 Dec 15 olle 2377         dna.dilutionConc = 1000 * dna.usedQuantity / TOTAL_VOLUME; // ng/µl
3652 08 Dec 15 olle 2378
3667 15 Dec 15 olle 2379         var volDNA = Math.ceil(10000*dna.usedQuantity/info.origQubitConc) / 10; // µl, rounded to 1 decimal
3652 08 Dec 15 olle 2380         var water = TOTAL_VOLUME - volDNA;
3652 08 Dec 15 olle 2381         
3652 08 Dec 15 olle 2382         if (volDNA < MINIMAL_DNA_VOLUME)
3652 08 Dec 15 olle 2383         {
3652 08 Dec 15 olle 2384           // Large mix since we do not want to take less than 1µl
3652 08 Dec 15 olle 2385           volDNA = MINIMAL_DNA_VOLUME;
3667 15 Dec 15 olle 2386           dna.usedQuantity = volDNA * info.origQubitConc / 1000; // µg
3652 08 Dec 15 olle 2387           var totalVolume = 1000 * dna.usedQuantity / dna.dilutionConc; // µl
3652 08 Dec 15 olle 2388           water = totalVolume - volDNA;
3652 08 Dec 15 olle 2389           warningMsg[warningMsg.length] = 'Large mix';
3652 08 Dec 15 olle 2390         }
3652 08 Dec 15 olle 2391         
3652 08 Dec 15 olle 2392         if (info.remainingQuantity)
3652 08 Dec 15 olle 2393         {
3652 08 Dec 15 olle 2394           //text += '<div class="quantity">'+Numbers.formatNumber(info.remainingQuantity, 2) + 'µg</div>';
3652 08 Dec 15 olle 2395           text += '<div class="quantity">'+Numbers.formatNumber(info.remainingQuantity, 2) + 'µg '+Numbers.formatNumber(volDNA, 1)+'µl</div>';
3652 08 Dec 15 olle 2396           // Must have at least 1.1µg or 1.22µg (if default values are used)
3652 08 Dec 15 olle 2397           var remainLimit = dna.qc ? QUANTITY_QC : QUANTITY_REGULAR;
3652 08 Dec 15 olle 2398           if (info.remainingQuantity < remainLimit)
3652 08 Dec 15 olle 2399           {
3652 08 Dec 15 olle 2400             well.setError('Not enough DNA');
3652 08 Dec 15 olle 2401           }
3652 08 Dec 15 olle 2402           // Warning if near the limit
3652 08 Dec 15 olle 2403           if (info.remainingQuantity < LOW_QUANTITY_WARNING_LIMIT && !info.preNormalized)
3652 08 Dec 15 olle 2404           {
3652 08 Dec 15 olle 2405             warningMsg[warningMsg.length] = 'Low quantity';
3652 08 Dec 15 olle 2406           }
3652 08 Dec 15 olle 2407         }
3652 08 Dec 15 olle 2408         else
3652 08 Dec 15 olle 2409         {
3652 08 Dec 15 olle 2410           warningMsg[warningMsg.length] = 'No quantity';
3652 08 Dec 15 olle 2411         }
3677 18 Dec 15 olle 2412         if (info.origDeltaCt)
3652 08 Dec 15 olle 2413         {
3677 18 Dec 15 olle 2414           text += '<div class="quality-score">ΔCt='+Numbers.formatNumber(info.origDeltaCt, 1) + '</div>';
3677 18 Dec 15 olle 2415           if (info.origDeltaCt > QUALITY_SCORE_WARNING_LIMIT) warningMsg[warningMsg.length] = 'High ΔCt value';
3652 08 Dec 15 olle 2416         }
3652 08 Dec 15 olle 2417         else
3652 08 Dec 15 olle 2418         {
3652 08 Dec 15 olle 2419           warningMsg[warningMsg.length] = 'No ΔCt value';
3652 08 Dec 15 olle 2420         }
3667 15 Dec 15 olle 2421         if (info.origQubitConc)
3652 08 Dec 15 olle 2422         {
3667 15 Dec 15 olle 2423           text += '<div class="origqubitconc">'+Numbers.formatNumber(info.origQubitConc, 2) + 'ng/µl</div>';
3652 08 Dec 15 olle 2424           text += '<div class="volumes"><span class="volume">'+Numbers.formatNumber(volDNA, 1)+'</span> + <span class="water">'+Numbers.formatNumber(water, 1)+'µl</span></div>';
3652 08 Dec 15 olle 2425         }
3652 08 Dec 15 olle 2426         else
3652 08 Dec 15 olle 2427         {
3652 08 Dec 15 olle 2428           warningMsg[warningMsg.length] = 'No QubitConc value';
3652 08 Dec 15 olle 2429         }
3652 08 Dec 15 olle 2430         if (info.QiacubeDate)
3652 08 Dec 15 olle 2431         {
3652 08 Dec 15 olle 2432           text += '<div class="qiacube-date">'+info.QiacubeDate+'</div>';
3652 08 Dec 15 olle 2433         }
3652 08 Dec 15 olle 2434         else if (info.DilutionDate)
3652 08 Dec 15 olle 2435         {
3652 08 Dec 15 olle 2436           text += '<div class="dilution-date">'+info.DilutionDate+'</div>';
3652 08 Dec 15 olle 2437         }
3652 08 Dec 15 olle 2438         else
3652 08 Dec 15 olle 2439         {
3652 08 Dec 15 olle 2440           warningMsg[warningMsg.length] = info.preNormalized ? 'No DilutionDate value' : 'No QiacubeDate value';
3652 08 Dec 15 olle 2441         }
3652 08 Dec 15 olle 2442         if (info.AutoProcessing)
3652 08 Dec 15 olle 2443         {
3652 08 Dec 15 olle 2444           warningMsg[warningMsg.length] = info.AutoProcessing;
3652 08 Dec 15 olle 2445         }
3652 08 Dec 15 olle 2446 */
3652 08 Dec 15 olle 2447       }
3667 15 Dec 15 olle 2448       else if (!dna.origId)
3652 08 Dec 15 olle 2449       {
3652 08 Dec 15 olle 2450         well.setError('DNA not found');
3652 08 Dec 15 olle 2451       }
3652 08 Dec 15 olle 2452       if (dna.comment)
3652 08 Dec 15 olle 2453       {
3652 08 Dec 15 olle 2454         text += '<div class="comment">'+Strings.encodeTags(dna.comment)+'</div>';
3652 08 Dec 15 olle 2455       }
3652 08 Dec 15 olle 2456       if (info && info.comment)
3652 08 Dec 15 olle 2457       {
3652 08 Dec 15 olle 2458         text += '<div class="comment">'+Strings.encodeTags(info.comment)+'</div>';
3652 08 Dec 15 olle 2459       }
3652 08 Dec 15 olle 2460       if (warningMsg.length > 0)
3652 08 Dec 15 olle 2461       {
3652 08 Dec 15 olle 2462         well.setWarning(warningMsg.join('; '));
3652 08 Dec 15 olle 2463       }
3652 08 Dec 15 olle 2464       // Index 1 & 2 primers
3652 08 Dec 15 olle 2465       var row = well.row + 1;
3652 08 Dec 15 olle 2466       var column = well.column + 1;
3652 08 Dec 15 olle 2467       var index2 = 'A50' + row;
3652 08 Dec 15 olle 2468       var index1 = 'A70' + column;
3652 08 Dec 15 olle 2469       if (column > 9)
3652 08 Dec 15 olle 2470       {
3652 08 Dec 15 olle 2471         index1 = 'A7' + column;
3652 08 Dec 15 olle 2472       }
3652 08 Dec 15 olle 2473       text += '<div class="indexprimer">'+index2+'</div>';
3652 08 Dec 15 olle 2474       text += '<div class="indexprimer">'+index1+'</div>';
3652 08 Dec 15 olle 2475     }
3652 08 Dec 15 olle 2476     else if (well.copyText)
3652 08 Dec 15 olle 2477     {
3652 08 Dec 15 olle 2478       text = '<div class="copy-text">'+well.copyText+'</div>';
3652 08 Dec 15 olle 2479     }
3652 08 Dec 15 olle 2480     else
3652 08 Dec 15 olle 2481     {
3652 08 Dec 15 olle 2482       text = 'empty';
3652 08 Dec 15 olle 2483     }
3652 08 Dec 15 olle 2484     if (well.duplicate)
3652 08 Dec 15 olle 2485     {
3652 08 Dec 15 olle 2486       well.setError('Duplicate barcode');
3652 08 Dec 15 olle 2487     }
3652 08 Dec 15 olle 2488
3652 08 Dec 15 olle 2489     var bc = Doc.element('barcode.'+well.row+'.'+well.column);
3652 08 Dec 15 olle 2490     if (bc)
3652 08 Dec 15 olle 2491     {
3652 08 Dec 15 olle 2492       var cls = 'barcode-well'
3652 08 Dec 15 olle 2493       cls += well.column == 0 ? ' barcode-left' : ' barcode-right';
3652 08 Dec 15 olle 2494
3652 08 Dec 15 olle 2495       if (well.barcode)
3652 08 Dec 15 olle 2496       {
3652 08 Dec 15 olle 2497         bc.innerHTML = well.barcode.name;
3652 08 Dec 15 olle 2498         var indexSet = painter.barcodeVariant ? painter.barcodeVariant.indexSets[well.column] : null;
3652 08 Dec 15 olle 2499         if (indexSet)
3652 08 Dec 15 olle 2500         {
3652 08 Dec 15 olle 2501           cls += ' ' + indexSet.color;
3652 08 Dec 15 olle 2502         }
3652 08 Dec 15 olle 2503         if (well.defaultBarcode && well.barcode != well.defaultBarcode)
3652 08 Dec 15 olle 2504         {
3652 08 Dec 15 olle 2505           cls += ' bg-modified';
3652 08 Dec 15 olle 2506         }
3652 08 Dec 15 olle 2507         if (well.duplicate)
3652 08 Dec 15 olle 2508         {
3652 08 Dec 15 olle 2509           cls += ' duplicate';
3652 08 Dec 15 olle 2510         }
3652 08 Dec 15 olle 2511       }
3652 08 Dec 15 olle 2512       bc.className = cls;
3652 08 Dec 15 olle 2513     }
3652 08 Dec 15 olle 2514     return text;
3652 08 Dec 15 olle 2515   }
3652 08 Dec 15 olle 2516
3652 08 Dec 15 olle 2517   /**
3652 08 Dec 15 olle 2518    * Returns `true` if HTML element with id 'elementId' has
3652 08 Dec 15 olle 2519    * class 'cls', else `false`.
3652 08 Dec 15 olle 2520    */
3652 08 Dec 15 olle 2521   painter.hasClass = function(elementId, cls)
3652 08 Dec 15 olle 2522   {
3652 08 Dec 15 olle 2523     var element = document.getElementById(elementId);
3652 08 Dec 15 olle 2524     return (' ' + element.className + ' ').indexOf(' ' + cls + ' ') > -1;
3652 08 Dec 15 olle 2525   }
3652 08 Dec 15 olle 2526
3652 08 Dec 15 olle 2527   painter.fetchDilutionFactor = function(deltaCt)
3652 08 Dec 15 olle 2528   {
3652 08 Dec 15 olle 2529     var dilutionFactor = 1.0;
3652 08 Dec 15 olle 2530 /*
3652 08 Dec 15 olle 2531     // Illumina ladder dilution chart
3652 08 Dec 15 olle 2532     if (deltaCt > 0.5 && deltaCt <= 1.5)
3652 08 Dec 15 olle 2533     {
3652 08 Dec 15 olle 2534       dilutionFactor = 2.0;
3652 08 Dec 15 olle 2535     }
3652 08 Dec 15 olle 2536     if (deltaCt > -0.5 && deltaCt <= 0.5)
3652 08 Dec 15 olle 2537     {
3652 08 Dec 15 olle 2538       dilutionFactor = 4.0;
3652 08 Dec 15 olle 2539     }
3652 08 Dec 15 olle 2540     if (deltaCt > -1.5 && deltaCt <= -0.5)
3652 08 Dec 15 olle 2541     {
3652 08 Dec 15 olle 2542       dilutionFactor = 8.0;
3652 08 Dec 15 olle 2543     }
3652 08 Dec 15 olle 2544     if (deltaCt <=- 1.5)
3652 08 Dec 15 olle 2545     {
3652 08 Dec 15 olle 2546       dilutionFactor = 16.0;
3652 08 Dec 15 olle 2547     }
3652 08 Dec 15 olle 2548 */
3652 08 Dec 15 olle 2549     // Dilution curve fitted to centers of ladder steps in Illumina ladder dilution chart (Mats Jönsson 2015-09-28)
3652 08 Dec 15 olle 2550     var fact = 2.8284271247;
3652 08 Dec 15 olle 2551     var expFact = 0.6931471806;
3652 08 Dec 15 olle 2552     dilutionFactor = fact * Math.exp(-expFact*deltaCt);
3652 08 Dec 15 olle 2553     // Apply cut-offs restricting the dilution factor to [1.0, 16.0]
3652 08 Dec 15 olle 2554     if (dilutionFactor < 1.0)
3652 08 Dec 15 olle 2555     {
3652 08 Dec 15 olle 2556       dilutionFactor = 1.0;
3652 08 Dec 15 olle 2557     }
3652 08 Dec 15 olle 2558     if (dilutionFactor > 16.0)
3652 08 Dec 15 olle 2559     {
3652 08 Dec 15 olle 2560       dilutionFactor = 16.0;
3652 08 Dec 15 olle 2561     }
3652 08 Dec 15 olle 2562     return dilutionFactor;
3652 08 Dec 15 olle 2563   }
3652 08 Dec 15 olle 2564   
3652 08 Dec 15 olle 2565   return painter;
3652 08 Dec 15 olle 2566 }();