diff -r de4a74899969 -r 5714ea86187d www/js/rec_view.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/www/js/rec_view.js Fri Aug 05 10:53:56 2022 +0200 @@ -0,0 +1,2055 @@ +/***************************************************************************** + * Copyright (C) 2018-2022 + * + * Michiel Broek + * + * This file is part of BMS + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * BrewCloud is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ThermFerm; see the file COPYING. If not, write to the Free + * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + *****************************************************************************/ + + var psugar = 0, // Percentage real sugars + pcara = 0, // Percentage cara/crystal malts + svg = 77, // Default attenuation + mashkg = 0, // Malt in mash weight + mash_infuse = 0, + dataRecord = {}, // Main recipe record + hop_flavour = 0, + hop_aroma = 0, + preboil_sg = 0, + last_base = '', + last_acid = '', + Ka1 = 0.0000004445, + Ka2 = 0.0000000000468, + error_count = 0, + MMCa = 40.048, + MMMg = 24.305, + MMNa = 22.98976928, + MMCl = 35.453, + MMSO4 = 96.0626, + MMCO3 = 60.01684, + MMHCO3 = 61.01684, + MMCaSO4 = 172.171, + MMCaCl2 = 147.015, + MMCaCO3 = 100.087, + MMMgCl2 = 95.211, /* Since 27-06-2021 */ + MMMgSO4 = 246.475, + MMNaHCO3 = 84.007, + MMNa2CO3 = 105.996, + MMNaCl = 58.443, + MMCaOH2 = 74.06268, + SpecificHeatWater = 1.0, + SpecificHeatMalt = 0.399, //cal/g.°C + SlakingHeat = 10.318, //cal/g.°C + eq_tun_weight = 2.0, // 2 Kg pot + eq_tun_specific_heat = 0.110, // Stainless Steel + data_loaded = 0; + +function hopFlavourContribution(bt, vol, use, amount) { + var result; + + if (use == 4 || use == 5) // Whirlpool or Dry-hop + return 0; + if (use == 1) { // First wort + result = 0.15; // assume 15% flavourcontribution for fwh + } else if (bt > 50) { + result = 0.10; // assume 10% flavourcontribution as a minimum + } else { + result = 15.25 / (6 * Math.sqrt(2 * Math.PI)) * Math.exp(-0.5 * Math.pow((bt - 21) / 6, 2)); + if (result < 0.10) + result = 0.10; // assume 10% flavourcontribution as a minimum + } + return (result * amount * 1000) / vol; +} + + +function hopAromaContribution(bt, vol, use, amount) { + var result = 0; + + if (use == 5) { // Dry hop + result = 1.33; + } else if (use == 4) { // Whirlpool + if (bt > 30) + bt = 30; // Max 30 minutes + result = 0.62 * bt / 30; + } else if (bt > 20) { + result = 0; + } else if (bt > 7.5) { + result = 10.03 / (4 * Math.sqrt(2 * Math.PI)) * Math.exp(-0.5 * Math.pow((bt - 7.5) / 4, 2)); + } else if (use == 2) { // Boil + result = 1; + } else if (use == 3) { // Aroma + result = 1.2; + } + return (result * amount * 1000) / vol; +} + + +function calcFermentables() { + console.log('calcFermentables()'); + var i, row, rows, org, s = 0, d, x, + sug, alc, cw, color, scolor, fig, + sugarsf = 0, // fermentable sugars mash + boil + sugarsm = 0; // fermentable sugars in mash + vol = 0, // Volume sugars after boil + addedS = 0, // Added sugars after boil + addedmass = 0, // Added mass after boil + mvol = 0, // mash volume + colort = 0, // Colors srm * vol totals + colorh = 0, // Colors ebc * vol * kt + colorn = 0, // Colors ebc * pt * pct + my_100 = false, + mashtime = 0, // Total mash time + mashtemp = 0, // Average mash temperature + bv = 0.925, // Bierverlies rendement + sr = 0.95, // Mash en spoel rendement + lintner = 0; // Total recipe lintner + /* Init global variables */ + psugar = 0; + pcara = 0; + mashkg = 0; + + if ((rows = $('#mashGrid').jqxGrid('getrows'))) { + for (i = 0; i < rows.length; i++) { + row = rows[i]; + if (row.step_type == 0) // Infusion + mvol += parseFloat(row.step_infuse_amount); + if (row.step_temp <= 75) { // Ignore mashout + mashtime += row.step_time; + mashtemp += row.step_time * row.step_temp; + } + } + mashtemp = mashtemp / mashtime; + } + + if (!(rows = $('#fermentableGrid').jqxGrid('getrows'))) { + return; // grid not yet loaded. + } + + for (i = 0; i < rows.length; i++) { + row = rows[i]; + if (row.f_adjust_to_total_100) + my_100 = true; + if (row.f_type == 1 && row.f_added < 4) // Sugar + psugar += row.f_percentage; + if (row.f_graintype == 2 && row.f_added < 4) // Crystal + pcara += row.f_percentage; + d = row.f_amount * (row.f_yield / 100) * (1 - row.f_moisture / 100); + if (row.f_added == 0) { // Mash + if (mvol > 0) { // Only if mash already known + mvol += row.f_amount * row.f_moisture / 100; + s += d; + } + d = parseFloat(dataRecord.efficiency) / 100 * d; + sugarsm += d; + mashkg += row.f_amount; + } + if (row.f_added == 0 || row.f_added == 1) // Mash or Boil + sugarsf += d; + if (row.f_added == 2 || row.f_added == 3) { // Fermentation or lagering + x = (row.f_yield / 100) * (1 - row.f_moisture / 100); + addedS += row.f_amount * x; + addedmass += row.f_amount; + vol += (x * sugardensity + (1 - x) * 1) * row.f_amount; + } + if (row.f_added == 0 && (row.f_type == 0 || row.f_type == 4) && row.f_color < 50) { // Mash and Grain/Adjunct and Color < 50 + lintner += row.f_diastatic_power * row.f_amount; + } + if (row.f_added < 4) { + colort += row.f_amount * ebc_to_srm(row.f_color); + colorh += row.f_amount * row.f_color * get_kt(row.f_color); + colorn += (row.f_percentage / 100) * row.f_color; // For 8.6 Pt wort. + } + } + $('#ferm_lintner').val(Math.round(parseFloat(lintner / mashkg))); + to_100 = my_100; + + // Estimate total recipe OG. + dataRecord.est_og = estimate_sg(sugarsf + addedS, parseFloat(dataRecord.batch_size)); + $('#est_og').val(dataRecord.est_og); + $('#est_og2').val(dataRecord.est_og); + org = dataRecord.est_og; + + // Estimate SG in kettle before boil + preboil_sg = estimate_sg(sugarsm, parseFloat(dataRecord.boil_size)); + + // Color of the wort + if (dataRecord.color_method == 4) { + color = Math.round(((sg_to_plato(dataRecord.est_og) / 8.6) * colorn) + (dataRecord.boil_time / 60)); + } else if (dataRecord.color_method == 3) { // Hans Halberstadt + color = Math.round((4.46 * bv * sr) / parseFloat(dataRecord.batch_size) * colorh); + } else { + cw = colort / parseFloat(dataRecord.batch_size) * 8.34436; + color = kw_to_ebc(dataRecord.color_method, cw); + } + dataRecord.est_color = color; + $('#est_color').val(color); + $('#est_color2').val(color); + scolor = ebc_to_color(color); + document.getElementById('bcolor').style.background = scolor; + document.getElementById('bcolor2').style.background = scolor; + + // Progress bars + pmalts = mashkg / (dataRecord.boil_size / 3) * 100; + $('#perc_malts').jqxProgressBar('val', pmalts); + $('#perc_sugars').jqxProgressBar('val', psugar); + $('#perc_cara').jqxProgressBar('val', pcara); + + // Calculate estimated svg. + svg = 0; // default. + rows = $('#yeastGrid').jqxGrid('getrows'); + for (i = 0; i < rows.length; i++) { + row = rows[i]; + if (row.y_use == 0) { // Primary + if (parseFloat(row.y_attenuation) > svg) + svg = parseFloat(row.y_attenuation); // Take the highest if multiple yeasts. + } + // TODO: brett in secondary ?? + } + if (svg == 0) + svg = 77; + + if ((mashkg > 0) && (mash_infuse > 0) && (mashtime > 0) && (mashtemp > 0)) { + dataRecord.est_fg = estimate_fg(psugar, pcara, mash_infuse / mashkg, mashtime, mashtemp, svg, dataRecord.est_og); + } else { + dataRecord.est_fg = estimate_fg(psugar, pcara, 0, 0, 0, svg, dataRecord.est_og); + } + $('#est_fg').val(dataRecord.est_fg); + $('#est_fg2').val(dataRecord.est_fg); + fig = dataRecord.est_fg; + + dataRecord.est_abv = abvol(dataRecord.est_og, dataRecord.est_fg); + $('#est_abv').val(dataRecord.est_abv); + $('#est_abv2').val(dataRecord.est_abv); + + // Calculate the calories in kcal/l (from brouwhulp) + alc = 1881.22 * fig * (org - fig) / (1.775 - org); + sug = 3550 * fig * (0.1808 * org + 0.8192 * fig - 1.0004); + $('#kcal').val(Math.round((alc + sug) / (12 * 0.0295735296))); +} + + +function infusionVol(step_infused, step_mashkg, infuse_temp, step_temp, last_temp) { + var a = last_temp * (eq_tun_weight * eq_tun_specific_heat + step_infused * SpecificHeatWater + step_mashkg * SpecificHeatMalt); + var b = step_temp * (eq_tun_weight * eq_tun_specific_heat + step_infused * SpecificHeatWater + step_mashkg * SpecificHeatMalt); + var vol = Round(((b - a) / ((infuse_temp - step_temp) * SpecificHeatWater)), 2); + console.log('infusionVol(' + step_infused + ', ' + step_mashkg + ', ' + infuse_temp + ', ' + step_temp + ', ' + last_temp + '): ' + vol); + return vol; +} + + +function decoctionVol(step_volume, step_temp, prev_temp) { + var a = (eq_tun_weight * eq_tun_specific_heat + step_volume * SpecificHeatWater) * (step_temp - prev_temp); + var b = SpecificHeatWater * (99 - step_temp); + var vol = 0; + if (b > 0) + vol = Round(a / b, 6); + console.log('decoctionVol(' + step_volume + ', ' + step_temp + ', ' + prev_temp + '): ' + vol); + return vol; +} + + +function calcMash() { + var infused = 0, vol, i, j, n, a, b, row, rows, temp; + var lasttemp = 18.0; + var graintemp = 18.0; + var tuntemp = 18.0; + + if ((rows = $('#mashGrid').jqxGrid('getrows')) && (mashkg > 0)) { + console.log('calcMash()'); + for (i = 0; i < rows.length; i++) { + row = $('#mashGrid').jqxGrid('getrowdata', i); + if (row.step_type == 0) { // Infusion + if (i == 0) { + // First mash step, temperature from the mashtun and malt. + n = 20; // tun is preheated. + tuntemp = row.step_temp; + for (j = 0; j < n; j++) { + a = mashkg * graintemp * SpecificHeatMalt + eq_tun_weight * tuntemp * eq_tun_specific_heat; + b = row.step_temp * (eq_tun_weight * eq_tun_specific_heat + row.step_infuse_amount * SpecificHeatWater + mashkg * SpecificHeatMalt) - SlakingHeat * mashkg; + if (row.step_infuse_amount > 0) { + temp = (b - a) / (row.step_infuse_amount * SpecificHeatWater); + } else { + temp = 99; + } + tuntemp += (temp - tuntemp) / 2; + row.step_infuse_temp = Round(temp, 6); + } + console.log('init infuse temp: ' + row.step_infuse_temp); + } else { + // Calculate amount of infusion water. + row.step_infuse_amount = infusionVol(infused, mashkg, row.step_infuse_temp, row.step_temp, lasttemp); + //console.log('vol: ' + row.step_infuse_amount + ' temp: ' + row.step_infuse_temp); + } + infused += row.step_infuse_amount; + } else if (row.step_type == 1) { // Temperature + if (i > 0) + row.step_infuse_amount = 0; + row.step_infuse_temp = 0; + } else if (row.step_type == 2) { // Decoction + row.step_infuse_amount = decoctionVol(infused, row.step_temp, lasttemp); + row.step_infuse_temp = 99; + } + row.step_volume = infused; + //console.log(i + ' type: ' + row.step_type + ' volume: ' + row.step_infuse_amount + ' temp: ' + row.step_infuse_temp); + lasttemp = row.step_temp; + mashtime += row.step_time + row.ramp_time; + row.step_wg_ratio = Round(infused / mashkg, 6); + $('#mashGrid').jqxGrid('updaterow', i, row); + } + } +} + + +function GetBUGU() { + var gu = (dataRecord.est_og - 1) * 1000; + if (gu > 0) + return dataRecord.est_ibu / gu; + else + return 0.5; +} + + +function GetOptSO4Clratio() { + var BUGU = GetBUGU(); + return (-1.2 * BUGU + 1.4); +} + + + +function setRangeIndicator(ion, rangeCode) { + if ((rangeCode == 'laag') || (rangeCode == 'hoog')) + $('#wr_' + ion).html('' + rangeCode + ''); + else + $('#wr_' + ion).html(''); +} + + +function mix(v1, v2, c1, c2) { + if ((v1 + v2) > 0) { + return ((v1 * c1) + (v2 * c2)) / (v1 + v2); + } + return 0; +} + + +// mg/l as CaCO3 +function ResidualAlkalinity(total_alkalinity, calcium, magnesium) { + return total_alkalinity - (calcium / 1.4 + magnesium / 1.7); +} + + +function PartCO3(pH) { + var H = Math.pow(10, -pH); + return 100 * Ka1 * Ka2 / (H * H + H * Ka1 + Ka1 * Ka2); +} + + +function PartHCO3(pH) { + var H = Math.pow(10, -pH); + return 100 * Ka1 * H / (H * H + H * Ka1 + Ka1 * Ka2); +} + + +function Charge(pH) { + return (-2 * PartCO3(pH) - PartHCO3(pH)); +} + + +//Z alkalinity is the amount of acid (in mEq/l) needed to bring water to the target pH (Z pH) +function ZAlkalinity(pHZ) { + var C43 = Charge(4.3), + Cw = Charge(parseFloat($('#wg_ph').jqxNumberInput('decimal'))), + Cz = Charge(pHZ), + DeltaCNaught = -C43 + Cw, + CT = parseFloat($('#wg_total_alkalinity').jqxNumberInput('decimal')) / 50 / DeltaCNaught, + DeltaCZ = -Cz + Cw; + return CT * DeltaCZ; +} + + +//Z Residual alkalinity is the amount of acid (in mEq/l) needed to bring the water in the mash to the target pH (Z pH) +function ZRA(pHZ) { + var Calc = parseFloat($('#wg_calcium').jqxNumberInput('decimal')) / (MMCa / 2), + Magn = parseFloat($('#wg_magnesium').jqxNumberInput('decimal')) / (MMMg / 2), + Z = ZAlkalinity(pHZ); + return Z - (Calc / 3.5 + Magn / 7); +} + + +function BufferCapacity(di_ph, acid_to_ph_57, ebc, graintype) { + C1 = 0; + if ((di_ph != 5.7) && ((acid_to_ph_57 < - 0.1) || (acid_to_ph_57 > 0.1))) { + C1 = acid_to_ph_57 / (di_ph - 5.7); + } else { + // If the acid_to_ph_5.7 is unknown from the maltster, guess the required acid. + switch (graintype) { + case 0: // Base, Special, Kilned + case 3: + case 5: C1 = 0.014 * ebc - 34.192; + break; + case 2: C1 = -0.0597 * ebc - 32.457; // Crystal + break; + case 1: C1 = 0.0107 * ebc - 54.768; // Roast + break; + case 4: C1 = -149; // Sour malt + break; + } + } + return C1; +} + + +function ProtonDeficit(pHZ) { + var C1, i, rows, row, Result = ZRA(pHZ) * parseFloat($('#wg_amount').jqxNumberInput('decimal')); + // proton deficit for the grist + if ((rows = $('#fermentableGrid').jqxGrid('getrows'))) { + for (i = 0; i < rows.length; i++) { + row = rows[i]; + if (row.f_added == 0 && row.f_graintype != 6) { // Added == Mash && graintype != No Malt + C1 = BufferCapacity(row.f_di_ph, row.f_acid_to_ph_57, row.f_color, row.f_graintype); + x = C1 * (pHZ - row.f_di_ph); // AcidRequired(ZpH) + Result += x * row.f_amount; + } + } + } else { + error_count++; + if (error_count < 5) + console.log('ProtonDeficit(' + pHZ + ') invalid grist, return ' + Result); + } + return Result; +} + + +function MashpH() { + var n = 0, + pH = 5.4, + deltapH = 0.001, + deltapd = 0.1, + pd = ProtonDeficit(pH); + while (((pd < -deltapd) || (pd > deltapd)) && (n < 2000)) { + n++; + if (pd < -deltapd) + pH -= deltapH; + else if (pd > deltapd) + pH += deltapH; + pd = ProtonDeficit(pH); + } + pH = Round(pH, 6); + //console.log('MashpH() n: ' + n + ' pH: ' + pH); + return pH; +} + + + + +$(document).ready(function() { + + var to_100 = false, // Fermentables adjust to 100% + + fermentableRow = 0, + fermentableData = {}, + hopRow = 0, + hopData = {}, + miscRow = 0, + miscData = {}, + yeastRow = 0, + yeastData = {}, + mashRow = 0, + mashData = {}, + + url = 'includes/db_recipes.php', + // prepare the data + source = { + datatype: 'json', + cache: false, + datafields: [ + { name: 'record', type: 'number' }, + { name: 'uuid', type: 'string' }, + { name: 'locked', type: 'int' }, + { name: 'st_name', type: 'string' }, + { name: 'st_letter', type: 'string' }, + { name: 'st_guide', type: 'string' }, + { name: 'st_type', type: 'int' }, + { name: 'st_category', type: 'string' }, + { name: 'st_category_number', type: 'int' }, + { name: 'st_og_min', type: 'float' }, + { name: 'st_og_max', type: 'float' }, + { name: 'st_fg_min', type: 'float' }, + { name: 'st_fg_max', type: 'float' }, + { name: 'st_ibu_min', type: 'float' }, + { name: 'st_ibu_max', type: 'float' }, + { name: 'st_color_min', type: 'float' }, + { name: 'st_color_max', type: 'float' }, + { name: 'st_carb_min', type: 'float' }, + { name: 'st_carb_max', type: 'float' }, + { name: 'st_abv_min', type: 'float' }, + { name: 'st_abv_max', type: 'float' }, + { name: 'name', type: 'string' }, + { name: 'notes', type: 'string' }, + { name: 'type', type: 'int' }, + { name: 'batch_size', type: 'float' }, + { name: 'boil_size', type: 'float' }, + { name: 'boil_time', type: 'float' }, + { name: 'efficiency', type: 'float' }, + { name: 'est_og', type: 'float' }, + { name: 'est_fg', type: 'float' }, + { name: 'est_abv', type: 'float' }, + { name: 'est_color', type: 'float' }, + { name: 'color_method', type: 'int' }, + { name: 'est_ibu', type: 'float' }, + { name: 'ibu_method', type: 'int' }, + { name: 'est_carb', type: 'float' }, + { name: 'sparge_temp', type: 'float' }, + { name: 'sparge_ph', type: 'float' }, + { name: 'sparge_volume', type: 'float' }, + { name: 'sparge_source', type: 'int' }, + { name: 'sparge_acid_type', type: 'int' }, + { name: 'sparge_acid_perc', type: 'float' }, + { name: 'sparge_acid_amount', type: 'float' }, + { name: 'mash_ph', type: 'float' }, + { name: 'mash_name', type: 'string' }, + { name: 'calc_acid', type: 'int' }, + { name: 'w1_name', type: 'string' }, + { name: 'w1_amount', type: 'float' }, + { name: 'w1_calcium', type: 'float' }, + { name: 'w1_sulfate', type: 'float' }, + { name: 'w1_chloride', type: 'float' }, + { name: 'w1_sodium', type: 'float' }, + { name: 'w1_magnesium', type: 'float' }, + { name: 'w1_total_alkalinity', type: 'float' }, + { name: 'w1_ph', type: 'float' }, + { name: 'w1_cost', type: 'float' }, + { name: 'w2_name', type: 'string' }, + { name: 'w2_amount', type: 'float' }, + { name: 'w2_calcium', type: 'float' }, + { name: 'w2_sulfate', type: 'float' }, + { name: 'w2_chloride', type: 'float' }, + { name: 'w2_sodium', type: 'float' }, + { name: 'w2_magnesium', type: 'float' }, + { name: 'w2_total_alkalinity', type: 'float' }, + { name: 'w2_ph', type: 'float' }, + { name: 'w2_cost', type: 'float' }, + { name: 'wg_amount', type: 'float' }, + { name: 'wg_calcium', type: 'float' }, + { name: 'wg_sulfate', type: 'float' }, + { name: 'wg_chloride', type: 'float' }, + { name: 'wg_sodium', type: 'float' }, + { name: 'wg_magnesium', type: 'float' }, + { name: 'wg_total_alkalinity', type: 'float' }, + { name: 'wg_ph', type: 'float' }, + { name: 'wb_calcium', type: 'float' }, + { name: 'wb_sulfate', type: 'float' }, + { name: 'wb_chloride', type: 'float' }, + { name: 'wb_sodium', type: 'float' }, + { name: 'wb_magnesium', type: 'float' }, + { name: 'wb_total_alkalinity', type: 'float' }, + { name: 'wb_ph', type: 'float' }, + { name: 'wa_acid_name', type: 'int' }, + { name: 'wa_acid_perc', type: 'int' }, + { name: 'wa_base_name', type: 'int' }, + { name: 'fermentables', type: 'string' }, + { name: 'hops', type: 'string' }, + { name: 'miscs', type: 'string' }, + { name: 'yeasts', type: 'string' }, + { name: 'mashs', type: 'string' } + ], + id: 'record', + url: url + '?record=' + my_record + }, + // Load data and select one record. + dataAdapter = new $.jqx.dataAdapter(source, { + loadComplete: function() { + var records = dataAdapter.records; + dataRecord = records[0]; + // Hidden record uuid + $('#name').val(dataRecord.name); + $('#notes').val(dataRecord.notes); + // Hidden record locked + $('#st_name').val(dataRecord.st_name); + $('#st_letter').val(dataRecord.st_letter); + $('#st_guide').val(dataRecord.st_guide); + $('#st_category').val(dataRecord.st_category); + $('#st_category_number').val(dataRecord.st_category_number); + $('#st_type').val(StyleTypeData[dataRecord.st_type].nl); + $('#type').val(RecipeTypeData[dataRecord.type].nl); + $('#batch_size').val(dataRecord.batch_size); + $('#boil_size').val(dataRecord.boil_size); + $('#boil_time').val(dataRecord.boil_time); + $('#efficiency').val(dataRecord.efficiency); + $('#est_og').val(dataRecord.est_og); + $('#est_og2').val(dataRecord.est_og); + $('#st_og_min').val(dataRecord.st_og_min); + $('#st_og_max').val(dataRecord.st_og_max); + $('#est_fg').val(dataRecord.est_fg); + $('#est_fg2').val(dataRecord.est_fg); + $('#st_fg_min').val(dataRecord.st_fg_min); + $('#st_fg_max').val(dataRecord.st_fg_max); + $('#est_fg').val(dataRecord.est_fg); + $('#est_fg2').val(dataRecord.est_fg); + $('#st_fg_min').val(dataRecord.st_fg_min); + $('#st_fg_max').val(dataRecord.st_fg_max); + $('#est_color').val(dataRecord.est_color); + $('#est_color2').val(dataRecord.est_color); + $('#est_abv').val(dataRecord.est_abv); + $('#est_abv2').val(dataRecord.est_abv); + $('#st_abv_min').val(dataRecord.st_abv_min); + $('#st_abv_max').val(dataRecord.st_abv_max); + $('#st_color_min').val(dataRecord.st_color_min); + $('#st_color_max').val(dataRecord.st_color_max); + $('#color_method').val(ColorMethodData[dataRecord.color_method].nl); + $('#est_ibu').val(dataRecord.est_ibu); + $('#est_ibu2').val(dataRecord.est_ibu); + $('#st_ibu_min').val(dataRecord.st_ibu_min); + $('#st_ibu_max').val(dataRecord.st_ibu_max); + $('#ibu_method').val(IBUmethodData[dataRecord.ibu_method].nl); + $('#est_carb').val(dataRecord.est_carb); + $('#st_carb_min').val(dataRecord.st_carb_min); + $('#st_carb_max').val(dataRecord.st_carb_max); + $('#mash_name').val(dataRecord.mash_name); + $('#mash_ph').val(dataRecord.mash_ph); + // Hidden record sparge_temp + $('#sparge_ph').val(dataRecord.sparge_ph); + $('#sw_amount').val(dataRecord.sparge_volume); + // Hidden record sparge_source + $('#sparge_acid_type').val(AcidTypeData[dataRecord.sparge_acid_type].nl); + $('#sparge_acid_perc').val(dataRecord.sparge_acid_perc); + $('#sparge_acid_amount').val(dataRecord.sparge_acid_amount * 1000); + $('#calc_acid').val(dataRecord.calc_acid); + $('#w1_name').val(dataRecord.w1_name); + $('#w1_amount').val(dataRecord.w1_amount); + $('#w1_calcium').val(dataRecord.w1_calcium); + $('#w1_sulfate').val(dataRecord.w1_sulfate); + $('#w1_chloride').val(dataRecord.w1_chloride); + $('#w1_sodium').val(dataRecord.w1_sodium); + $('#w1_magnesium').val(dataRecord.w1_magnesium); + $('#w1_total_alkalinity').val(dataRecord.w1_total_alkalinity); + $('#w1_ph').val(dataRecord.w1_ph); + $('#w1_bicarbonate').val(Bicarbonate(dataRecord.w1_total_alkalinity, dataRecord.w1_ph)); + $('#w1_cost').val(dataRecord.w1_cost); + $('#w2_name').val(dataRecord.w2_name); + $('#w2_amount').val(dataRecord.w2_amount); + $('#w2_calcium').val(dataRecord.w2_calcium); + $('#w2_sulfate').val(dataRecord.w2_sulfate); + $('#w2_chloride').val(dataRecord.w2_chloride); + $('#w2_sodium').val(dataRecord.w2_sodium); + $('#w2_magnesium').val(dataRecord.w2_magnesium); + $('#w2_total_alkalinity').val(dataRecord.w2_total_alkalinity); + $('#w2_ph').val(dataRecord.w2_ph); + $('#w2_bicarbonate').val(Bicarbonate(dataRecord.w2_total_alkalinity, dataRecord.w2_ph)); + $('#w2_cost').val(dataRecord.w2_cost); + $('#wg_amount').val(dataRecord.wg_amount); + $('#wg_calcium').val(dataRecord.wg_calcium); + $('#wg_sulfate').val(dataRecord.wg_sulfate); + $('#wg_chloride').val(dataRecord.wg_chloride); + $('#wg_sodium').val(dataRecord.wg_sodium); + $('#wg_magnesium').val(dataRecord.wg_magnesium); + $('#wg_total_alkalinity').val(dataRecord.wg_total_alkalinity); + $('#wg_ph').val(dataRecord.wg_ph); + $('#wb_calcium').val(dataRecord.wb_calcium); + $('#wb_sulfate').val(dataRecord.wb_sulfate); + $('#wb_chloride').val(dataRecord.wb_chloride); + $('#wb_sodium').val(dataRecord.wb_sodium); + $('#wb_magnesium').val(dataRecord.wb_magnesium); + $('#wb_total_alkalinity').val(dataRecord.wb_total_alkalinity); + $('#wb_ph').val(dataRecord.wb_ph); + $('#wa_acid_name').val(AcidTypeData[dataRecord.wa_acid_name].nl); + $('#wa_acid_perc').val(dataRecord.wa_acid_perc); + editFermentable(dataRecord); + editHop(dataRecord); + editMisc(dataRecord); + editYeast(dataRecord); + editMash(dataRecord); + $('#jqxTabs').jqxTabs('next'); + data_loaded = 1; + }, + loadError: function(jqXHR, status, error) {}, + beforeLoadComplete: function(records) { $('#jqxLoader').jqxLoader('open'); } + }), + + // Inline fermentables editor + editFermentable = function(data) { + var fermentableSource = { + localdata: data.fermentables, + datafields: [ + { name: 'f_name', type: 'string' }, + { name: 'f_origin', type: 'string' }, + { name: 'f_supplier', type: 'string' }, + { name: 'f_amount', type: 'float' }, + { name: 'f_cost', type: 'float' }, + { name: 'f_type', type: 'int' }, + { name: 'f_yield', type: 'float' }, + { name: 'f_color', type: 'float' }, + { name: 'f_coarse_fine_diff', type: 'float' }, + { name: 'f_moisture', type: 'float' }, + { name: 'f_diastatic_power', type: 'float' }, + { name: 'f_protein', type: 'float' }, + { name: 'f_max_in_batch', type: 'float' }, + { name: 'f_graintype', type: 'int' }, + { name: 'f_added', type: 'int' }, + { name: 'f_dissolved_protein', type: 'float' }, + { name: 'f_recommend_mash', type: 'int' }, + { name: 'f_add_after_boil', type: 'int' }, + { name: 'f_adjust_to_total_100', type: 'int' }, + { name: 'f_percentage', type: 'float' }, + { name: 'f_di_ph', type: 'float' }, + { name: 'f_acid_to_ph_57', type: 'float' }, + { name: 'f_inventory', type: 'float' }, + { name: 'f_avail', type: 'int' } + ], + }, + fermentableAdapter = new $.jqx.dataAdapter(fermentableSource); + + $('#fermentableGrid').jqxGrid({ + width: 1240, + height: 470, + source: fermentableAdapter, + theme: theme, + editable: false, + ready: function() { + calcFermentables(); + $('#jqxTabs').jqxTabs('next'); + }, + columns: [ + { text: 'Vergistbaar ingrediënt', datafield: 'f_name' }, + { text: 'Leverancier', datafield: 'f_supplier', width: 180 }, + { text: 'Kleur', datafield: 'f_color', width: 90, align: 'right', + cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { + return '' + dataAdapter.formatNumber(value, 'f0') + ' EBC'; + } + }, + { text: 'Type', width: 100, datafield: 'f_type', + cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { + return '' + FermentableTypeData[value].nl + ''; + } + }, + { text: 'Moment', width: 110, datafield: 'f_added', + cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { + return '' + AddedData[value].nl + ''; + } + }, + { text: 'Maxinbatch', datafield: 'f_max_in_batch', hidden: true }, + { text: 'Opbrengst', editable: false, datafield: 'f_yield', width: 90, align: 'right', cellsalign: 'right', cellsformat: 'p1' }, + { text: 'Gewicht Kg', datafield: 'f_amount', width: 120, align: 'right', cellsalign: 'right', cellsformat: 'f3' }, + { text: 'Procent', datafield: 'f_percentage', width: 90, align: 'right', + cellsrenderer: function(row, columnfield, value, defaulthtml, columnproperties, rowdata) { + var color = '#ffffff'; + if (value > rowdata.f_max_in_batch) + color = '#ff4040'; + return '' + fermentableAdapter.formatNumber(value, 'p1') + ''; + } + }, + { text: '100%', align: 'center', datafield: 'f_adjust_to_total_100', columntype: 'checkbox', width: 70 } + ] + }); + }; + + // Inline hops editor + var editHop = function(data) { + var hopSource = { + localdata: data.hops, + datafields: [ + { name: 'h_name', type: 'string' }, + { name: 'h_origin', type: 'string' }, + { name: 'h_amount', type: 'float' }, + { name: 'h_cost', type: 'float' }, + { name: 'h_type', type: 'int' }, + { name: 'h_form', type: 'int' }, + { name: 'h_useat', type: 'int' }, + { name: 'h_time', type: 'float' }, + { name: 'h_alpha', type: 'float' }, + { name: 'h_beta', type: 'float' }, + { name: 'h_hsi', type: 'float' }, + { name: 'h_humulene', type: 'float' }, + { name: 'h_caryophyllene', type: 'float' }, + { name: 'h_cohumulone', type: 'float' }, + { name: 'h_myrcene', type: 'float' }, + { name: 'h_total_oil', type: 'float' }, + { name: 'h_inventory', type: 'float' }, + { name: 'h_avail', type: 'int' } + ], + }, + hopAdapter = new $.jqx.dataAdapter(hopSource); + + $('#hopGrid').jqxGrid({ + width: 1240, + height: 560, + source: hopAdapter, + theme: theme, + editable: false, + ready: function() { $('#jqxTabs').jqxTabs('next'); }, + columns: [ + { text: 'Hop', datafield: 'h_name' }, + { text: 'Origin', width: 180, datafield: 'h_origin' }, + { text: 'Type', width: 90, datafield: 'h_type', + cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { + return '' + HopTypeData[value].nl + ''; + } + }, + { text: 'Vorm', width: 110, datafield: 'h_form', + cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { + return '' + HopFormData[value].nl + ''; + } + }, + { text: 'Alpha', datafield: 'h_alpha', width: 80, align: 'right', cellsalign: 'right', cellsformat: 'p1' }, + { text: 'Gebruik', width: 110, datafield: 'h_useat', + cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { + return '' + HopUseData[value].nl + ''; + } + }, + { text: 'Tijdsduur', datafield: 'h_time', width: 90, align: 'right', + cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { + var duration = ''; + if ((rowdata.h_useat == 2) || (rowdata.h_useat == 4)) // Boil, Whirlpool + duration = dataAdapter.formatNumber(value, 'f0') + ' min.'; + else if (rowdata.h_useat == 5) // Dry hop + duration = dataAdapter.formatNumber(value / 1440, 'f0') + ' dagen'; + return '' + duration + ''; + } + }, + { text: 'IBU', datafield: 'ibu', width: 80, align: 'right', + cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { + var ibu = toIBU(rowdata.h_useat, rowdata.h_form, preboil_sg, parseFloat(dataRecord.batch_size), + parseFloat(rowdata.h_amount), parseFloat(rowdata.h_time), + parseFloat(rowdata.h_alpha), dataRecord.ibu_method, 0, parseFloat(rowdata.h_time), 0); + return '' + dataAdapter.formatNumber(ibu, 'f1') + ''; + } + }, + { text: 'Gewicht', datafield: 'h_amount', width: 110, align: 'right', + cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { + var amount = dataAdapter.formatNumber(value, 'f1') + ' kg'; + if (value < 1) + amount = dataAdapter.formatNumber(value * 1000, 'f1') + ' gr'; + return '' + amount + ''; + } + } + ] + }); + }; + + // Inline miscs editor + var editMisc = function(data) { + var miscSource = { + localdata: data.miscs, + datafields: [ + { name: 'm_name', type: 'string' }, + { name: 'm_amount', type: 'float' }, + { name: 'm_cost', type: 'float' }, + { name: 'm_type', type: 'int' }, + { name: 'm_use_use', type: 'int' }, + { name: 'm_time', type: 'float' }, + { name: 'm_amount_is_weight', type: 'int' }, + { name: 'm_inventory', type: 'float' }, + { name: 'm_avail', type: 'int' } + ], + }, + miscAdapter = new $.jqx.dataAdapter(miscSource, { + beforeLoadComplete: function(records) { + var i, row, data = new Array(); + for (i = 0; i < records.length; i++) { + row = records[i]; + data.push(row); + // Initial set water agent values. + if (row.m_use_use == 1) { // Mash + switch (row.m_name) { + case 'CaCl2': + $('#wa_cacl2').val(row.m_amount * 1000); + break; + case 'CaSO4': + $('#wa_caso4').val(row.m_amount * 1000); + break; + case 'MgSO4': + $('#wa_mgso4').val(row.m_amount * 1000); + break; + case 'NaCl': + $('#wa_nacl').val(row.m_amount * 1000); + break; + case 'MgCl2': + $('#wa_mgcl2').val(row.m_amount * 1000); + break; + case 'NaHCO3': + $('#wa_nahco3').val(row.m_amount * 1000); + break; + case 'CaCO3': + $('#wa_caco3').val(row.m_amount * 1000); + break; + case 'Melkzuur': + $('#wa_acid_name').val(AcidTypeData[0].nl); + $('#wa_acid').val(row.m_amount * 1000); + $('#wa_acid_perc').val(AcidTypeData[0].AcidPrc); + last_acid = 'Melkzuur'; + break; + case 'Zoutzuur': + $('#wa_acid_name').val(AcidTypeData[1].nl); + $('#wa_acid').val(row.m_amount * 1000); + $('#wa_acid_perc').val(AcidTypeData[1].AcidPrc); + last_acid = 'Zoutzuur'; + break; + case 'Fosforzuur': + $('#wa_acid_name').val(AcidTypeData[2].nl); + $('#wa_acid').val(row.m_amount * 1000); + $('#wa_acid_perc').val(AcidTypeData[2].AcidPrc); + last_acid = 'Fosforzuur'; + break; + case 'Zwavelzuur': + $('#wa_acid_name').val(AcidTypeData[3].nl); + $('#wa_acid').val(row.m_amount * 1000); + $('#wa_acid_perc').val(AcidTypeData[3].AcidPrc); + last_acid = 'Zwavelzuur'; + break; + } + } + if (row.m_use_use == 6) { // Sparge + switch (row.m_name) { + case 'CaCl2': + $('#ss_cacl2').val(row.m_amount * 1000); + break; + case 'CaSO4': + $('#ss_caso4').val(row.m_amount * 1000); + break; + case 'MgSO4': + $('#ss_mgso4').val(row.m_amount * 1000); + break; + case 'NaCl': + $('#ss_nacl').val(row.m_amount * 1000); + break; + case 'MgCl2': + $('#ss_mgcl2').val(row.m_amount * 1000); + break; + case 'Melkzuur': +// $('#wa_acid_name').val(0); +// $('#wa_acid').val(row.m_amount * 1000); +// $('#wa_acid_perc').val(AcidTypeData[0].AcidPrc); // TODO: this ignores changed percentages. +// last_acid = 'Melkzuur'; + break; + case 'Zoutzuur': + // $('#wa_acid_name').val(1); +// $('#wa_acid').val(row.m_amount * 1000); +// $('#wa_acid_perc').val(AcidTypeData[1].AcidPrc); +// last_acid = 'Zoutzuur'; + break; + case 'Fosforzuur': +// $('#wa_acid_name').val(2); +// $('#wa_acid').val(row.m_amount * 1000); +// $('#wa_acid_perc').val(AcidTypeData[2].AcidPrc); +// last_acid = 'Fosforzuur'; + break; + case 'Zwavelzuur': +// $('#wa_acid_name').val(3); +// $('#wa_acid').val(row.m_amount * 1000); +// $('#wa_acid_perc').val(AcidTypeData[3].AcidPrc); +// last_acid = 'Zwavelzuur'; + break; + } + } + } + return data; + }, + loadError: function(jqXHR, status, error) {} + }); + $('#miscGrid').jqxGrid({ + width: 1240, + height: 575, + source: miscAdapter, + theme: theme, + editable: false, + ready: function() { + $('#jqxTabs').jqxTabs('next'); + }, + columns: [ + { text: 'Ingredient', datafield: 'm_name' }, + { text: 'Type', width: 140, datafield: 'm_type', + cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { + return '' + MiscTypeData[value].nl + ''; + } + }, + { text: 'Gebruik', width: 140, datafield: 'm_use_use', + cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { + return '' + MiscUseData[value].nl + ''; + } + }, + { text: 'Tijd', datafield: 'm_time', width: 140, align: 'right', + cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { + var duration = ''; + if (rowdata.m_use_use == 2) // Boil + duration = dataAdapter.formatNumber(value, 'f0') + ' minuten'; + else if ((rowdata.m_use_use == 3) || (rowdata.m_use_use == 4)) // Primary or Secondary + duration = dataAdapter.formatNumber(value / 1440, 'f0') + ' dagen'; + return '' + duration + ''; + } + }, + { text: 'Hoeveel', datafield: 'm_amount', width: 110, align: 'right', + cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { + var vstr = rowdata.m_amount_is_weight ? 'gr' : 'ml'; + return '' + + dataAdapter.formatNumber(value * 1000, 'f2') + ' ' + vstr + ''; + } + } + ] + }); + }; + + // Inline yeasts editor + var editYeast = function(data) { + var yeastSource = { + localdata: data.yeasts, + datafields: [ + { name: 'y_name', type: 'string' }, + { name: 'y_laboratory', type: 'string' }, + { name: 'y_product_id', type: 'string' }, + { name: 'y_amount', type: 'float' }, + { name: 'y_cost', type: 'float' }, + { name: 'y_type', type: 'int' }, + { name: 'y_form', type: 'int' }, + { name: 'y_flocculation', type: 'int' }, + { name: 'y_min_temperature', type: 'float' }, + { name: 'y_max_temperature', type: 'float' }, + { name: 'y_attenuation', type: 'float' }, + { name: 'y_use', type: 'int' }, + { name: 'y_cells', type: 'float' }, + { name: 'y_tolerance', type: 'float' }, + { name: 'y_inventory', type: 'float' }, + { name: 'y_sta1', type: 'int' }, + { name: 'y_bacteria', type: 'int' }, + { name: 'y_harvest_top', type: 'int' }, + { name: 'y_harvest_time', type: 'int' }, + { name: 'y_pitch_temperature', type: 'float' }, + { name: 'y_pofpos', type: 'int' }, + { name: 'y_zymocide', type: 'int' }, + { name: 'y_gr_hl_lo', type: 'int' }, + { name: 'y_sg_lo', type: 'float' }, + { name: 'y_gr_hl_hi', type: 'int' }, + { name: 'y_sg_hi', type: 'float' }, + { name: 'y_avail', type: 'int' } + ], + }, + yeastAdapter = new $.jqx.dataAdapter(yeastSource); + + $('#yeastGrid').jqxGrid({ + width: 1240, + height: 350, + source: yeastAdapter, + theme: theme, + editable: false, + ready: function() { + calcFermentables(); + $('#jqxTabs').jqxTabs('next'); + }, + columns: [ + { text: 'Gist', datafield: 'y_name' }, + { text: 'Laboratorium', width: 150, datafield: 'y_laboratory' }, + { text: 'Code', width: 90, datafield: 'y_product_id' }, + { text: 'Soort', width: 100, datafield: 'y_form', + cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { + return '' + YeastFormData[value].nl + ''; + } + }, + { text: 'Min. °C', width: 70, align: 'right', cellsalign: 'right', datafield: 'y_min_temperature' }, + { text: 'Max. °C', width: 70, align: 'right', cellsalign: 'right', datafield: 'y_max_temperature' }, + { text: 'Tol. %', width: 60, align: 'right', cellsalign: 'right', datafield: 'y_tolerance', + cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { + var amount = '', color = '#ffffff'; + if (value > 0) { + amount = dataAdapter.formatNumber(value, 'f1'); + if (dataRecord.est_abv > value) + color = '#ff4040'; + } + return '' + amount + ''; + } + }, + { text: 'Attn. %', width: 70, align: 'right', cellsalign: 'right', datafield: 'y_attenuation', cellsformat: 'f1' }, + { text: 'Voor', width: 120, datafield: 'y_use', + cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { + return '' + YeastUseData[value].nl + ''; + } + }, + { text: 'Hoeveel', datafield: 'y_amount', width: 90, align: 'right', + cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { + var amount = dataAdapter.formatNumber(value * 1000, 'f0') + ' ml'; + if (rowdata.y_form == 0) // Liquid + amount = dataAdapter.formatNumber(value, 'f0') + ' pk'; + else if (rowdata.y_form == 1) // Dry + amount = dataAdapter.formatNumber(value * 1000, 'f1') + ' gr'; + return '' + amount + ''; + } + } + ] + }); + }; + + // inline mash editor + var editMash = function(data) { + var mashSource = { + localdata: data.mashs, + datafields: [ + { name: 'step_name', type: 'string' }, + { name: 'step_type', type: 'int' }, + { name: 'step_volume', type: 'float' }, + { name: 'step_infuse_amount', type: 'float' }, + { name: 'step_infuse_temp', type: 'float' }, + { name: 'step_temp', type: 'float' }, + { name: 'step_time', type: 'float' }, + { name: 'step_wg_ratio', type: 'float' }, + { name: 'ramp_time', type: 'float' }, + { name: 'end_temp', type: 'float' } + ], + }, + mashAdapter = new $.jqx.dataAdapter(mashSource, { + beforeLoadComplete: function(records) { + mash_infuse = 0; + var row, i, data = new Array(); + for (i = 0; i < records.length; i++) { + row = records[i]; + if (row.step_type == 0) // Infusion + mash_infuse += parseFloat(row.step_infuse_amount); + row.step_wg_ratio = 0; // Init this field. + data.push(row); + } + }, + }); + $('#mashGrid').jqxGrid({ + width: 1240, + height: 400, + source: mashAdapter, + theme: theme, + editable: false, + ready: function() { + calcFermentables(); + calcInit(); + calcMash(); + $('#jqxLoader').jqxLoader('close'); + $('#jqxTabs').jqxTabs('first'); + }, + columns: [ + { text: 'Stap naam', datafield: 'step_name' }, + { text: 'Stap type', datafield: 'step_type', width: 175, + cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) { + return '
' + MashStepTypeData[value].nl + '
'; + } + }, + { text: 'Start °C', datafield: 'step_temp', width: 90, align: 'right', cellsalign: 'right', cellsformat: 'f1' }, + { text: 'Eind °C', datafield: 'end_temp', width: 90, align: 'right', cellsalign: 'right', cellsformat: 'f1' }, + { text: 'Rust min.', datafield: 'step_time', width: 90, align: 'right', cellsalign: 'right' }, + { text: 'Stap min.', datafield: 'ramp_time', width: 90, align: 'right', cellsalign: 'right' }, + { text: 'Inf/dec L.', datafield: 'step_infuse_amount', width: 90, align: 'right', + cellsrenderer: function(row, columnfield, value, defaulthtml, columnproperties, rowdata) { + if (rowdata.step_type == 1) + return ''; + return '' + dataAdapter.formatNumber(value, 'f1') + ''; + } + }, + { text: 'Inf/dec °C', datafield: 'step_infuse_temp', width: 90, align: 'right', + cellsrenderer: function(row, columnfield, value, defaulthtml, columnproperties, rowdata) { + if (rowdata.step_type == 1) + return ''; + return '' + dataAdapter.formatNumber(value, 'f2') + ''; + } + }, + { text: 'L/Kg.', datafield: 'step_wg_ratio', width: 90, align: 'right', + cellsrenderer: function(row, columnfield, value, defaulthtml, columnproperties, rowdata) { + var color = '#ffffff'; + if (value < 2.0 || value > 6.0) + color = '#ff4040'; + return '' + dataAdapter.formatNumber(value, 'f2') + ''; + } + } + ] + }); + }; + + + /* + * Remove the top menu so that we MUST use the buttons to leave the editor. + */ + $('#jqxMenu').jqxMenu('destroy'); + + console.log('record:' + my_record + ' return:' + my_return + ' theme:' + theme); + $('#jqxLoader').jqxLoader({ + width: 250, + height: 150, + isModal: true, + text: 'Laden recept ...', + theme: theme + }); + + function setWaterAgent(name, amount) { + + var record, records, miscs, i, id, row, found = false, rows = $('#miscGrid').jqxGrid('getrows'); + if (amount == 0) { + for (i = 0; i < rows.length; i++) { + row = rows[i]; + if (row.m_name == name) { + id = $('#miscGrid').jqxGrid('getrowid', i); + $('#miscGrid').jqxGrid('deleterow', id); + } + } + } else { + for (i = 0; i < rows.length; i++) { + row = rows[i]; + if (row.m_name == name) { + found = true; + $('#miscGrid').jqxGrid('setcellvalue', i, 'm_amount', amount / 1000); + break; + } + } + if (! found) { + miscs = new $.jqx.dataAdapter(miscInvSource, { + loadComplete: function() { + records = miscs.records; + for (i = 0; i < records.length; i++) { + record = records[i]; + if (record.name == name) { + row = {}; + row['m_name'] = record.name; + row['m_amount'] = amount / 1000; + row['m_cost'] = record.cost; + row['m_type'] = record.type; + row['m_use_use'] = record.use_use; + row['m_time'] = 0; + row['m_amount_is_weight'] = record.amount_is_weight; + row['m_inventory'] = record.inventory; + row['m_avail'] = 1; + $('#miscGrid').jqxGrid('addrow', null, row); + } + } + } + }); + miscs.dataBind(); + return; + } + } + } + + + // Procedure TFrmWaterAdjustment.CalcWater2; + function calcWater() { + + if (! data_loaded) { + console.log('calcWater(): failsave'); + return; + } + + var liters = 0, + calcium = 0, + magnesium = 0, + sodium = 0, + total_alkalinity = 0, + bicarbonate = 0, + chloride = 0, + sulfate = 0, + ph = 0, + RA = 0, + frac = 0, + TpH = 0, + protonDeficit = 0, + AT, BT, + r1d, r2d, f1d, f2d, f3d, + deltapH, deltapd, pd, n, + Res; + + if (dataRecord.w1_name == '') { + return; + } + + $('#w1_hardness').val(Hardness(dataRecord.w1_calcium, dataRecord.w1_magnesium)); + $('#w1_ra').val(ResidualAlkalinity(dataRecord.w1_total_alkalinity, dataRecord.w1_calcium, dataRecord.w1_magnesium)); + + // If there is a dillute water source, mix the waters. + if (dataRecord.w2_name != '') { + liters = dataRecord.w1_amount + dataRecord.w2_amount; + calcium = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_calcium, dataRecord.w2_calcium); + magnesium = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_magnesium, dataRecord.w2_magnesium); + sodium = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_sodium, dataRecord.w2_sodium); + chloride = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_chloride, dataRecord.w2_chloride); + sulfate = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_sulfate, dataRecord.w2_sulfate); + total_alkalinity = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_total_alkalinity, dataRecord.w2_total_alkalinity); + ph = -Math.log10(((Math.pow(10, -dataRecord.w1_ph) * dataRecord.w1_amount) + (Math.pow(10, -dataRecord.w2_ph) * dataRecord.w2_amount)) / liters); + $('#w2_hardness').val(Hardness(dataRecord.w2_calcium, dataRecord.w2_magnesium)); + $('#w2_ra').val(ResidualAlkalinity(dataRecord.w2_total_alkalinity, dataRecord.w2_calcium, dataRecord.w2_magnesium)); + } else { + liters = dataRecord.w1_amount; + calcium = dataRecord.w1_calcium; + magnesium = dataRecord.w1_magnesium; + sodium = dataRecord.w1_sodium; + chloride = dataRecord.w1_chloride; + sulfate = dataRecord.w1_sulfate; + total_alkalinity = dataRecord.w1_total_alkalinity; + ph = dataRecord.w1_ph; + } + var bicarbonate = Bicarbonate(total_alkalinity, ph); + + /* Save mixed water ions for later */ + var wg_calcium = calcium; + var wg_sodium = sodium; + var wg_total_alkalinity = total_alkalinity; + var wg_chloride = chloride; + var wg_sulfate = sulfate; + var wg_bicarbonate = bicarbonate; + + dataRecord.wg_amount = liters; + dataRecord.wg_ph = ph; + + $('#wg_amount').val(liters); + $('#wg_calcium').val(Round(calcium, 1)); + $('#wg_magnesium').val(Round(magnesium, 1)); + $('#wg_sodium').val(Round(sodium, 1)); + $('#wg_bicarbonate').val(Round(bicarbonate, 1)); + $('#wg_total_alkalinity').val(Round(total_alkalinity, 1)); + $('#wg_chloride').val(Round(chloride, 1)); + $('#wg_sulfate').val(Round(sulfate, 1)); + $('#wg_ph').val(Round(ph, 2)); + $('#wg_hardness').val(Round(Hardness(calcium, magnesium), 1)); + $('#wg_ra').val(Round(ResidualAlkalinity(total_alkalinity, calcium, magnesium), 1)); + + var mash_ph = Round(MashpH(), 3); + console.log('Distilled water mash pH: ' + mash_ph); + + /* Calculate Salt additions */ + if (liters > 0) { + calcium += (parseFloat($('#wa_cacl2').jqxNumberInput('decimal')) * MMCa / MMCaCl2 * 1000 + + parseFloat($('#wa_caso4').jqxNumberInput('decimal')) * MMCa / MMCaSO4 * 1000 + + parseFloat($('#wa_caco3').jqxNumberInput('decimal')) * MMCa / MMCaCO3 * 1000) / liters; + magnesium += (parseFloat($('#wa_mgso4').jqxNumberInput('decimal')) * MMMg / MMMgSO4 * 1000 + + parseFloat($('#wa_mgcl2').jqxNumberInput('decimal')) * MMMg / MMMgCl2 * 1000) / liters; + sodium += (parseFloat($('#wa_nacl').jqxNumberInput('decimal')) * MMNa / MMNaCl * 1000 + + parseFloat($('#wa_nahco3').jqxNumberInput('decimal')) * MMNa / MMNaHCO3 * 1000) / liters; + sulfate += (parseFloat($('#wa_caso4').jqxNumberInput('decimal')) * MMSO4 / MMCaSO4 * 1000 + + parseFloat($('#wa_mgso4').jqxNumberInput('decimal')) * MMSO4 / MMMgSO4 * 1000) / liters; + chloride += (2 * parseFloat($('#wa_cacl2').jqxNumberInput('decimal')) * MMCl / MMCaCl2 * 1000 + + parseFloat($('#wa_nacl').jqxNumberInput('decimal')) * MMCl / MMNaCl * 1000 + + parseFloat($('#wa_mgcl2').jqxNumberInput('decimal')) * MMCl / MMMgCl2 * 1000) / liters; + bicarbonate += (parseFloat($('#wa_nahco3').jqxNumberInput('decimal')) * MMHCO3 / MMNaHCO3 * 1000 + + parseFloat($('#wa_caco3').jqxNumberInput('decimal')) / 3 * MMHCO3 / MMCaCO3 * 1000) / liters; + } + + if (dataRecord.wa_acid_name < 0 || dataRecord,wa_acid_name >= AcidTypeData.length) { + $('#wa_acid_name').val(0); + dataRecord.wa_acid_name = 0; + dataRecord.wa_acid_perc = AcidTypeData[0].AcidPrc; + $('#wa_acid_perc').val(AcidTypeData[0].AcidPrc); + } + if (last_acid == '') + last_acid = AcidTypeData[dataRecord.wa_acid_name].nl; + + if (parseFloat(dataRecord.wa_acid_perc) == 0) { + dataRecord.wa_acid_perc = AcidTypeData[AT].AcidPrc; + $('#wa_acid_perc').val(AcidTypeData[AT].AcidPrc); + } + + AT = dataRecord.wa_acid_name; + + /* Note that the next calculations do not correct the pH change by the added salts. + This pH change is at most 0.1 pH and is a minor difference in Acid amount. */ + + if (dataRecord.calc_acid) { + $('.c_mashph').show(); + /* Auto calculate pH */ + TpH = parseFloat(dataRecord.mash_ph); + protonDeficit = ProtonDeficit(TpH); + console.log('calc_acid tgt: ' + TpH + ' protonDeficit: ' + protonDeficit); + if (protonDeficit > 0) { // Add acid + frac = CalcFrac(TpH, AcidTypeData[AT].pK1, AcidTypeData[AT].pK2, AcidTypeData[AT].pK3); + Acid = protonDeficit / frac; + Acid *= AcidTypeData[AT].MolWt; // mg + Acidmg = Acid; + var RealSG = Round(((AcidTypeData[AT].AcidSG - 1000) * (parseFloat(dataRecord.wa_acid_perc) / 100)) + 1000, 2); + Acid /= RealSG; + Acid /= AcidTypeData[AT].AcidPrc / 100; + Acid = Round(Acid, 2); + console.log('Mash auto Acid final ml: ' + Acid); + $('#wa_acid').val(Acid); + setWaterAgent(AcidTypeData[AT].nl, Acid); + + bicarbonate = bicarbonate - protonDeficit * frac / liters; + total_alkalinity = bicarbonate * 50 / 61; + } + ph = TpH; + dataRecord.wb_ph = ph; + $('#wb_ph').val(Round(ph, 2)); + $('#est_mash_ph').val(Round(ph, 2)); + } else { // Manual + /* Manual calculate pH */ + $('.c_mashph').hide(); + console.log('calc_acid no'); + pHa = Round(ph, 3); // Adjusted water pH + // Then calculate the new pH with added acids and malts + console.log('Mash pH: ' + pHa); + Acid = AcidTypeData[AT].AcidSG * (parseFloat(dataRecord.wa_acid_perc) / 100); // ml + Acid *= parseFloat($('#wa_acid').jqxNumberInput('decimal')); + Acid /= AcidTypeData[AT].MolWt; // mg + Acidmg = Acid; + + //find the pH where the protondeficit = protondeficit by the acid + frac = CalcFrac(pHa, AcidTypeData[AT].pK1, AcidTypeData[AT].pK2, AcidTypeData[AT].pK3); + protonDeficit = Round(Acid * frac, 3); + //console.log('protonDeficit Acid: ' + protonDeficit + ' frac: ' + frac + ' pH: ' + pHa); + + deltapH = 0.001; + deltapd = 0.1; + pd = Round(ProtonDeficit(pHa), 6); + n = 0; + while (((pd < (protonDeficit - deltapd)) || (pd > (protonDeficit + deltapd))) && (n < 4000)) { + n++; + if (pd < (protonDeficit - deltapd)) + pHa -= deltapH; + else if (pd > (protonDeficit + deltapd)) + pHa += deltapH; + frac = CalcFrac(pHa, AcidTypeData[AT].pK1, AcidTypeData[AT].pK2, AcidTypeData[AT].pK3); + protonDeficit = Acid * frac; + pd = ProtonDeficit(pHa); + } + //console.log('n: ' + n + ' pd: ' + pd + ' protonDeficit: ' + protonDeficit + ' frac: ' + frac + ' pHa: ' + pHa); + bicarbonate = wg_bicarbonate - protonDeficit * frac / liters; + total_alkalinity = RA * 50 / 61; + ph = pHa; + $('#wb_ph').val(Round(ph, 2)); + $('#est_mash_ph').val(Round(ph, 2)); + } + + if ((AT == 3) && (liters > 0)) { // Sulfuctic / Zwavelzuur + RA = parseFloat($('#wa_caso4').jqxNumberInput('decimal')) * MMSO4 / MMCaSO4 + + parseFloat($('#wa_mgso4').jqxNumberInput('decimal')) * MMSO4 / MMMgSO4 + + Acidmg / 1000 * MMSO4 / (MMSO4 + 2); + RA = 1000 * RA / liters; + sulfate = wg_sulfate + RA; // Not add to sulfate?? + } else if ((AT == 1) && (liters > 0)) { // Hydrochloric, Zoutzuur + RA = parseFloat($('#wa_cacl2').jqxNumberInput('decimal')) * MMCl / MMCaCl2 + + parseFloat($('#wa_nacl').jqxNumberInput('decimal')) * MMCl / MMNaCl + + Acidmg / 1000 * MMCl / (MMCl + 1); + RA = 1000 * RA / liters; + chloride = wg_chloride + RA; + } + + var BUGU = GetBUGU(); + $('#tgt_bu').val(Round(BUGU, 2)); + // From brouwhulp. + if (BUGU < 0.32) + $('#wr_bu').html("Zeer moutig en zoet"); + else if (BUGU < 0.43) + $('#wr_bu').html("Moutig, zoet"); + else if (BUGU < 0.52) + $('#wr_bu').html("Evenwichtig"); + else if (BUGU < 0.63) + $('#wr_bu').html("Licht hoppig, bitter"); + else + $('#wr_bu').html("Extra hoppig, zeer bitter"); + + // Sulfate to Chloride ratio (Palmer). + var OptSO4Clratio = GetOptSO4Clratio(); + $('#tgt_so4_cl').val(Round(OptSO4Clratio, 1)); + if (OptSO4Clratio < 0.4) + $('#wrt_so4_cl').html("Te moutig"); + else if (OptSO4Clratio < 0.6) + $('#wrt_so4_cl').html("Zeer moutig"); + else if (OptSO4Clratio < 0.8) + $('#wrt_so4_cl').html("Moutig"); + else if (OptSO4Clratio < 1.5) + $('#wrt_so4_cl').html("Gebalanceerd"); + else if (OptSO4Clratio < 2.0) + $('#wrt_so4_cl').html("Licht bitter"); + else if (OptSO4Clratio < 4.0) + $('#wrt_so4_cl').html("Bitter"); + else if (OptSO4Clratio < 9.0) + $('#wrt_so4_cl').html("Zeer bitter"); + else + $('#wrt_so4_cl').html("Te bitter"); + if (chloride > 0) + RA = sulfate / chloride; + else + RA = 10; + $('#got_so4_cl').val(Round(RA, 1)); + Res = 'normaal'; + if (RA < (0.8 * OptSO4Clratio)) + Res = 'laag'; + else if (RA > (1.2 * OptSO4Clratio)) + Res = 'hoog'; + setRangeIndicator('so4_cl', Res); + + $('#wb_calcium').val(Round(calcium, 1)); + $('#wb_magnesium').val(Round(magnesium, 1)); + $('#wb_sodium').val(Round(sodium, 1)); + $('#wb_sulfate').val(Round(sulfate, 1)); + $('#wb_chloride').val(Round(chloride, 1)); + $('#wb_bicarbonate').val(Round(bicarbonate, 1)); + $('#wb_total_alkalinity').val(Round(total_alkalinity, 1)); + $('#wb_hardness').val(Hardness(calcium, magnesium)); + $('#wb_ra').val(ResidualAlkalinity(total_alkalinity, calcium, magnesium)); + + if (calcium < 40) { + setRangeIndicator('calcium', 'laag'); + } else if (calcium > 150) { + setRangeIndicator('calcium', 'hoog'); + } else { + setRangeIndicator('calcium', 'normaal'); + } + if (magnesium < 5) { + setRangeIndicator('magnesium', 'laag'); + } else if (magnesium > 40) { + setRangeIndicator('magnesium', 'hoog'); + } else { + setRangeIndicator('magnesium', 'normaal'); + } + if (sodium <= 150) { + setRangeIndicator('sodium', 'normaal'); + } else { + setRangeIndicator('sodium', 'hoog'); + } + // Both chloride and sulfate should be above 50 according to + // John Palmer. So the Cl/SO4 ratio calculation will work. + if (chloride <= 50) { + setRangeIndicator('chloride', 'laag'); + } else if (chloride <= 150) { + setRangeIndicator('chloride', 'normaal'); + } else { + setRangeIndicator('chloride', 'hoog'); + } + if (sulfate <= 50) { + setRangeIndicator('sulfate', 'laag'); + } else if (sulfate <= 400) { + setRangeIndicator('sulfate', 'normaal'); + } else { + setRangeIndicator('sulfate', 'hoog'); + } + // (cloride + sulfate) > 500 is too high + if ((chloride + sulfate) > 500) { + setRangeIndicator('chloride', 'hoog'); + setRangeIndicator('sulfate', 'hoog'); + } + if (ph < 5.2) { + setRangeIndicator('ph', 'laag'); + } else if (ph > 5.6) { + setRangeIndicator('ph', 'hoog'); + } else { + setRangeIndicator('ph', 'normaal'); + } + if (bicarbonate > 250) { + setRangeIndicator('bicarbonate', 'hoog'); + } else { + setRangeIndicator('bicarbonate', 'normaal'); + } + calcSparge(); + } + + + function calcSparge() { + + /* Based on the work of ajDeLange. */ + var ws_calcium, ws_magnesium, ws_total_alkalinity, ws_sodium, ws_chloride; + var ws_sulfate, ws_ph, ws_hardness, ws_ra; + var TargetpH = dataRecord.sparge_ph; + var Source_pH = 7.0; + + // Select watersource or fallback to the first source. + if ((dataRecord.sparge_source == 1) && (dataRecord.w2_ph > 0.0)) { // Source 2 + ws_calcium = dataRecord.w2_calcium; + ws_magnesium = dataRecord.w2_magnesium; + ws_total_alkalinity = dataRecord.w2_total_alkalinity; + ws_sodium = dataRecord.w2_sodium; + ws_chloride = dataRecord.w2_chloride; + ws_sulfate = dataRecord.w2_sulfate; + Source_pH = dataRecord.w2_ph; + $('#w2_button').jqxRadioButton({ checked: true }); + } else if ((dataRecord.sparge_source == 2) && (dataRecord.w2_ph > 0.0)) { // Mixed + ws_calcium = dataRecord.wg_calcium; + ws_magnesium = dataRecord.wg_magnesium; + ws_total_alkalinity = dataRecord.wg_total_alkalinity; + ws_sodium = dataRecord.wg_sodium; + ws_chloride = dataRecord.wg_chloride; + ws_sulfate = dataRecord.wg_sulfate; + Source_pH = dataRecord.wg_ph; + $('#wg_button').jqxRadioButton({ checked: true }); + } else { + ws_calcium = dataRecord.w1_calcium; + ws_magnesium = dataRecord.w1_magnesium; + ws_total_alkalinity = dataRecord.w1_total_alkalinity; + ws_sodium = dataRecord.w1_sodium; + ws_chloride = dataRecord.w1_chloride; + ws_sulfate = dataRecord.w1_sulfate; + Source_pH = dataRecord.w1_ph; + $('#w1_button').jqxRadioButton({ checked: true }); + } + + if (dataRecord.sparge_volume > 0) { + ws_calcium += (parseFloat($('#ss_cacl2').jqxNumberInput('decimal')) * MMCa / MMCaCl2 * 1000 + + parseFloat($('#ss_caso4').jqxNumberInput('decimal')) * MMCa / MMCaSO4 * 1000) / dataRecord.sparge_volume; + ws_magnesium += (parseFloat($('#ss_mgso4').jqxNumberInput('decimal')) * MMMg / MMMgSO4 * 1000 + + parseFloat($('#ss_mgcl2').jqxNumberInput('decimal')) * MMMg / MMMgCl2 * 1000) / dataRecord.sparge_volume; + ws_sodium += (parseFloat($('#ss_nacl').jqxNumberInput('decimal')) * MMNa / MMNaCl * 1000) / dataRecord.sparge_volume; + ws_sulfate += (parseFloat($('#ss_caso4').jqxNumberInput('decimal')) * MMSO4 / MMCaSO4 * 1000 + + parseFloat($('#ss_mgso4').jqxNumberInput('decimal')) * MMSO4 / MMMgSO4 * 1000) / dataRecord.sparge_volume; + ws_chloride += (2 * parseFloat($('#ss_cacl2').jqxNumberInput('decimal')) * MMCl / MMCaCl2 * 1000 + + parseFloat($('#ss_nacl').jqxNumberInput('decimal')) * MMCl / MMNaCl * 1000 + + parseFloat($('#ss_mgcl2').jqxNumberInput('decimal')) * MMCl / MMMgCl2 * 1000) / dataRecord.sparge_volume; + } + + /* Show the spargewate with salt additions */ + $('#sw_calcium').val(Round(ws_calcium, 1)); + $('#sw_magnesium').val(Round(ws_magnesium, 1)); + $('#sw_sodium').val(Round(ws_sodium, 1)); + $('#sw_sulfate').val(Round(ws_sulfate, 1)); + $('#sw_chloride').val(Round(ws_chloride, 1)); + $('#sw_bicarbonate').val(Round(Bicarbonate(ws_total_alkalinity, Source_pH), 1)); + $('#sw_total_alkalinity').val(Round(ws_total_alkalinity, 1)); + $('#sw_ph').val(dataRecord.sparge_ph); + $('#sw_hardness').val(Hardness(ws_calcium, ws_magnesium)); + $('#sw_ra').val(ResidualAlkalinity(ws_total_alkalinity, ws_calcium, ws_magnesium)); + + AT = dataRecord.sparge_acid_type; + if (AT < 0 || AT >= AcidTypeData.length) { + AT = 0; + dataRecord.sparge_acid_type = 0; + $('#sparge_acid_type').val(AcidTypeData[0].nl); + dataRecord.sparge_acid_perc = AcidTypeData[0].AcidPrc; + $('#sparge_acid_perc').val(dataRecord.sparge_acid_perc); + } + + /* + * Auto calculate the required acid + */ + if (dataRecord.calc_acid) { + // Step 1: Compute the mole fractions of carbonic (f1o), bicarbonate (f2o) and carbonate(f3o) at the water pH + var r1 = Math.pow(10, Source_pH - 6.35); + var r2 = Math.pow(10, Source_pH - 10.33); + var d = 1 + r1 + r1 * r2; + var f1 = 1 / d; + var f3 = r1 * r2 / d; + + //Step 2. Compute the mole fractions at pH = 4.3 (the pH which defines alkalinity) + var r143 = Math.pow(10, 4.3 - 6.35); + var r243 = Math.pow(10, 4.3 - 10.33); + var d43 = 1 + r143 + r143 * r243; + var f143 = 1 / d43; + var f343 = r143 * r243 / d43; + + //Step 4. Solve + var Ct = ws_total_alkalinity / 50 / ((f143 - f1) + (f3 - f343)); + + //Step 5. Compute mole fractions at desired pH + var r1g = Math.pow(10, TargetpH - 6.35); + var r2g = Math.pow(10, TargetpH - 10.33); + var dg = 1 + r1g + r1g * r2g; + var f1g = 1 / dg; + var f3g = r1g * r2g / dg; + + //Step 6. Use these to compute the milliequivalents acid required per liter (mEq/L) + var Acid = Ct * ((f1g - f1) + (f3 - f3g)) + Math.pow(10, -TargetpH) - Math.pow(10, -Source_pH); //mEq/l + Acid += 0.01; // Add acid that would be required for distilled water. + + //Step 8. Get the acid data. + var fract = CalcFrac(TargetpH, AcidTypeData[AT].pK1, AcidTypeData[AT].pK2, AcidTypeData[AT].pK3); + + //Step 9. Now divide the mEq required by the "fraction". This is the required number of moles of acid. + Acid /= fract; + + //Step 10. Multiply by molecular weight of the acid + Acid *= AcidTypeData[AT].MolWt; //mg + + //Step 11. Divide by Specific Gravity and Percentage to get the final ml. + var RealSG = Round(((AcidTypeData[AT].AcidSG - 1000) * (dataRecord.sparge_acid_perc / 100)) + 1000, 2); + Acid = Acid / RealSG; //ml + Acid *= dataRecord.sparge_volume; //ml acid total at 100% + Acid /= AcidTypeData[AT].AcidPrc / 100; //ml acid at supplied strength + Acid = Round(Acid, 2); + dataRecord.sparge_acid_amount = Acid / 1000; + $('#sparge_acid_amount').val(Acid); + } + + // Finally calculate the estimate preboil pH + var ph = -Math.log10(((Math.pow(10, -dataRecord.wb_ph) * dataRecord.wg_amount) + (Math.pow(10, -dataRecord.sparge_ph) * dataRecord.sparge_volume)) / + (dataRecord.wg_amount + dataRecord.sparge_volume)); + $('#preboil_ph').val(ph); + } + + function calcInit() { + console.log('calc.init()'); + + calcWater(); + $('#w1_name').jqxDropDownList('selectItem', dataRecord.w1_name); + $('#w2_name').jqxDropDownList('selectItem', dataRecord.w2_name); + // Fix tap water if zero using mash infuse amount. + if (parseFloat($('#w1_amount').jqxNumberInput('decimal')) == 0 && mash_infuse > 0) { + $('#w1_amount').val(mash_infuse); + dataRecord.w1_amount = mash_infuse; + $('#wg_amount').val(mash_infuse); + $('#w2_amount').val(0); + dataRecord.w2_amount = 0; + } + calcWater(); + + }; + + function saveRecord(goback) { + window.location.href = my_return; + }; + + dataAdapter.dataBind(); + + // initialize the input fields. + // Tab 1, Algemeen + $('#name').jqxTooltip({ content: 'De naam voor dit recept.' }); + $('#name').jqxInput({ theme: theme, width: 640, height: 23 }); + $('#notes').jqxTooltip({ content: 'De uitgebreide opmerkingen over dit recept.' }); + $('#notes').jqxInput({ theme: theme, width: 960, height: 200 }); + $('#type').jqxTooltip({ content: 'Het brouw type van dit recept.' }); + $('#type').jqxInput({ theme: theme, width: 180, height: 23 }); + $('#efficiency').jqxTooltip({ content: 'Het rendement van maischen en koken.' }); + $('#efficiency').jqxNumberInput(Show1dec); + $('#batch_size').jqxTooltip({ content: 'Het volume van het gekoelde wort na het koken.' }); + $('#batch_size').jqxNumberInput(Show1dec); + $('#batch_size').jqxNumberInput({ min: 4 }); + $('#boil_size').jqxTooltip({ content: 'Het volume van het wort voor het koken.' }); + $('#boil_size').jqxNumberInput({ inputMode: 'simple', theme: theme, width: 90, height: 23, decimalDigits: 2, readOnly: true }); + $('#boil_time').jqxTooltip({ content: 'De kooktijd in minuten.' }); + $('#boil_time').jqxNumberInput(Show0dec); + $('#boil_time').jqxNumberInput({ min: 4, max: 360 }); + + $('#st_name').jqxTooltip({ content: 'De bierstijl naam voor dit recept.'}); + $('#st_name').jqxInput({ theme: theme, width: 250, height: 23 }); + $('#st_letter').jqxTooltip({ content: 'De bierstijl letter voor dit recept.'}); + $('#st_letter').jqxInput({ theme: theme, width: 90, height: 23 }); + $('#st_guide').jqxTooltip({ content: 'De bierstijl gids voor dit recept.'}); + $('#st_guide').jqxInput({ theme: theme, width: 250, height: 23 }); + $('#st_category').jqxTooltip({ content: 'De Amerikaanse bierstijl categorie.'}); + $('#st_category').jqxInput({ theme: theme, width: 250, height: 23 }); + $('#st_category_number').jqxTooltip({ content: 'De Amerikaanse bierstijl categorie sub nummer.'}); + $('#st_category_number').jqxNumberInput(Smal0dec); + $('#st_type').jqxTooltip({ content: 'Het bierstijl type.'}); + $('#st_type').jqxInput({ theme: theme, width: 250, height: 23 }); + + $('#est_og').jqxTooltip({ content: 'Het begin SG wat je wilt bereiken. De moutstort wordt automatisch herberekend.' }); + $('#est_og').jqxNumberInput(Show3dec); + $('#st_og_min').jqxTooltip({ content: 'Het minimum begin SG voor deze bierstijl.'}); + $('#st_og_min').jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 3, readOnly: true }); + $('#st_og_max').jqxTooltip({ content: 'Het maximum begin SG voor deze bierstijl.'}); + $('#st_og_max').jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 3, readOnly: true }); + + $('#est_fg').jqxTooltip({ content: 'Het eind SG. Dit wordt automatisch berekend.' }); + $('#est_fg').jqxNumberInput(Show3dec); + $('#st_fg_min').jqxTooltip({ content: 'Het minimum eind SG voor deze bierstijl.'}); + $('#st_fg_min').jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 3, readOnly: true }); + $('#st_fg_max').jqxTooltip({ content: 'Het maximum eind SG voor deze bierstijl.'}); + $('#st_fg_max').jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 3, readOnly: true }); + + $('#est_abv').jqxTooltip({ content: 'Alcohol volume %. Dit wordt automatisch berekend.' }); + $('#est_abv').jqxNumberInput(Smal1dec); + $('#st_abv_min').jqxTooltip({ content: 'Het minimum alcohol volume % voor deze bierstijl.'}); + $('#st_abv_min').jqxNumberInput(Smal1dec); + $('#st_abv_max').jqxTooltip({ content: 'Het maximum alcohol volume % voor deze bierstijl.'}); + $('#st_abv_max').jqxNumberInput(Smal1dec); + + $('#est_color').jqxTooltip({ content: 'De kleur in EBC. Dit wordt automatisch berekend.' }); + $('#est_color').jqxNumberInput(Show0dec); + $('#st_color_min').jqxTooltip({ content: 'De minimum kleur voor deze bierstijl.'}); + $('#st_color_min').jqxNumberInput(Smal0dec); + $('#st_color_max').jqxTooltip({ content: 'De maximum kleur voor deze bierstijl.'}); + $('#st_color_max').jqxNumberInput(Smal0dec); + $('#color_method').jqxInput({ theme: theme, width: 180, height: 23 }); + $('#est_ibu').jqxTooltip({ content: 'De bitterheid in IBU. Dit wordt automatisch berekend.' }); + $('#est_ibu').jqxNumberInput(Show0dec); + $('#st_ibu_min').jqxTooltip({ content: 'De minimum bitterheid voor deze bierstijl.'}); + $('#st_ibu_min').jqxNumberInput(Smal0dec); + $('#st_ibu_max').jqxTooltip({ content: 'De maximum bitterheid voor deze bierstijl.'}); + $('#st_ibu_max').jqxNumberInput(Smal0dec); + + $('#ibu_method').jqxInput({ theme: theme, width: 180, height: 23 }); + $('#kcal').jqxTooltip({ content: 'Energie-inhoud in kcal/liter.' }); + $('#kcal').jqxNumberInput(Smal0dec); + $('#est_carb').jqxTooltip({ content: 'Koolzuur volume. Dit wordt automatisch berekend.' }); + $('#est_carb').jqxNumberInput(Smal1dec); + $('#st_carb_min').jqxTooltip({ content: 'Het minimum koolzuur volume voor deze bierstijl.'}); + $('#st_carb_min').jqxNumberInput(Smal1dec); + $('#st_carb_max').jqxTooltip({ content: 'Het maximum koolzuur volume voor deze bierstijl.'}); + $('#st_carb_max').jqxNumberInput(Smal1dec); + + // Tab 2, Vergistbaar + $('#est_color2').jqxTooltip({ content: 'De kleur in EBC. Dit wordt automatisch berekend.' }); + $('#est_color2').jqxNumberInput(Show0dec); + $('#est_og2').jqxTooltip({ content: 'Het begin SG wat je wilt bereiken. De moutstort wordt automatisch herberekend.' }); + $('#est_og2').jqxNumberInput(Show3dec); + $('#perc_malts').jqxProgressBar({ + width: 300, + height: 23, + theme: theme, + showText: true, + max: 120, + animationDuration: 0, + colorRanges: [ + { stop: 90, color: '#008C00' }, + { stop: 100, color: '#EB7331' }, + { stop: 120, color: '#FF0000' } + ], + renderText: function(text) { + return (Math.round(parseInt(text) * 1.2)) + '%'; + } + }); + $('#perc_sugars').jqxProgressBar({ + width: 300, + height: 23, + theme: theme, + showText: true, + max: 50, + animationDuration: 0, + colorRanges: [ + { stop: 20, color: '#008C00' }, + { stop: 50, color: '#FF0000' } + ], + renderText: function(text) { + return (Math.round(parseInt(text) * 5) / 10) + '%'; + } + }); + $('#perc_cara').jqxProgressBar({ + width: 300, + height: 23, + theme: theme, + showText: true, + max: 50, + animationDuration: 0, + colorRanges: [ + { stop: 25, color: '#008C00' }, + { stop: 50, color: '#FF0000' } + ], + renderText: function(text) { + return (Math.round(parseInt(text) * 5) / 10) + '%'; + } + }); + $('#ferm_lintner').jqxProgressBar({ + width: 300, + height: 23, + theme: theme, + showText: true, + max: 200, + animationDuration: 0, + colorRanges: [ + { stop: 30, color: '#FF0000' }, + { stop: 40, color: '#EB7331' }, + { stop: 200, color: '#008C00' } + ], + renderText: function(text) { + return (parseInt(text) * 2) + ' lintner'; + } + }); + + // Tab 3, Hoppen + $('#est_ibu2').jqxTooltip({ content: 'De bitterheid in IBU. Dit wordt automatisch berekend.' }); + $('#est_ibu2').jqxNumberInput(Smal0dec); + $('#hop_flavour').jqxProgressBar({ + width: 300, + height: 23, + theme: theme, + showText: true, + animationDuration: 0, + colorRanges: [ + { stop: 20, color: '#004D00' }, + { stop: 40, color: '#008C00' }, + { stop: 60, color: '#00BF00' }, + { stop: 80, color: '#00FF00' }, + { stop: 100, color: '#80FF80' } + ], + renderText: function(text) { + var val = parseInt(text); + if (val < 20) + return 'Weinig'; + else if (val < 40) + return 'Matig'; + else if (val < 60) + return 'Redelijk'; + else if (val < 80) + return 'Veel'; + else + return 'Zeer veel'; + } + }); + $('#hop_aroma').jqxProgressBar({ + width: 300, + height: 23, + theme: theme, + showText: true, + animationDuration: 0, + colorRanges: [ + { stop: 20, color: '#004D00' }, + { stop: 40, color: '#008C00' }, + { stop: 60, color: '#00BF00' }, + { stop: 80, color: '#00FF00' }, + { stop: 100, color: '#80FF80' } + ], + renderText: function(text) { + var val = parseInt(text); + if (val < 20) + return 'Weinig'; + else if (val < 40) + return 'Matig'; + else if (val < 60) + return 'Redelijk'; + else if (val < 80) + return 'Veel'; + else + return 'Zeer veel'; + } + }); + + // Tab 4, Diversen + + // Tab 5, Gist + $('#est_fg2').jqxTooltip({ content: 'Het eind SG. Dit wordt automatisch berekend.' }); + $('#est_fg2').jqxNumberInput(Show3dec); + $('#est_abv2').jqxTooltip({ content: 'Alcohol volume %. Dit wordt automatisch berekend.' }); + $('#est_abv2').jqxNumberInput(Smal1dec); + + // Tab 6, Maischen + $('#mash_name').jqxInput({ theme: theme, width: 320, height: 23 }); + + // Tab 7, Water + $('#tgt_bu').jqxNumberInput(Show2wat); + $('#tgt_so4_cl,#got_so4_cl').jqxNumberInput(Show1wat); + $('#preboil_ph').jqxNumberInput(Show2wat); + + // Water source 1 + $('#w1_name').jqxInput({ theme: theme, width: 200, height: 23 }); + $('#w1_button').jqxRadioButton({ theme: theme, width: 50, height: 23, disabled: true }); + $('#w1_amount').jqxNumberInput(Show1wat); + $('#w1_calcium').jqxNumberInput(Show1wat); + $('#w1_magnesium').jqxNumberInput(Show1wat); + $('#w1_sodium').jqxNumberInput(Show1wat); + $('#w1_bicarbonate').jqxNumberInput(Show1wat); + $('#w1_total_alkalinity').jqxNumberInput(Show1wat); + $('#w1_chloride').jqxNumberInput(Show1wat); + $('#w1_sulfate').jqxNumberInput(Show1wat); + $('#w1_ph').jqxNumberInput(Show2wat); + $('#w1_hardness').jqxNumberInput(Show1wat); + $('#w1_ra').jqxNumberInput(Show1wat); + // Water source 2 + $('#w2_name').jqxInput({ theme: theme, width: 200, height: 23 }); + $('#w2_button').jqxRadioButton({ theme: theme, width: 50, height: 23, disabled: true }); + $('#w2_amount').jqxNumberInput(Show1wat); + $('#w2_calcium').jqxNumberInput(Show1wat); + $('#w2_magnesium').jqxNumberInput(Show1wat); + $('#w2_sodium').jqxNumberInput(Show1wat); + $('#w2_bicarbonate').jqxNumberInput(Show1wat); + $('#w2_total_alkalinity').jqxNumberInput(Show1wat); + $('#w2_chloride').jqxNumberInput(Show1wat); + $('#w2_sulfate').jqxNumberInput(Show1wat); + $('#w2_ph').jqxNumberInput(Show2wat); + $('#w2_hardness').jqxNumberInput(Show1wat); + $('#w2_ra').jqxNumberInput(Show1wat); + // Water mixed + $('#wg_button').jqxRadioButton({ theme: theme, width: 50, height: 23, disabled: true }); + $('#wg_amount').jqxNumberInput(Show1wat); + $('#wg_calcium').jqxNumberInput(Show1wat); + $('#wg_magnesium').jqxNumberInput(Show1wat); + $('#wg_sodium').jqxNumberInput(Show1wat); + $('#wg_bicarbonate').jqxNumberInput(Show1wat); + $('#wg_total_alkalinity').jqxNumberInput(Show1wat); + $('#wg_chloride').jqxNumberInput(Show1wat); + $('#wg_sulfate').jqxNumberInput(Show1wat); + $('#wg_ph').jqxNumberInput(Show2wat); + $('#wg_hardness').jqxNumberInput(Show1wat); + $('#wg_ra').jqxNumberInput(Show1wat); + // Water treated + $('#wb_calcium').jqxTooltip({ content: 'De ideale hoeveelheid Calcium is tussen 40 en 150.'}); + $('#wb_calcium').jqxNumberInput(Show1wat); + $('#wb_magnesium').jqxTooltip({ content: 'De ideale hoeveelheid Magnesium is tussen 5 en 40.'}); + $('#wb_magnesium').jqxNumberInput(Show1wat); + $('#wb_sodium').jqxTooltip({ content: 'De ideale hoeveelheid Natrium is lager dan 150.'}); + $('#wb_sodium').jqxNumberInput(Show1wat); + $('#wb_chloride').jqxTooltip({ content: 'De ideale hoeveelheid Chloride is tussen 50 en 150. Samen met Sulfaat minder dan 500.'}); + $('#wb_chloride').jqxNumberInput(Show1wat); + $('#wb_sulfate').jqxTooltip({ content: 'De ideale hoeveelheid Sulfaat is tussen 50 en 400. Samen met Sulfaat minder dan 500.'}); + $('#wb_sulfate').jqxNumberInput(Show1wat); + $('#wb_bicarbonate').jqxTooltip({ content: '0 tot 50 lichte bieren, 50 tot 150 amber bieren, 150 tot 250 donkere bieren.'}); + $('#wb_bicarbonate').jqxNumberInput(Show1wat); + $('#wb_total_alkalinity').jqxNumberInput(Show1wat); + $('#wb_ph').jqxNumberInput(Show2wat); + $('#wb_hardness').jqxNumberInput(Show1wat); + $('#wb_ra').jqxNumberInput(Show1wat); + // Sparge water + $('#sw_amount').jqxNumberInput(Show1wat); + $('#sw_calcium').jqxNumberInput(Show1wat); + $('#sw_magnesium').jqxNumberInput(Show1wat); + $('#sw_sodium').jqxNumberInput(Show1wat); + $('#sw_bicarbonate').jqxNumberInput(Show1wat); + $('#sw_total_alkalinity').jqxNumberInput(Show1wat); + $('#sw_chloride').jqxNumberInput(Show1wat); + $('#sw_sulfate').jqxNumberInput(Show1wat); + $('#sw_ph').jqxNumberInput(Show2wat); + $('#sw_hardness').jqxNumberInput(Show1wat); + $('#sw_ra').jqxNumberInput(Show1wat); + + // Water agents + $('#wa_cacl2').jqxTooltip({ content: 'Voor het maken van een ander waterprofiel. Voegt calcium en chloride toe. Voor het verbeteren van zoetere bieren.'}); + $('#wa_cacl2').jqxNumberInput(Show2wat); + $('#ss_cacl2').jqxNumberInput(Show2wat); + + $('#wa_caso4').jqxTooltip({ + content: 'Gips. Voor het maken van een ander waterprofiel. Voegt calcium en sulfaat toe. Voor het verbeteren van bittere bieren.' + }); + $('#wa_caso4').jqxNumberInput(Show2wat); + $('#ss_caso4').jqxNumberInput(Show2wat); + + $('#wa_mgso4').jqxTooltip({ content: 'Epsom zout. Voor het maken van een ander waterprofiel. Voegt magnesium en sulfaat toe. Gebruik spaarzaam!'}); + $('#wa_mgso4').jqxNumberInput(Show2wat); + $('#ss_mgso4').jqxNumberInput(Show2wat); + + $('#wa_nacl').jqxTooltip({ + content: 'Keukenzout. Voor het maken van een ander waterprofiel. Voegt natrium en chloride toe. ' + + 'Voor het accentueren van zoetheid. Bij hoge dosering wordt het bier ziltig.' + }); + $('#wa_nacl').jqxNumberInput(Show2wat); + $('#ss_nacl').jqxNumberInput(Show2wat); + + $('#wa_mgcl2').jqxTooltip({ content: 'Magnesiumchloride'}); + $('#wa_mgcl2').jqxNumberInput(Show2wat); + $('#ss_mgcl2').jqxNumberInput(Show2wat); + + $('#wa_nahco3').jqxTooltip({ content: 'Baksoda'}); + $('#wa_caco3').jqxTooltip({ content: 'Kalk'}); + $('#wa_nahco3,#wa_caco3').jqxNumberInput(Show2wat); + + $('#mash_ph').jqxTooltip({ content: 'Maisch pH tussen 5.2 en 5.6. Gebruik 5.2 voor lichte en 5.5 voor donkere bieren.'}); + $('#mash_ph').jqxNumberInput(Show2dec); + + $('#calc_acid').jqxCheckBox({ theme: theme, width: 120, height: 23, disabled: true }); + + $('#wa_acid_name').jqxInput({ theme: theme, width: 130, height: 23 }); + $('#wa_acid').jqxNumberInput(Show2dec); + $('#wa_acid').jqxNumberInput({ symbol: ' ml', symbolPosition: 'right' }); + $('#wa_acid_perc').jqxNumberInput(Show0dec); + $('#wa_acid_perc').jqxNumberInput({ symbol: '%', symbolPosition: 'right' }); + + // Sparge water + $('#sparge_ph').jqxNumberInput(Show2dec); + $('#sparge_acid_amount').jqxNumberInput(Show2dec); + $('#sparge_acid_amount').jqxNumberInput({ symbol: ' ml', symbolPosition: 'right' }); + $('#sparge_acid_type').jqxInput({ theme: theme, width: 130, height: 23 }); + $('#sparge_acid_perc').jqxNumberInput(Show0dec); + $('#sparge_acid_perc').jqxNumberInput({ symbol: '%', symbolPosition: 'right' }); + + // Tabs inside the popup window. + $('#jqxTabs').jqxTabs({ + theme: theme, + width: 1280, + height: 660, + autoHeight: false, + position: 'top' + }); + + // Button below + $('#Terug').jqxButton({ template: 'primary', width: '80px', theme: theme }); + $('#Terug').bind('click', function() { + window.location.href = my_return; + }); + +}); +