www/js/rec_view.js

changeset 815
5714ea86187d
parent 814
de4a74899969
child 825
8b87ad5bd3c3
equal deleted inserted replaced
814:de4a74899969 815:5714ea86187d
1 /*****************************************************************************
2 * Copyright (C) 2018-2022
3 *
4 * Michiel Broek <mbroek at mbse dot eu>
5 *
6 * This file is part of BMS
7 *
8 * This is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2, or (at your option) any
11 * later version.
12 *
13 * BrewCloud is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with ThermFerm; see the file COPYING. If not, write to the Free
20 * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
21 *****************************************************************************/
22
23 var psugar = 0, // Percentage real sugars
24 pcara = 0, // Percentage cara/crystal malts
25 svg = 77, // Default attenuation
26 mashkg = 0, // Malt in mash weight
27 mash_infuse = 0,
28 dataRecord = {}, // Main recipe record
29 hop_flavour = 0,
30 hop_aroma = 0,
31 preboil_sg = 0,
32 last_base = '',
33 last_acid = '',
34 Ka1 = 0.0000004445,
35 Ka2 = 0.0000000000468,
36 error_count = 0,
37 MMCa = 40.048,
38 MMMg = 24.305,
39 MMNa = 22.98976928,
40 MMCl = 35.453,
41 MMSO4 = 96.0626,
42 MMCO3 = 60.01684,
43 MMHCO3 = 61.01684,
44 MMCaSO4 = 172.171,
45 MMCaCl2 = 147.015,
46 MMCaCO3 = 100.087,
47 MMMgCl2 = 95.211, /* Since 27-06-2021 */
48 MMMgSO4 = 246.475,
49 MMNaHCO3 = 84.007,
50 MMNa2CO3 = 105.996,
51 MMNaCl = 58.443,
52 MMCaOH2 = 74.06268,
53 SpecificHeatWater = 1.0,
54 SpecificHeatMalt = 0.399, //cal/g.°C
55 SlakingHeat = 10.318, //cal/g.°C
56 eq_tun_weight = 2.0, // 2 Kg pot
57 eq_tun_specific_heat = 0.110, // Stainless Steel
58 data_loaded = 0;
59
60 function hopFlavourContribution(bt, vol, use, amount) {
61 var result;
62
63 if (use == 4 || use == 5) // Whirlpool or Dry-hop
64 return 0;
65 if (use == 1) { // First wort
66 result = 0.15; // assume 15% flavourcontribution for fwh
67 } else if (bt > 50) {
68 result = 0.10; // assume 10% flavourcontribution as a minimum
69 } else {
70 result = 15.25 / (6 * Math.sqrt(2 * Math.PI)) * Math.exp(-0.5 * Math.pow((bt - 21) / 6, 2));
71 if (result < 0.10)
72 result = 0.10; // assume 10% flavourcontribution as a minimum
73 }
74 return (result * amount * 1000) / vol;
75 }
76
77
78 function hopAromaContribution(bt, vol, use, amount) {
79 var result = 0;
80
81 if (use == 5) { // Dry hop
82 result = 1.33;
83 } else if (use == 4) { // Whirlpool
84 if (bt > 30)
85 bt = 30; // Max 30 minutes
86 result = 0.62 * bt / 30;
87 } else if (bt > 20) {
88 result = 0;
89 } else if (bt > 7.5) {
90 result = 10.03 / (4 * Math.sqrt(2 * Math.PI)) * Math.exp(-0.5 * Math.pow((bt - 7.5) / 4, 2));
91 } else if (use == 2) { // Boil
92 result = 1;
93 } else if (use == 3) { // Aroma
94 result = 1.2;
95 }
96 return (result * amount * 1000) / vol;
97 }
98
99
100 function calcFermentables() {
101 console.log('calcFermentables()');
102 var i, row, rows, org, s = 0, d, x,
103 sug, alc, cw, color, scolor, fig,
104 sugarsf = 0, // fermentable sugars mash + boil
105 sugarsm = 0; // fermentable sugars in mash
106 vol = 0, // Volume sugars after boil
107 addedS = 0, // Added sugars after boil
108 addedmass = 0, // Added mass after boil
109 mvol = 0, // mash volume
110 colort = 0, // Colors srm * vol totals
111 colorh = 0, // Colors ebc * vol * kt
112 colorn = 0, // Colors ebc * pt * pct
113 my_100 = false,
114 mashtime = 0, // Total mash time
115 mashtemp = 0, // Average mash temperature
116 bv = 0.925, // Bierverlies rendement
117 sr = 0.95, // Mash en spoel rendement
118 lintner = 0; // Total recipe lintner
119 /* Init global variables */
120 psugar = 0;
121 pcara = 0;
122 mashkg = 0;
123
124 if ((rows = $('#mashGrid').jqxGrid('getrows'))) {
125 for (i = 0; i < rows.length; i++) {
126 row = rows[i];
127 if (row.step_type == 0) // Infusion
128 mvol += parseFloat(row.step_infuse_amount);
129 if (row.step_temp <= 75) { // Ignore mashout
130 mashtime += row.step_time;
131 mashtemp += row.step_time * row.step_temp;
132 }
133 }
134 mashtemp = mashtemp / mashtime;
135 }
136
137 if (!(rows = $('#fermentableGrid').jqxGrid('getrows'))) {
138 return; // grid not yet loaded.
139 }
140
141 for (i = 0; i < rows.length; i++) {
142 row = rows[i];
143 if (row.f_adjust_to_total_100)
144 my_100 = true;
145 if (row.f_type == 1 && row.f_added < 4) // Sugar
146 psugar += row.f_percentage;
147 if (row.f_graintype == 2 && row.f_added < 4) // Crystal
148 pcara += row.f_percentage;
149 d = row.f_amount * (row.f_yield / 100) * (1 - row.f_moisture / 100);
150 if (row.f_added == 0) { // Mash
151 if (mvol > 0) { // Only if mash already known
152 mvol += row.f_amount * row.f_moisture / 100;
153 s += d;
154 }
155 d = parseFloat(dataRecord.efficiency) / 100 * d;
156 sugarsm += d;
157 mashkg += row.f_amount;
158 }
159 if (row.f_added == 0 || row.f_added == 1) // Mash or Boil
160 sugarsf += d;
161 if (row.f_added == 2 || row.f_added == 3) { // Fermentation or lagering
162 x = (row.f_yield / 100) * (1 - row.f_moisture / 100);
163 addedS += row.f_amount * x;
164 addedmass += row.f_amount;
165 vol += (x * sugardensity + (1 - x) * 1) * row.f_amount;
166 }
167 if (row.f_added == 0 && (row.f_type == 0 || row.f_type == 4) && row.f_color < 50) { // Mash and Grain/Adjunct and Color < 50
168 lintner += row.f_diastatic_power * row.f_amount;
169 }
170 if (row.f_added < 4) {
171 colort += row.f_amount * ebc_to_srm(row.f_color);
172 colorh += row.f_amount * row.f_color * get_kt(row.f_color);
173 colorn += (row.f_percentage / 100) * row.f_color; // For 8.6 Pt wort.
174 }
175 }
176 $('#ferm_lintner').val(Math.round(parseFloat(lintner / mashkg)));
177 to_100 = my_100;
178
179 // Estimate total recipe OG.
180 dataRecord.est_og = estimate_sg(sugarsf + addedS, parseFloat(dataRecord.batch_size));
181 $('#est_og').val(dataRecord.est_og);
182 $('#est_og2').val(dataRecord.est_og);
183 org = dataRecord.est_og;
184
185 // Estimate SG in kettle before boil
186 preboil_sg = estimate_sg(sugarsm, parseFloat(dataRecord.boil_size));
187
188 // Color of the wort
189 if (dataRecord.color_method == 4) {
190 color = Math.round(((sg_to_plato(dataRecord.est_og) / 8.6) * colorn) + (dataRecord.boil_time / 60));
191 } else if (dataRecord.color_method == 3) { // Hans Halberstadt
192 color = Math.round((4.46 * bv * sr) / parseFloat(dataRecord.batch_size) * colorh);
193 } else {
194 cw = colort / parseFloat(dataRecord.batch_size) * 8.34436;
195 color = kw_to_ebc(dataRecord.color_method, cw);
196 }
197 dataRecord.est_color = color;
198 $('#est_color').val(color);
199 $('#est_color2').val(color);
200 scolor = ebc_to_color(color);
201 document.getElementById('bcolor').style.background = scolor;
202 document.getElementById('bcolor2').style.background = scolor;
203
204 // Progress bars
205 pmalts = mashkg / (dataRecord.boil_size / 3) * 100;
206 $('#perc_malts').jqxProgressBar('val', pmalts);
207 $('#perc_sugars').jqxProgressBar('val', psugar);
208 $('#perc_cara').jqxProgressBar('val', pcara);
209
210 // Calculate estimated svg.
211 svg = 0; // default.
212 rows = $('#yeastGrid').jqxGrid('getrows');
213 for (i = 0; i < rows.length; i++) {
214 row = rows[i];
215 if (row.y_use == 0) { // Primary
216 if (parseFloat(row.y_attenuation) > svg)
217 svg = parseFloat(row.y_attenuation); // Take the highest if multiple yeasts.
218 }
219 // TODO: brett in secondary ??
220 }
221 if (svg == 0)
222 svg = 77;
223
224 if ((mashkg > 0) && (mash_infuse > 0) && (mashtime > 0) && (mashtemp > 0)) {
225 dataRecord.est_fg = estimate_fg(psugar, pcara, mash_infuse / mashkg, mashtime, mashtemp, svg, dataRecord.est_og);
226 } else {
227 dataRecord.est_fg = estimate_fg(psugar, pcara, 0, 0, 0, svg, dataRecord.est_og);
228 }
229 $('#est_fg').val(dataRecord.est_fg);
230 $('#est_fg2').val(dataRecord.est_fg);
231 fig = dataRecord.est_fg;
232
233 dataRecord.est_abv = abvol(dataRecord.est_og, dataRecord.est_fg);
234 $('#est_abv').val(dataRecord.est_abv);
235 $('#est_abv2').val(dataRecord.est_abv);
236
237 // Calculate the calories in kcal/l (from brouwhulp)
238 alc = 1881.22 * fig * (org - fig) / (1.775 - org);
239 sug = 3550 * fig * (0.1808 * org + 0.8192 * fig - 1.0004);
240 $('#kcal').val(Math.round((alc + sug) / (12 * 0.0295735296)));
241 }
242
243
244 function infusionVol(step_infused, step_mashkg, infuse_temp, step_temp, last_temp) {
245 var a = last_temp * (eq_tun_weight * eq_tun_specific_heat + step_infused * SpecificHeatWater + step_mashkg * SpecificHeatMalt);
246 var b = step_temp * (eq_tun_weight * eq_tun_specific_heat + step_infused * SpecificHeatWater + step_mashkg * SpecificHeatMalt);
247 var vol = Round(((b - a) / ((infuse_temp - step_temp) * SpecificHeatWater)), 2);
248 console.log('infusionVol(' + step_infused + ', ' + step_mashkg + ', ' + infuse_temp + ', ' + step_temp + ', ' + last_temp + '): ' + vol);
249 return vol;
250 }
251
252
253 function decoctionVol(step_volume, step_temp, prev_temp) {
254 var a = (eq_tun_weight * eq_tun_specific_heat + step_volume * SpecificHeatWater) * (step_temp - prev_temp);
255 var b = SpecificHeatWater * (99 - step_temp);
256 var vol = 0;
257 if (b > 0)
258 vol = Round(a / b, 6);
259 console.log('decoctionVol(' + step_volume + ', ' + step_temp + ', ' + prev_temp + '): ' + vol);
260 return vol;
261 }
262
263
264 function calcMash() {
265 var infused = 0, vol, i, j, n, a, b, row, rows, temp;
266 var lasttemp = 18.0;
267 var graintemp = 18.0;
268 var tuntemp = 18.0;
269
270 if ((rows = $('#mashGrid').jqxGrid('getrows')) && (mashkg > 0)) {
271 console.log('calcMash()');
272 for (i = 0; i < rows.length; i++) {
273 row = $('#mashGrid').jqxGrid('getrowdata', i);
274 if (row.step_type == 0) { // Infusion
275 if (i == 0) {
276 // First mash step, temperature from the mashtun and malt.
277 n = 20; // tun is preheated.
278 tuntemp = row.step_temp;
279 for (j = 0; j < n; j++) {
280 a = mashkg * graintemp * SpecificHeatMalt + eq_tun_weight * tuntemp * eq_tun_specific_heat;
281 b = row.step_temp * (eq_tun_weight * eq_tun_specific_heat + row.step_infuse_amount * SpecificHeatWater + mashkg * SpecificHeatMalt) - SlakingHeat * mashkg;
282 if (row.step_infuse_amount > 0) {
283 temp = (b - a) / (row.step_infuse_amount * SpecificHeatWater);
284 } else {
285 temp = 99;
286 }
287 tuntemp += (temp - tuntemp) / 2;
288 row.step_infuse_temp = Round(temp, 6);
289 }
290 console.log('init infuse temp: ' + row.step_infuse_temp);
291 } else {
292 // Calculate amount of infusion water.
293 row.step_infuse_amount = infusionVol(infused, mashkg, row.step_infuse_temp, row.step_temp, lasttemp);
294 //console.log('vol: ' + row.step_infuse_amount + ' temp: ' + row.step_infuse_temp);
295 }
296 infused += row.step_infuse_amount;
297 } else if (row.step_type == 1) { // Temperature
298 if (i > 0)
299 row.step_infuse_amount = 0;
300 row.step_infuse_temp = 0;
301 } else if (row.step_type == 2) { // Decoction
302 row.step_infuse_amount = decoctionVol(infused, row.step_temp, lasttemp);
303 row.step_infuse_temp = 99;
304 }
305 row.step_volume = infused;
306 //console.log(i + ' type: ' + row.step_type + ' volume: ' + row.step_infuse_amount + ' temp: ' + row.step_infuse_temp);
307 lasttemp = row.step_temp;
308 mashtime += row.step_time + row.ramp_time;
309 row.step_wg_ratio = Round(infused / mashkg, 6);
310 $('#mashGrid').jqxGrid('updaterow', i, row);
311 }
312 }
313 }
314
315
316 function GetBUGU() {
317 var gu = (dataRecord.est_og - 1) * 1000;
318 if (gu > 0)
319 return dataRecord.est_ibu / gu;
320 else
321 return 0.5;
322 }
323
324
325 function GetOptSO4Clratio() {
326 var BUGU = GetBUGU();
327 return (-1.2 * BUGU + 1.4);
328 }
329
330
331
332 function setRangeIndicator(ion, rangeCode) {
333 if ((rangeCode == 'laag') || (rangeCode == 'hoog'))
334 $('#wr_' + ion).html('<img src="images/dialog-error.png"><span style="vertical-align: top; font-size: 10px; font-style: italic;">' + rangeCode + '</span>');
335 else
336 $('#wr_' + ion).html('<img src="images/dialog-ok-apply.png">');
337 }
338
339
340 function mix(v1, v2, c1, c2) {
341 if ((v1 + v2) > 0) {
342 return ((v1 * c1) + (v2 * c2)) / (v1 + v2);
343 }
344 return 0;
345 }
346
347
348 // mg/l as CaCO3
349 function ResidualAlkalinity(total_alkalinity, calcium, magnesium) {
350 return total_alkalinity - (calcium / 1.4 + magnesium / 1.7);
351 }
352
353
354 function PartCO3(pH) {
355 var H = Math.pow(10, -pH);
356 return 100 * Ka1 * Ka2 / (H * H + H * Ka1 + Ka1 * Ka2);
357 }
358
359
360 function PartHCO3(pH) {
361 var H = Math.pow(10, -pH);
362 return 100 * Ka1 * H / (H * H + H * Ka1 + Ka1 * Ka2);
363 }
364
365
366 function Charge(pH) {
367 return (-2 * PartCO3(pH) - PartHCO3(pH));
368 }
369
370
371 //Z alkalinity is the amount of acid (in mEq/l) needed to bring water to the target pH (Z pH)
372 function ZAlkalinity(pHZ) {
373 var C43 = Charge(4.3),
374 Cw = Charge(parseFloat($('#wg_ph').jqxNumberInput('decimal'))),
375 Cz = Charge(pHZ),
376 DeltaCNaught = -C43 + Cw,
377 CT = parseFloat($('#wg_total_alkalinity').jqxNumberInput('decimal')) / 50 / DeltaCNaught,
378 DeltaCZ = -Cz + Cw;
379 return CT * DeltaCZ;
380 }
381
382
383 //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)
384 function ZRA(pHZ) {
385 var Calc = parseFloat($('#wg_calcium').jqxNumberInput('decimal')) / (MMCa / 2),
386 Magn = parseFloat($('#wg_magnesium').jqxNumberInput('decimal')) / (MMMg / 2),
387 Z = ZAlkalinity(pHZ);
388 return Z - (Calc / 3.5 + Magn / 7);
389 }
390
391
392 function BufferCapacity(di_ph, acid_to_ph_57, ebc, graintype) {
393 C1 = 0;
394 if ((di_ph != 5.7) && ((acid_to_ph_57 < - 0.1) || (acid_to_ph_57 > 0.1))) {
395 C1 = acid_to_ph_57 / (di_ph - 5.7);
396 } else {
397 // If the acid_to_ph_5.7 is unknown from the maltster, guess the required acid.
398 switch (graintype) {
399 case 0: // Base, Special, Kilned
400 case 3:
401 case 5: C1 = 0.014 * ebc - 34.192;
402 break;
403 case 2: C1 = -0.0597 * ebc - 32.457; // Crystal
404 break;
405 case 1: C1 = 0.0107 * ebc - 54.768; // Roast
406 break;
407 case 4: C1 = -149; // Sour malt
408 break;
409 }
410 }
411 return C1;
412 }
413
414
415 function ProtonDeficit(pHZ) {
416 var C1, i, rows, row, Result = ZRA(pHZ) * parseFloat($('#wg_amount').jqxNumberInput('decimal'));
417 // proton deficit for the grist
418 if ((rows = $('#fermentableGrid').jqxGrid('getrows'))) {
419 for (i = 0; i < rows.length; i++) {
420 row = rows[i];
421 if (row.f_added == 0 && row.f_graintype != 6) { // Added == Mash && graintype != No Malt
422 C1 = BufferCapacity(row.f_di_ph, row.f_acid_to_ph_57, row.f_color, row.f_graintype);
423 x = C1 * (pHZ - row.f_di_ph); // AcidRequired(ZpH)
424 Result += x * row.f_amount;
425 }
426 }
427 } else {
428 error_count++;
429 if (error_count < 5)
430 console.log('ProtonDeficit(' + pHZ + ') invalid grist, return ' + Result);
431 }
432 return Result;
433 }
434
435
436 function MashpH() {
437 var n = 0,
438 pH = 5.4,
439 deltapH = 0.001,
440 deltapd = 0.1,
441 pd = ProtonDeficit(pH);
442 while (((pd < -deltapd) || (pd > deltapd)) && (n < 2000)) {
443 n++;
444 if (pd < -deltapd)
445 pH -= deltapH;
446 else if (pd > deltapd)
447 pH += deltapH;
448 pd = ProtonDeficit(pH);
449 }
450 pH = Round(pH, 6);
451 //console.log('MashpH() n: ' + n + ' pH: ' + pH);
452 return pH;
453 }
454
455
456
457
458 $(document).ready(function() {
459
460 var to_100 = false, // Fermentables adjust to 100%
461
462 fermentableRow = 0,
463 fermentableData = {},
464 hopRow = 0,
465 hopData = {},
466 miscRow = 0,
467 miscData = {},
468 yeastRow = 0,
469 yeastData = {},
470 mashRow = 0,
471 mashData = {},
472
473 url = 'includes/db_recipes.php',
474 // prepare the data
475 source = {
476 datatype: 'json',
477 cache: false,
478 datafields: [
479 { name: 'record', type: 'number' },
480 { name: 'uuid', type: 'string' },
481 { name: 'locked', type: 'int' },
482 { name: 'st_name', type: 'string' },
483 { name: 'st_letter', type: 'string' },
484 { name: 'st_guide', type: 'string' },
485 { name: 'st_type', type: 'int' },
486 { name: 'st_category', type: 'string' },
487 { name: 'st_category_number', type: 'int' },
488 { name: 'st_og_min', type: 'float' },
489 { name: 'st_og_max', type: 'float' },
490 { name: 'st_fg_min', type: 'float' },
491 { name: 'st_fg_max', type: 'float' },
492 { name: 'st_ibu_min', type: 'float' },
493 { name: 'st_ibu_max', type: 'float' },
494 { name: 'st_color_min', type: 'float' },
495 { name: 'st_color_max', type: 'float' },
496 { name: 'st_carb_min', type: 'float' },
497 { name: 'st_carb_max', type: 'float' },
498 { name: 'st_abv_min', type: 'float' },
499 { name: 'st_abv_max', type: 'float' },
500 { name: 'name', type: 'string' },
501 { name: 'notes', type: 'string' },
502 { name: 'type', type: 'int' },
503 { name: 'batch_size', type: 'float' },
504 { name: 'boil_size', type: 'float' },
505 { name: 'boil_time', type: 'float' },
506 { name: 'efficiency', type: 'float' },
507 { name: 'est_og', type: 'float' },
508 { name: 'est_fg', type: 'float' },
509 { name: 'est_abv', type: 'float' },
510 { name: 'est_color', type: 'float' },
511 { name: 'color_method', type: 'int' },
512 { name: 'est_ibu', type: 'float' },
513 { name: 'ibu_method', type: 'int' },
514 { name: 'est_carb', type: 'float' },
515 { name: 'sparge_temp', type: 'float' },
516 { name: 'sparge_ph', type: 'float' },
517 { name: 'sparge_volume', type: 'float' },
518 { name: 'sparge_source', type: 'int' },
519 { name: 'sparge_acid_type', type: 'int' },
520 { name: 'sparge_acid_perc', type: 'float' },
521 { name: 'sparge_acid_amount', type: 'float' },
522 { name: 'mash_ph', type: 'float' },
523 { name: 'mash_name', type: 'string' },
524 { name: 'calc_acid', type: 'int' },
525 { name: 'w1_name', type: 'string' },
526 { name: 'w1_amount', type: 'float' },
527 { name: 'w1_calcium', type: 'float' },
528 { name: 'w1_sulfate', type: 'float' },
529 { name: 'w1_chloride', type: 'float' },
530 { name: 'w1_sodium', type: 'float' },
531 { name: 'w1_magnesium', type: 'float' },
532 { name: 'w1_total_alkalinity', type: 'float' },
533 { name: 'w1_ph', type: 'float' },
534 { name: 'w1_cost', type: 'float' },
535 { name: 'w2_name', type: 'string' },
536 { name: 'w2_amount', type: 'float' },
537 { name: 'w2_calcium', type: 'float' },
538 { name: 'w2_sulfate', type: 'float' },
539 { name: 'w2_chloride', type: 'float' },
540 { name: 'w2_sodium', type: 'float' },
541 { name: 'w2_magnesium', type: 'float' },
542 { name: 'w2_total_alkalinity', type: 'float' },
543 { name: 'w2_ph', type: 'float' },
544 { name: 'w2_cost', type: 'float' },
545 { name: 'wg_amount', type: 'float' },
546 { name: 'wg_calcium', type: 'float' },
547 { name: 'wg_sulfate', type: 'float' },
548 { name: 'wg_chloride', type: 'float' },
549 { name: 'wg_sodium', type: 'float' },
550 { name: 'wg_magnesium', type: 'float' },
551 { name: 'wg_total_alkalinity', type: 'float' },
552 { name: 'wg_ph', type: 'float' },
553 { name: 'wb_calcium', type: 'float' },
554 { name: 'wb_sulfate', type: 'float' },
555 { name: 'wb_chloride', type: 'float' },
556 { name: 'wb_sodium', type: 'float' },
557 { name: 'wb_magnesium', type: 'float' },
558 { name: 'wb_total_alkalinity', type: 'float' },
559 { name: 'wb_ph', type: 'float' },
560 { name: 'wa_acid_name', type: 'int' },
561 { name: 'wa_acid_perc', type: 'int' },
562 { name: 'wa_base_name', type: 'int' },
563 { name: 'fermentables', type: 'string' },
564 { name: 'hops', type: 'string' },
565 { name: 'miscs', type: 'string' },
566 { name: 'yeasts', type: 'string' },
567 { name: 'mashs', type: 'string' }
568 ],
569 id: 'record',
570 url: url + '?record=' + my_record
571 },
572 // Load data and select one record.
573 dataAdapter = new $.jqx.dataAdapter(source, {
574 loadComplete: function() {
575 var records = dataAdapter.records;
576 dataRecord = records[0];
577 // Hidden record uuid
578 $('#name').val(dataRecord.name);
579 $('#notes').val(dataRecord.notes);
580 // Hidden record locked
581 $('#st_name').val(dataRecord.st_name);
582 $('#st_letter').val(dataRecord.st_letter);
583 $('#st_guide').val(dataRecord.st_guide);
584 $('#st_category').val(dataRecord.st_category);
585 $('#st_category_number').val(dataRecord.st_category_number);
586 $('#st_type').val(StyleTypeData[dataRecord.st_type].nl);
587 $('#type').val(RecipeTypeData[dataRecord.type].nl);
588 $('#batch_size').val(dataRecord.batch_size);
589 $('#boil_size').val(dataRecord.boil_size);
590 $('#boil_time').val(dataRecord.boil_time);
591 $('#efficiency').val(dataRecord.efficiency);
592 $('#est_og').val(dataRecord.est_og);
593 $('#est_og2').val(dataRecord.est_og);
594 $('#st_og_min').val(dataRecord.st_og_min);
595 $('#st_og_max').val(dataRecord.st_og_max);
596 $('#est_fg').val(dataRecord.est_fg);
597 $('#est_fg2').val(dataRecord.est_fg);
598 $('#st_fg_min').val(dataRecord.st_fg_min);
599 $('#st_fg_max').val(dataRecord.st_fg_max);
600 $('#est_fg').val(dataRecord.est_fg);
601 $('#est_fg2').val(dataRecord.est_fg);
602 $('#st_fg_min').val(dataRecord.st_fg_min);
603 $('#st_fg_max').val(dataRecord.st_fg_max);
604 $('#est_color').val(dataRecord.est_color);
605 $('#est_color2').val(dataRecord.est_color);
606 $('#est_abv').val(dataRecord.est_abv);
607 $('#est_abv2').val(dataRecord.est_abv);
608 $('#st_abv_min').val(dataRecord.st_abv_min);
609 $('#st_abv_max').val(dataRecord.st_abv_max);
610 $('#st_color_min').val(dataRecord.st_color_min);
611 $('#st_color_max').val(dataRecord.st_color_max);
612 $('#color_method').val(ColorMethodData[dataRecord.color_method].nl);
613 $('#est_ibu').val(dataRecord.est_ibu);
614 $('#est_ibu2').val(dataRecord.est_ibu);
615 $('#st_ibu_min').val(dataRecord.st_ibu_min);
616 $('#st_ibu_max').val(dataRecord.st_ibu_max);
617 $('#ibu_method').val(IBUmethodData[dataRecord.ibu_method].nl);
618 $('#est_carb').val(dataRecord.est_carb);
619 $('#st_carb_min').val(dataRecord.st_carb_min);
620 $('#st_carb_max').val(dataRecord.st_carb_max);
621 $('#mash_name').val(dataRecord.mash_name);
622 $('#mash_ph').val(dataRecord.mash_ph);
623 // Hidden record sparge_temp
624 $('#sparge_ph').val(dataRecord.sparge_ph);
625 $('#sw_amount').val(dataRecord.sparge_volume);
626 // Hidden record sparge_source
627 $('#sparge_acid_type').val(AcidTypeData[dataRecord.sparge_acid_type].nl);
628 $('#sparge_acid_perc').val(dataRecord.sparge_acid_perc);
629 $('#sparge_acid_amount').val(dataRecord.sparge_acid_amount * 1000);
630 $('#calc_acid').val(dataRecord.calc_acid);
631 $('#w1_name').val(dataRecord.w1_name);
632 $('#w1_amount').val(dataRecord.w1_amount);
633 $('#w1_calcium').val(dataRecord.w1_calcium);
634 $('#w1_sulfate').val(dataRecord.w1_sulfate);
635 $('#w1_chloride').val(dataRecord.w1_chloride);
636 $('#w1_sodium').val(dataRecord.w1_sodium);
637 $('#w1_magnesium').val(dataRecord.w1_magnesium);
638 $('#w1_total_alkalinity').val(dataRecord.w1_total_alkalinity);
639 $('#w1_ph').val(dataRecord.w1_ph);
640 $('#w1_bicarbonate').val(Bicarbonate(dataRecord.w1_total_alkalinity, dataRecord.w1_ph));
641 $('#w1_cost').val(dataRecord.w1_cost);
642 $('#w2_name').val(dataRecord.w2_name);
643 $('#w2_amount').val(dataRecord.w2_amount);
644 $('#w2_calcium').val(dataRecord.w2_calcium);
645 $('#w2_sulfate').val(dataRecord.w2_sulfate);
646 $('#w2_chloride').val(dataRecord.w2_chloride);
647 $('#w2_sodium').val(dataRecord.w2_sodium);
648 $('#w2_magnesium').val(dataRecord.w2_magnesium);
649 $('#w2_total_alkalinity').val(dataRecord.w2_total_alkalinity);
650 $('#w2_ph').val(dataRecord.w2_ph);
651 $('#w2_bicarbonate').val(Bicarbonate(dataRecord.w2_total_alkalinity, dataRecord.w2_ph));
652 $('#w2_cost').val(dataRecord.w2_cost);
653 $('#wg_amount').val(dataRecord.wg_amount);
654 $('#wg_calcium').val(dataRecord.wg_calcium);
655 $('#wg_sulfate').val(dataRecord.wg_sulfate);
656 $('#wg_chloride').val(dataRecord.wg_chloride);
657 $('#wg_sodium').val(dataRecord.wg_sodium);
658 $('#wg_magnesium').val(dataRecord.wg_magnesium);
659 $('#wg_total_alkalinity').val(dataRecord.wg_total_alkalinity);
660 $('#wg_ph').val(dataRecord.wg_ph);
661 $('#wb_calcium').val(dataRecord.wb_calcium);
662 $('#wb_sulfate').val(dataRecord.wb_sulfate);
663 $('#wb_chloride').val(dataRecord.wb_chloride);
664 $('#wb_sodium').val(dataRecord.wb_sodium);
665 $('#wb_magnesium').val(dataRecord.wb_magnesium);
666 $('#wb_total_alkalinity').val(dataRecord.wb_total_alkalinity);
667 $('#wb_ph').val(dataRecord.wb_ph);
668 $('#wa_acid_name').val(AcidTypeData[dataRecord.wa_acid_name].nl);
669 $('#wa_acid_perc').val(dataRecord.wa_acid_perc);
670 editFermentable(dataRecord);
671 editHop(dataRecord);
672 editMisc(dataRecord);
673 editYeast(dataRecord);
674 editMash(dataRecord);
675 $('#jqxTabs').jqxTabs('next');
676 data_loaded = 1;
677 },
678 loadError: function(jqXHR, status, error) {},
679 beforeLoadComplete: function(records) { $('#jqxLoader').jqxLoader('open'); }
680 }),
681
682 // Inline fermentables editor
683 editFermentable = function(data) {
684 var fermentableSource = {
685 localdata: data.fermentables,
686 datafields: [
687 { name: 'f_name', type: 'string' },
688 { name: 'f_origin', type: 'string' },
689 { name: 'f_supplier', type: 'string' },
690 { name: 'f_amount', type: 'float' },
691 { name: 'f_cost', type: 'float' },
692 { name: 'f_type', type: 'int' },
693 { name: 'f_yield', type: 'float' },
694 { name: 'f_color', type: 'float' },
695 { name: 'f_coarse_fine_diff', type: 'float' },
696 { name: 'f_moisture', type: 'float' },
697 { name: 'f_diastatic_power', type: 'float' },
698 { name: 'f_protein', type: 'float' },
699 { name: 'f_max_in_batch', type: 'float' },
700 { name: 'f_graintype', type: 'int' },
701 { name: 'f_added', type: 'int' },
702 { name: 'f_dissolved_protein', type: 'float' },
703 { name: 'f_recommend_mash', type: 'int' },
704 { name: 'f_add_after_boil', type: 'int' },
705 { name: 'f_adjust_to_total_100', type: 'int' },
706 { name: 'f_percentage', type: 'float' },
707 { name: 'f_di_ph', type: 'float' },
708 { name: 'f_acid_to_ph_57', type: 'float' },
709 { name: 'f_inventory', type: 'float' },
710 { name: 'f_avail', type: 'int' }
711 ],
712 },
713 fermentableAdapter = new $.jqx.dataAdapter(fermentableSource);
714
715 $('#fermentableGrid').jqxGrid({
716 width: 1240,
717 height: 470,
718 source: fermentableAdapter,
719 theme: theme,
720 editable: false,
721 ready: function() {
722 calcFermentables();
723 $('#jqxTabs').jqxTabs('next');
724 },
725 columns: [
726 { text: 'Vergistbaar ingredi&euml;nt', datafield: 'f_name' },
727 { text: 'Leverancier', datafield: 'f_supplier', width: 180 },
728 { text: 'Kleur', datafield: 'f_color', width: 90, align: 'right',
729 cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) {
730 return '<span style="margin: 4px; margin-top: 6px; float: right;">' + dataAdapter.formatNumber(value, 'f0') + ' EBC</span>';
731 }
732 },
733 { text: 'Type', width: 100, datafield: 'f_type',
734 cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) {
735 return '<span style="margin: 3px; margin-top: 6px; float: left;">' + FermentableTypeData[value].nl + '</span>';
736 }
737 },
738 { text: 'Moment', width: 110, datafield: 'f_added',
739 cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) {
740 return '<span style="margin: 3px; margin-top: 6px; float: left;">' + AddedData[value].nl + '</span>';
741 }
742 },
743 { text: 'Maxinbatch', datafield: 'f_max_in_batch', hidden: true },
744 { text: 'Opbrengst', editable: false, datafield: 'f_yield', width: 90, align: 'right', cellsalign: 'right', cellsformat: 'p1' },
745 { text: 'Gewicht Kg', datafield: 'f_amount', width: 120, align: 'right', cellsalign: 'right', cellsformat: 'f3' },
746 { text: 'Procent', datafield: 'f_percentage', width: 90, align: 'right',
747 cellsrenderer: function(row, columnfield, value, defaulthtml, columnproperties, rowdata) {
748 var color = '#ffffff';
749 if (value > rowdata.f_max_in_batch)
750 color = '#ff4040';
751 return '<span style="margin: 4px; margin-top: 6px; float: right; color: ' +
752 color + ';">' + fermentableAdapter.formatNumber(value, 'p1') + '</span>';
753 }
754 },
755 { text: '100%', align: 'center', datafield: 'f_adjust_to_total_100', columntype: 'checkbox', width: 70 }
756 ]
757 });
758 };
759
760 // Inline hops editor
761 var editHop = function(data) {
762 var hopSource = {
763 localdata: data.hops,
764 datafields: [
765 { name: 'h_name', type: 'string' },
766 { name: 'h_origin', type: 'string' },
767 { name: 'h_amount', type: 'float' },
768 { name: 'h_cost', type: 'float' },
769 { name: 'h_type', type: 'int' },
770 { name: 'h_form', type: 'int' },
771 { name: 'h_useat', type: 'int' },
772 { name: 'h_time', type: 'float' },
773 { name: 'h_alpha', type: 'float' },
774 { name: 'h_beta', type: 'float' },
775 { name: 'h_hsi', type: 'float' },
776 { name: 'h_humulene', type: 'float' },
777 { name: 'h_caryophyllene', type: 'float' },
778 { name: 'h_cohumulone', type: 'float' },
779 { name: 'h_myrcene', type: 'float' },
780 { name: 'h_total_oil', type: 'float' },
781 { name: 'h_inventory', type: 'float' },
782 { name: 'h_avail', type: 'int' }
783 ],
784 },
785 hopAdapter = new $.jqx.dataAdapter(hopSource);
786
787 $('#hopGrid').jqxGrid({
788 width: 1240,
789 height: 560,
790 source: hopAdapter,
791 theme: theme,
792 editable: false,
793 ready: function() { $('#jqxTabs').jqxTabs('next'); },
794 columns: [
795 { text: 'Hop', datafield: 'h_name' },
796 { text: 'Origin', width: 180, datafield: 'h_origin' },
797 { text: 'Type', width: 90, datafield: 'h_type',
798 cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) {
799 return '<span style="margin: 4px; margin-top: 6px; float: left;">' + HopTypeData[value].nl + '</span>';
800 }
801 },
802 { text: 'Vorm', width: 110, datafield: 'h_form',
803 cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) {
804 return '<span style="margin: 4px; margin-top: 6px; float: left;">' + HopFormData[value].nl + '</span>';
805 }
806 },
807 { text: 'Alpha', datafield: 'h_alpha', width: 80, align: 'right', cellsalign: 'right', cellsformat: 'p1' },
808 { text: 'Gebruik', width: 110, datafield: 'h_useat',
809 cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) {
810 return '<span style="margin: 4px; margin-top: 6px; float: left;">' + HopUseData[value].nl + '</span>';
811 }
812 },
813 { text: 'Tijdsduur', datafield: 'h_time', width: 90, align: 'right',
814 cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) {
815 var duration = '';
816 if ((rowdata.h_useat == 2) || (rowdata.h_useat == 4)) // Boil, Whirlpool
817 duration = dataAdapter.formatNumber(value, 'f0') + ' min.';
818 else if (rowdata.h_useat == 5) // Dry hop
819 duration = dataAdapter.formatNumber(value / 1440, 'f0') + ' dagen';
820 return '<span style="margin: 4px; margin-top: 6px; float: right;">' + duration + '</span>';
821 }
822 },
823 { text: 'IBU', datafield: 'ibu', width: 80, align: 'right',
824 cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) {
825 var ibu = toIBU(rowdata.h_useat, rowdata.h_form, preboil_sg, parseFloat(dataRecord.batch_size),
826 parseFloat(rowdata.h_amount), parseFloat(rowdata.h_time),
827 parseFloat(rowdata.h_alpha), dataRecord.ibu_method, 0, parseFloat(rowdata.h_time), 0);
828 return '<span style="margin: 4px; margin-top: 6px; float: right;">' + dataAdapter.formatNumber(ibu, 'f1') + '</span>';
829 }
830 },
831 { text: 'Gewicht', datafield: 'h_amount', width: 110, align: 'right',
832 cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) {
833 var amount = dataAdapter.formatNumber(value, 'f1') + ' kg';
834 if (value < 1)
835 amount = dataAdapter.formatNumber(value * 1000, 'f1') + ' gr';
836 return '<span style="margin: 4px; margin-top: 6px; float: right;">' + amount + '</span>';
837 }
838 }
839 ]
840 });
841 };
842
843 // Inline miscs editor
844 var editMisc = function(data) {
845 var miscSource = {
846 localdata: data.miscs,
847 datafields: [
848 { name: 'm_name', type: 'string' },
849 { name: 'm_amount', type: 'float' },
850 { name: 'm_cost', type: 'float' },
851 { name: 'm_type', type: 'int' },
852 { name: 'm_use_use', type: 'int' },
853 { name: 'm_time', type: 'float' },
854 { name: 'm_amount_is_weight', type: 'int' },
855 { name: 'm_inventory', type: 'float' },
856 { name: 'm_avail', type: 'int' }
857 ],
858 },
859 miscAdapter = new $.jqx.dataAdapter(miscSource, {
860 beforeLoadComplete: function(records) {
861 var i, row, data = new Array();
862 for (i = 0; i < records.length; i++) {
863 row = records[i];
864 data.push(row);
865 // Initial set water agent values.
866 if (row.m_use_use == 1) { // Mash
867 switch (row.m_name) {
868 case 'CaCl2':
869 $('#wa_cacl2').val(row.m_amount * 1000);
870 break;
871 case 'CaSO4':
872 $('#wa_caso4').val(row.m_amount * 1000);
873 break;
874 case 'MgSO4':
875 $('#wa_mgso4').val(row.m_amount * 1000);
876 break;
877 case 'NaCl':
878 $('#wa_nacl').val(row.m_amount * 1000);
879 break;
880 case 'MgCl2':
881 $('#wa_mgcl2').val(row.m_amount * 1000);
882 break;
883 case 'NaHCO3':
884 $('#wa_nahco3').val(row.m_amount * 1000);
885 break;
886 case 'CaCO3':
887 $('#wa_caco3').val(row.m_amount * 1000);
888 break;
889 case 'Melkzuur':
890 $('#wa_acid_name').val(AcidTypeData[0].nl);
891 $('#wa_acid').val(row.m_amount * 1000);
892 $('#wa_acid_perc').val(AcidTypeData[0].AcidPrc);
893 last_acid = 'Melkzuur';
894 break;
895 case 'Zoutzuur':
896 $('#wa_acid_name').val(AcidTypeData[1].nl);
897 $('#wa_acid').val(row.m_amount * 1000);
898 $('#wa_acid_perc').val(AcidTypeData[1].AcidPrc);
899 last_acid = 'Zoutzuur';
900 break;
901 case 'Fosforzuur':
902 $('#wa_acid_name').val(AcidTypeData[2].nl);
903 $('#wa_acid').val(row.m_amount * 1000);
904 $('#wa_acid_perc').val(AcidTypeData[2].AcidPrc);
905 last_acid = 'Fosforzuur';
906 break;
907 case 'Zwavelzuur':
908 $('#wa_acid_name').val(AcidTypeData[3].nl);
909 $('#wa_acid').val(row.m_amount * 1000);
910 $('#wa_acid_perc').val(AcidTypeData[3].AcidPrc);
911 last_acid = 'Zwavelzuur';
912 break;
913 }
914 }
915 if (row.m_use_use == 6) { // Sparge
916 switch (row.m_name) {
917 case 'CaCl2':
918 $('#ss_cacl2').val(row.m_amount * 1000);
919 break;
920 case 'CaSO4':
921 $('#ss_caso4').val(row.m_amount * 1000);
922 break;
923 case 'MgSO4':
924 $('#ss_mgso4').val(row.m_amount * 1000);
925 break;
926 case 'NaCl':
927 $('#ss_nacl').val(row.m_amount * 1000);
928 break;
929 case 'MgCl2':
930 $('#ss_mgcl2').val(row.m_amount * 1000);
931 break;
932 case 'Melkzuur':
933 // $('#wa_acid_name').val(0);
934 // $('#wa_acid').val(row.m_amount * 1000);
935 // $('#wa_acid_perc').val(AcidTypeData[0].AcidPrc); // TODO: this ignores changed percentages.
936 // last_acid = 'Melkzuur';
937 break;
938 case 'Zoutzuur':
939 // $('#wa_acid_name').val(1);
940 // $('#wa_acid').val(row.m_amount * 1000);
941 // $('#wa_acid_perc').val(AcidTypeData[1].AcidPrc);
942 // last_acid = 'Zoutzuur';
943 break;
944 case 'Fosforzuur':
945 // $('#wa_acid_name').val(2);
946 // $('#wa_acid').val(row.m_amount * 1000);
947 // $('#wa_acid_perc').val(AcidTypeData[2].AcidPrc);
948 // last_acid = 'Fosforzuur';
949 break;
950 case 'Zwavelzuur':
951 // $('#wa_acid_name').val(3);
952 // $('#wa_acid').val(row.m_amount * 1000);
953 // $('#wa_acid_perc').val(AcidTypeData[3].AcidPrc);
954 // last_acid = 'Zwavelzuur';
955 break;
956 }
957 }
958 }
959 return data;
960 },
961 loadError: function(jqXHR, status, error) {}
962 });
963 $('#miscGrid').jqxGrid({
964 width: 1240,
965 height: 575,
966 source: miscAdapter,
967 theme: theme,
968 editable: false,
969 ready: function() {
970 $('#jqxTabs').jqxTabs('next');
971 },
972 columns: [
973 { text: 'Ingredient', datafield: 'm_name' },
974 { text: 'Type', width: 140, datafield: 'm_type',
975 cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) {
976 return '<span style="margin: 3px; margin-top: 6px; float: left;">' + MiscTypeData[value].nl + '</span>';
977 }
978 },
979 { text: 'Gebruik', width: 140, datafield: 'm_use_use',
980 cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) {
981 return '<span style="margin: 3px; margin-top: 6px; float: left;">' + MiscUseData[value].nl + '</span>';
982 }
983 },
984 { text: 'Tijd', datafield: 'm_time', width: 140, align: 'right',
985 cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) {
986 var duration = '';
987 if (rowdata.m_use_use == 2) // Boil
988 duration = dataAdapter.formatNumber(value, 'f0') + ' minuten';
989 else if ((rowdata.m_use_use == 3) || (rowdata.m_use_use == 4)) // Primary or Secondary
990 duration = dataAdapter.formatNumber(value / 1440, 'f0') + ' dagen';
991 return '<span style="margin: 4px; margin-top: 6px; float: right;">' + duration + '</span>';
992 }
993 },
994 { text: 'Hoeveel', datafield: 'm_amount', width: 110, align: 'right',
995 cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) {
996 var vstr = rowdata.m_amount_is_weight ? 'gr' : 'ml';
997 return '<span style="margin: 4px; margin-top: 6px; float: right;">' +
998 dataAdapter.formatNumber(value * 1000, 'f2') + ' ' + vstr + '</span>';
999 }
1000 }
1001 ]
1002 });
1003 };
1004
1005 // Inline yeasts editor
1006 var editYeast = function(data) {
1007 var yeastSource = {
1008 localdata: data.yeasts,
1009 datafields: [
1010 { name: 'y_name', type: 'string' },
1011 { name: 'y_laboratory', type: 'string' },
1012 { name: 'y_product_id', type: 'string' },
1013 { name: 'y_amount', type: 'float' },
1014 { name: 'y_cost', type: 'float' },
1015 { name: 'y_type', type: 'int' },
1016 { name: 'y_form', type: 'int' },
1017 { name: 'y_flocculation', type: 'int' },
1018 { name: 'y_min_temperature', type: 'float' },
1019 { name: 'y_max_temperature', type: 'float' },
1020 { name: 'y_attenuation', type: 'float' },
1021 { name: 'y_use', type: 'int' },
1022 { name: 'y_cells', type: 'float' },
1023 { name: 'y_tolerance', type: 'float' },
1024 { name: 'y_inventory', type: 'float' },
1025 { name: 'y_sta1', type: 'int' },
1026 { name: 'y_bacteria', type: 'int' },
1027 { name: 'y_harvest_top', type: 'int' },
1028 { name: 'y_harvest_time', type: 'int' },
1029 { name: 'y_pitch_temperature', type: 'float' },
1030 { name: 'y_pofpos', type: 'int' },
1031 { name: 'y_zymocide', type: 'int' },
1032 { name: 'y_gr_hl_lo', type: 'int' },
1033 { name: 'y_sg_lo', type: 'float' },
1034 { name: 'y_gr_hl_hi', type: 'int' },
1035 { name: 'y_sg_hi', type: 'float' },
1036 { name: 'y_avail', type: 'int' }
1037 ],
1038 },
1039 yeastAdapter = new $.jqx.dataAdapter(yeastSource);
1040
1041 $('#yeastGrid').jqxGrid({
1042 width: 1240,
1043 height: 350,
1044 source: yeastAdapter,
1045 theme: theme,
1046 editable: false,
1047 ready: function() {
1048 calcFermentables();
1049 $('#jqxTabs').jqxTabs('next');
1050 },
1051 columns: [
1052 { text: 'Gist', datafield: 'y_name' },
1053 { text: 'Laboratorium', width: 150, datafield: 'y_laboratory' },
1054 { text: 'Code', width: 90, datafield: 'y_product_id' },
1055 { text: 'Soort', width: 100, datafield: 'y_form',
1056 cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) {
1057 return '<span style="margin: 4px; margin-top: 6px; float: left;">' + YeastFormData[value].nl + '</span>';
1058 }
1059 },
1060 { text: 'Min. &deg;C', width: 70, align: 'right', cellsalign: 'right', datafield: 'y_min_temperature' },
1061 { text: 'Max. &deg;C', width: 70, align: 'right', cellsalign: 'right', datafield: 'y_max_temperature' },
1062 { text: 'Tol. %', width: 60, align: 'right', cellsalign: 'right', datafield: 'y_tolerance',
1063 cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) {
1064 var amount = '', color = '#ffffff';
1065 if (value > 0) {
1066 amount = dataAdapter.formatNumber(value, 'f1');
1067 if (dataRecord.est_abv > value)
1068 color = '#ff4040';
1069 }
1070 return '<span style="margin: 4px; margin-top: 6px; float: right; color: ' + color + ';">' + amount + '</span>';
1071 }
1072 },
1073 { text: 'Attn. %', width: 70, align: 'right', cellsalign: 'right', datafield: 'y_attenuation', cellsformat: 'f1' },
1074 { text: 'Voor', width: 120, datafield: 'y_use',
1075 cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) {
1076 return '<span style="margin: 4px; margin-top: 6px; float: left;">' + YeastUseData[value].nl + '</span>';
1077 }
1078 },
1079 { text: 'Hoeveel', datafield: 'y_amount', width: 90, align: 'right',
1080 cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) {
1081 var amount = dataAdapter.formatNumber(value * 1000, 'f0') + ' ml';
1082 if (rowdata.y_form == 0) // Liquid
1083 amount = dataAdapter.formatNumber(value, 'f0') + ' pk';
1084 else if (rowdata.y_form == 1) // Dry
1085 amount = dataAdapter.formatNumber(value * 1000, 'f1') + ' gr';
1086 return '<span style="margin: 4px; margin-top: 6px; float: right;">' + amount + '</span>';
1087 }
1088 }
1089 ]
1090 });
1091 };
1092
1093 // inline mash editor
1094 var editMash = function(data) {
1095 var mashSource = {
1096 localdata: data.mashs,
1097 datafields: [
1098 { name: 'step_name', type: 'string' },
1099 { name: 'step_type', type: 'int' },
1100 { name: 'step_volume', type: 'float' },
1101 { name: 'step_infuse_amount', type: 'float' },
1102 { name: 'step_infuse_temp', type: 'float' },
1103 { name: 'step_temp', type: 'float' },
1104 { name: 'step_time', type: 'float' },
1105 { name: 'step_wg_ratio', type: 'float' },
1106 { name: 'ramp_time', type: 'float' },
1107 { name: 'end_temp', type: 'float' }
1108 ],
1109 },
1110 mashAdapter = new $.jqx.dataAdapter(mashSource, {
1111 beforeLoadComplete: function(records) {
1112 mash_infuse = 0;
1113 var row, i, data = new Array();
1114 for (i = 0; i < records.length; i++) {
1115 row = records[i];
1116 if (row.step_type == 0) // Infusion
1117 mash_infuse += parseFloat(row.step_infuse_amount);
1118 row.step_wg_ratio = 0; // Init this field.
1119 data.push(row);
1120 }
1121 },
1122 });
1123 $('#mashGrid').jqxGrid({
1124 width: 1240,
1125 height: 400,
1126 source: mashAdapter,
1127 theme: theme,
1128 editable: false,
1129 ready: function() {
1130 calcFermentables();
1131 calcInit();
1132 calcMash();
1133 $('#jqxLoader').jqxLoader('close');
1134 $('#jqxTabs').jqxTabs('first');
1135 },
1136 columns: [
1137 { text: 'Stap naam', datafield: 'step_name' },
1138 { text: 'Stap type', datafield: 'step_type', width: 175,
1139 cellsrenderer: function(index, datafield, value, defaultvalue, column, rowdata) {
1140 return '<div style="margin: 4px;">' + MashStepTypeData[value].nl + '</div>';
1141 }
1142 },
1143 { text: 'Start &deg;C', datafield: 'step_temp', width: 90, align: 'right', cellsalign: 'right', cellsformat: 'f1' },
1144 { text: 'Eind &deg;C', datafield: 'end_temp', width: 90, align: 'right', cellsalign: 'right', cellsformat: 'f1' },
1145 { text: 'Rust min.', datafield: 'step_time', width: 90, align: 'right', cellsalign: 'right' },
1146 { text: 'Stap min.', datafield: 'ramp_time', width: 90, align: 'right', cellsalign: 'right' },
1147 { text: 'Inf/dec L.', datafield: 'step_infuse_amount', width: 90, align: 'right',
1148 cellsrenderer: function(row, columnfield, value, defaulthtml, columnproperties, rowdata) {
1149 if (rowdata.step_type == 1)
1150 return '<span></span>';
1151 return '<span style="margin: 4px; margin-top: 6px; float: right;">' + dataAdapter.formatNumber(value, 'f1') + '</span>';
1152 }
1153 },
1154 { text: 'Inf/dec &deg;C', datafield: 'step_infuse_temp', width: 90, align: 'right',
1155 cellsrenderer: function(row, columnfield, value, defaulthtml, columnproperties, rowdata) {
1156 if (rowdata.step_type == 1)
1157 return '<span></span>';
1158 return '<span style="margin: 4px; margin-top: 6px; float: right;">' + dataAdapter.formatNumber(value, 'f2') + '</span>';
1159 }
1160 },
1161 { text: 'L/Kg.', datafield: 'step_wg_ratio', width: 90, align: 'right',
1162 cellsrenderer: function(row, columnfield, value, defaulthtml, columnproperties, rowdata) {
1163 var color = '#ffffff';
1164 if (value < 2.0 || value > 6.0)
1165 color = '#ff4040';
1166 return '<span style="margin: 4px; margin-top: 6px; float: right; color: ' + color + ';">' + dataAdapter.formatNumber(value, 'f2') + '</span>';
1167 }
1168 }
1169 ]
1170 });
1171 };
1172
1173
1174 /*
1175 * Remove the top menu so that we MUST use the buttons to leave the editor.
1176 */
1177 $('#jqxMenu').jqxMenu('destroy');
1178
1179 console.log('record:' + my_record + ' return:' + my_return + ' theme:' + theme);
1180 $('#jqxLoader').jqxLoader({
1181 width: 250,
1182 height: 150,
1183 isModal: true,
1184 text: 'Laden recept ...',
1185 theme: theme
1186 });
1187
1188 function setWaterAgent(name, amount) {
1189
1190 var record, records, miscs, i, id, row, found = false, rows = $('#miscGrid').jqxGrid('getrows');
1191 if (amount == 0) {
1192 for (i = 0; i < rows.length; i++) {
1193 row = rows[i];
1194 if (row.m_name == name) {
1195 id = $('#miscGrid').jqxGrid('getrowid', i);
1196 $('#miscGrid').jqxGrid('deleterow', id);
1197 }
1198 }
1199 } else {
1200 for (i = 0; i < rows.length; i++) {
1201 row = rows[i];
1202 if (row.m_name == name) {
1203 found = true;
1204 $('#miscGrid').jqxGrid('setcellvalue', i, 'm_amount', amount / 1000);
1205 break;
1206 }
1207 }
1208 if (! found) {
1209 miscs = new $.jqx.dataAdapter(miscInvSource, {
1210 loadComplete: function() {
1211 records = miscs.records;
1212 for (i = 0; i < records.length; i++) {
1213 record = records[i];
1214 if (record.name == name) {
1215 row = {};
1216 row['m_name'] = record.name;
1217 row['m_amount'] = amount / 1000;
1218 row['m_cost'] = record.cost;
1219 row['m_type'] = record.type;
1220 row['m_use_use'] = record.use_use;
1221 row['m_time'] = 0;
1222 row['m_amount_is_weight'] = record.amount_is_weight;
1223 row['m_inventory'] = record.inventory;
1224 row['m_avail'] = 1;
1225 $('#miscGrid').jqxGrid('addrow', null, row);
1226 }
1227 }
1228 }
1229 });
1230 miscs.dataBind();
1231 return;
1232 }
1233 }
1234 }
1235
1236
1237 // Procedure TFrmWaterAdjustment.CalcWater2;
1238 function calcWater() {
1239
1240 if (! data_loaded) {
1241 console.log('calcWater(): failsave');
1242 return;
1243 }
1244
1245 var liters = 0,
1246 calcium = 0,
1247 magnesium = 0,
1248 sodium = 0,
1249 total_alkalinity = 0,
1250 bicarbonate = 0,
1251 chloride = 0,
1252 sulfate = 0,
1253 ph = 0,
1254 RA = 0,
1255 frac = 0,
1256 TpH = 0,
1257 protonDeficit = 0,
1258 AT, BT,
1259 r1d, r2d, f1d, f2d, f3d,
1260 deltapH, deltapd, pd, n,
1261 Res;
1262
1263 if (dataRecord.w1_name == '') {
1264 return;
1265 }
1266
1267 $('#w1_hardness').val(Hardness(dataRecord.w1_calcium, dataRecord.w1_magnesium));
1268 $('#w1_ra').val(ResidualAlkalinity(dataRecord.w1_total_alkalinity, dataRecord.w1_calcium, dataRecord.w1_magnesium));
1269
1270 // If there is a dillute water source, mix the waters.
1271 if (dataRecord.w2_name != '') {
1272 liters = dataRecord.w1_amount + dataRecord.w2_amount;
1273 calcium = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_calcium, dataRecord.w2_calcium);
1274 magnesium = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_magnesium, dataRecord.w2_magnesium);
1275 sodium = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_sodium, dataRecord.w2_sodium);
1276 chloride = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_chloride, dataRecord.w2_chloride);
1277 sulfate = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_sulfate, dataRecord.w2_sulfate);
1278 total_alkalinity = mix(dataRecord.w1_amount, dataRecord.w2_amount, dataRecord.w1_total_alkalinity, dataRecord.w2_total_alkalinity);
1279 ph = -Math.log10(((Math.pow(10, -dataRecord.w1_ph) * dataRecord.w1_amount) + (Math.pow(10, -dataRecord.w2_ph) * dataRecord.w2_amount)) / liters);
1280 $('#w2_hardness').val(Hardness(dataRecord.w2_calcium, dataRecord.w2_magnesium));
1281 $('#w2_ra').val(ResidualAlkalinity(dataRecord.w2_total_alkalinity, dataRecord.w2_calcium, dataRecord.w2_magnesium));
1282 } else {
1283 liters = dataRecord.w1_amount;
1284 calcium = dataRecord.w1_calcium;
1285 magnesium = dataRecord.w1_magnesium;
1286 sodium = dataRecord.w1_sodium;
1287 chloride = dataRecord.w1_chloride;
1288 sulfate = dataRecord.w1_sulfate;
1289 total_alkalinity = dataRecord.w1_total_alkalinity;
1290 ph = dataRecord.w1_ph;
1291 }
1292 var bicarbonate = Bicarbonate(total_alkalinity, ph);
1293
1294 /* Save mixed water ions for later */
1295 var wg_calcium = calcium;
1296 var wg_sodium = sodium;
1297 var wg_total_alkalinity = total_alkalinity;
1298 var wg_chloride = chloride;
1299 var wg_sulfate = sulfate;
1300 var wg_bicarbonate = bicarbonate;
1301
1302 dataRecord.wg_amount = liters;
1303 dataRecord.wg_ph = ph;
1304
1305 $('#wg_amount').val(liters);
1306 $('#wg_calcium').val(Round(calcium, 1));
1307 $('#wg_magnesium').val(Round(magnesium, 1));
1308 $('#wg_sodium').val(Round(sodium, 1));
1309 $('#wg_bicarbonate').val(Round(bicarbonate, 1));
1310 $('#wg_total_alkalinity').val(Round(total_alkalinity, 1));
1311 $('#wg_chloride').val(Round(chloride, 1));
1312 $('#wg_sulfate').val(Round(sulfate, 1));
1313 $('#wg_ph').val(Round(ph, 2));
1314 $('#wg_hardness').val(Round(Hardness(calcium, magnesium), 1));
1315 $('#wg_ra').val(Round(ResidualAlkalinity(total_alkalinity, calcium, magnesium), 1));
1316
1317 var mash_ph = Round(MashpH(), 3);
1318 console.log('Distilled water mash pH: ' + mash_ph);
1319
1320 /* Calculate Salt additions */
1321 if (liters > 0) {
1322 calcium += (parseFloat($('#wa_cacl2').jqxNumberInput('decimal')) * MMCa / MMCaCl2 * 1000 +
1323 parseFloat($('#wa_caso4').jqxNumberInput('decimal')) * MMCa / MMCaSO4 * 1000 +
1324 parseFloat($('#wa_caco3').jqxNumberInput('decimal')) * MMCa / MMCaCO3 * 1000) / liters;
1325 magnesium += (parseFloat($('#wa_mgso4').jqxNumberInput('decimal')) * MMMg / MMMgSO4 * 1000 +
1326 parseFloat($('#wa_mgcl2').jqxNumberInput('decimal')) * MMMg / MMMgCl2 * 1000) / liters;
1327 sodium += (parseFloat($('#wa_nacl').jqxNumberInput('decimal')) * MMNa / MMNaCl * 1000 +
1328 parseFloat($('#wa_nahco3').jqxNumberInput('decimal')) * MMNa / MMNaHCO3 * 1000) / liters;
1329 sulfate += (parseFloat($('#wa_caso4').jqxNumberInput('decimal')) * MMSO4 / MMCaSO4 * 1000 +
1330 parseFloat($('#wa_mgso4').jqxNumberInput('decimal')) * MMSO4 / MMMgSO4 * 1000) / liters;
1331 chloride += (2 * parseFloat($('#wa_cacl2').jqxNumberInput('decimal')) * MMCl / MMCaCl2 * 1000 +
1332 parseFloat($('#wa_nacl').jqxNumberInput('decimal')) * MMCl / MMNaCl * 1000 +
1333 parseFloat($('#wa_mgcl2').jqxNumberInput('decimal')) * MMCl / MMMgCl2 * 1000) / liters;
1334 bicarbonate += (parseFloat($('#wa_nahco3').jqxNumberInput('decimal')) * MMHCO3 / MMNaHCO3 * 1000 +
1335 parseFloat($('#wa_caco3').jqxNumberInput('decimal')) / 3 * MMHCO3 / MMCaCO3 * 1000) / liters;
1336 }
1337
1338 if (dataRecord.wa_acid_name < 0 || dataRecord,wa_acid_name >= AcidTypeData.length) {
1339 $('#wa_acid_name').val(0);
1340 dataRecord.wa_acid_name = 0;
1341 dataRecord.wa_acid_perc = AcidTypeData[0].AcidPrc;
1342 $('#wa_acid_perc').val(AcidTypeData[0].AcidPrc);
1343 }
1344 if (last_acid == '')
1345 last_acid = AcidTypeData[dataRecord.wa_acid_name].nl;
1346
1347 if (parseFloat(dataRecord.wa_acid_perc) == 0) {
1348 dataRecord.wa_acid_perc = AcidTypeData[AT].AcidPrc;
1349 $('#wa_acid_perc').val(AcidTypeData[AT].AcidPrc);
1350 }
1351
1352 AT = dataRecord.wa_acid_name;
1353
1354 /* Note that the next calculations do not correct the pH change by the added salts.
1355 This pH change is at most 0.1 pH and is a minor difference in Acid amount. */
1356
1357 if (dataRecord.calc_acid) {
1358 $('.c_mashph').show();
1359 /* Auto calculate pH */
1360 TpH = parseFloat(dataRecord.mash_ph);
1361 protonDeficit = ProtonDeficit(TpH);
1362 console.log('calc_acid tgt: ' + TpH + ' protonDeficit: ' + protonDeficit);
1363 if (protonDeficit > 0) { // Add acid
1364 frac = CalcFrac(TpH, AcidTypeData[AT].pK1, AcidTypeData[AT].pK2, AcidTypeData[AT].pK3);
1365 Acid = protonDeficit / frac;
1366 Acid *= AcidTypeData[AT].MolWt; // mg
1367 Acidmg = Acid;
1368 var RealSG = Round(((AcidTypeData[AT].AcidSG - 1000) * (parseFloat(dataRecord.wa_acid_perc) / 100)) + 1000, 2);
1369 Acid /= RealSG;
1370 Acid /= AcidTypeData[AT].AcidPrc / 100;
1371 Acid = Round(Acid, 2);
1372 console.log('Mash auto Acid final ml: ' + Acid);
1373 $('#wa_acid').val(Acid);
1374 setWaterAgent(AcidTypeData[AT].nl, Acid);
1375
1376 bicarbonate = bicarbonate - protonDeficit * frac / liters;
1377 total_alkalinity = bicarbonate * 50 / 61;
1378 }
1379 ph = TpH;
1380 dataRecord.wb_ph = ph;
1381 $('#wb_ph').val(Round(ph, 2));
1382 $('#est_mash_ph').val(Round(ph, 2));
1383 } else { // Manual
1384 /* Manual calculate pH */
1385 $('.c_mashph').hide();
1386 console.log('calc_acid no');
1387 pHa = Round(ph, 3); // Adjusted water pH
1388 // Then calculate the new pH with added acids and malts
1389 console.log('Mash pH: ' + pHa);
1390 Acid = AcidTypeData[AT].AcidSG * (parseFloat(dataRecord.wa_acid_perc) / 100); // ml
1391 Acid *= parseFloat($('#wa_acid').jqxNumberInput('decimal'));
1392 Acid /= AcidTypeData[AT].MolWt; // mg
1393 Acidmg = Acid;
1394
1395 //find the pH where the protondeficit = protondeficit by the acid
1396 frac = CalcFrac(pHa, AcidTypeData[AT].pK1, AcidTypeData[AT].pK2, AcidTypeData[AT].pK3);
1397 protonDeficit = Round(Acid * frac, 3);
1398 //console.log('protonDeficit Acid: ' + protonDeficit + ' frac: ' + frac + ' pH: ' + pHa);
1399
1400 deltapH = 0.001;
1401 deltapd = 0.1;
1402 pd = Round(ProtonDeficit(pHa), 6);
1403 n = 0;
1404 while (((pd < (protonDeficit - deltapd)) || (pd > (protonDeficit + deltapd))) && (n < 4000)) {
1405 n++;
1406 if (pd < (protonDeficit - deltapd))
1407 pHa -= deltapH;
1408 else if (pd > (protonDeficit + deltapd))
1409 pHa += deltapH;
1410 frac = CalcFrac(pHa, AcidTypeData[AT].pK1, AcidTypeData[AT].pK2, AcidTypeData[AT].pK3);
1411 protonDeficit = Acid * frac;
1412 pd = ProtonDeficit(pHa);
1413 }
1414 //console.log('n: ' + n + ' pd: ' + pd + ' protonDeficit: ' + protonDeficit + ' frac: ' + frac + ' pHa: ' + pHa);
1415 bicarbonate = wg_bicarbonate - protonDeficit * frac / liters;
1416 total_alkalinity = RA * 50 / 61;
1417 ph = pHa;
1418 $('#wb_ph').val(Round(ph, 2));
1419 $('#est_mash_ph').val(Round(ph, 2));
1420 }
1421
1422 if ((AT == 3) && (liters > 0)) { // Sulfuctic / Zwavelzuur
1423 RA = parseFloat($('#wa_caso4').jqxNumberInput('decimal')) * MMSO4 / MMCaSO4 +
1424 parseFloat($('#wa_mgso4').jqxNumberInput('decimal')) * MMSO4 / MMMgSO4 +
1425 Acidmg / 1000 * MMSO4 / (MMSO4 + 2);
1426 RA = 1000 * RA / liters;
1427 sulfate = wg_sulfate + RA; // Not add to sulfate??
1428 } else if ((AT == 1) && (liters > 0)) { // Hydrochloric, Zoutzuur
1429 RA = parseFloat($('#wa_cacl2').jqxNumberInput('decimal')) * MMCl / MMCaCl2 +
1430 parseFloat($('#wa_nacl').jqxNumberInput('decimal')) * MMCl / MMNaCl +
1431 Acidmg / 1000 * MMCl / (MMCl + 1);
1432 RA = 1000 * RA / liters;
1433 chloride = wg_chloride + RA;
1434 }
1435
1436 var BUGU = GetBUGU();
1437 $('#tgt_bu').val(Round(BUGU, 2));
1438 // From brouwhulp.
1439 if (BUGU < 0.32)
1440 $('#wr_bu').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Zeer moutig en zoet</span>");
1441 else if (BUGU < 0.43)
1442 $('#wr_bu').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Moutig, zoet</span>");
1443 else if (BUGU < 0.52)
1444 $('#wr_bu').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Evenwichtig</span>");
1445 else if (BUGU < 0.63)
1446 $('#wr_bu').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Licht hoppig, bitter</span>");
1447 else
1448 $('#wr_bu').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Extra hoppig, zeer bitter</span>");
1449
1450 // Sulfate to Chloride ratio (Palmer).
1451 var OptSO4Clratio = GetOptSO4Clratio();
1452 $('#tgt_so4_cl').val(Round(OptSO4Clratio, 1));
1453 if (OptSO4Clratio < 0.4)
1454 $('#wrt_so4_cl').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Te moutig</span>");
1455 else if (OptSO4Clratio < 0.6)
1456 $('#wrt_so4_cl').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Zeer moutig</span>");
1457 else if (OptSO4Clratio < 0.8)
1458 $('#wrt_so4_cl').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Moutig</span>");
1459 else if (OptSO4Clratio < 1.5)
1460 $('#wrt_so4_cl').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Gebalanceerd</span>");
1461 else if (OptSO4Clratio < 2.0)
1462 $('#wrt_so4_cl').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Licht bitter</span>");
1463 else if (OptSO4Clratio < 4.0)
1464 $('#wrt_so4_cl').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Bitter</span>");
1465 else if (OptSO4Clratio < 9.0)
1466 $('#wrt_so4_cl').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Zeer bitter</span>");
1467 else
1468 $('#wrt_so4_cl').html("<span style='vertical-align: top; font-size: 14px; font-style: italic;'>Te bitter</span>");
1469 if (chloride > 0)
1470 RA = sulfate / chloride;
1471 else
1472 RA = 10;
1473 $('#got_so4_cl').val(Round(RA, 1));
1474 Res = 'normaal';
1475 if (RA < (0.8 * OptSO4Clratio))
1476 Res = 'laag';
1477 else if (RA > (1.2 * OptSO4Clratio))
1478 Res = 'hoog';
1479 setRangeIndicator('so4_cl', Res);
1480
1481 $('#wb_calcium').val(Round(calcium, 1));
1482 $('#wb_magnesium').val(Round(magnesium, 1));
1483 $('#wb_sodium').val(Round(sodium, 1));
1484 $('#wb_sulfate').val(Round(sulfate, 1));
1485 $('#wb_chloride').val(Round(chloride, 1));
1486 $('#wb_bicarbonate').val(Round(bicarbonate, 1));
1487 $('#wb_total_alkalinity').val(Round(total_alkalinity, 1));
1488 $('#wb_hardness').val(Hardness(calcium, magnesium));
1489 $('#wb_ra').val(ResidualAlkalinity(total_alkalinity, calcium, magnesium));
1490
1491 if (calcium < 40) {
1492 setRangeIndicator('calcium', 'laag');
1493 } else if (calcium > 150) {
1494 setRangeIndicator('calcium', 'hoog');
1495 } else {
1496 setRangeIndicator('calcium', 'normaal');
1497 }
1498 if (magnesium < 5) {
1499 setRangeIndicator('magnesium', 'laag');
1500 } else if (magnesium > 40) {
1501 setRangeIndicator('magnesium', 'hoog');
1502 } else {
1503 setRangeIndicator('magnesium', 'normaal');
1504 }
1505 if (sodium <= 150) {
1506 setRangeIndicator('sodium', 'normaal');
1507 } else {
1508 setRangeIndicator('sodium', 'hoog');
1509 }
1510 // Both chloride and sulfate should be above 50 according to
1511 // John Palmer. So the Cl/SO4 ratio calculation will work.
1512 if (chloride <= 50) {
1513 setRangeIndicator('chloride', 'laag');
1514 } else if (chloride <= 150) {
1515 setRangeIndicator('chloride', 'normaal');
1516 } else {
1517 setRangeIndicator('chloride', 'hoog');
1518 }
1519 if (sulfate <= 50) {
1520 setRangeIndicator('sulfate', 'laag');
1521 } else if (sulfate <= 400) {
1522 setRangeIndicator('sulfate', 'normaal');
1523 } else {
1524 setRangeIndicator('sulfate', 'hoog');
1525 }
1526 // (cloride + sulfate) > 500 is too high
1527 if ((chloride + sulfate) > 500) {
1528 setRangeIndicator('chloride', 'hoog');
1529 setRangeIndicator('sulfate', 'hoog');
1530 }
1531 if (ph < 5.2) {
1532 setRangeIndicator('ph', 'laag');
1533 } else if (ph > 5.6) {
1534 setRangeIndicator('ph', 'hoog');
1535 } else {
1536 setRangeIndicator('ph', 'normaal');
1537 }
1538 if (bicarbonate > 250) {
1539 setRangeIndicator('bicarbonate', 'hoog');
1540 } else {
1541 setRangeIndicator('bicarbonate', 'normaal');
1542 }
1543 calcSparge();
1544 }
1545
1546
1547 function calcSparge() {
1548
1549 /* Based on the work of ajDeLange. */
1550 var ws_calcium, ws_magnesium, ws_total_alkalinity, ws_sodium, ws_chloride;
1551 var ws_sulfate, ws_ph, ws_hardness, ws_ra;
1552 var TargetpH = dataRecord.sparge_ph;
1553 var Source_pH = 7.0;
1554
1555 // Select watersource or fallback to the first source.
1556 if ((dataRecord.sparge_source == 1) && (dataRecord.w2_ph > 0.0)) { // Source 2
1557 ws_calcium = dataRecord.w2_calcium;
1558 ws_magnesium = dataRecord.w2_magnesium;
1559 ws_total_alkalinity = dataRecord.w2_total_alkalinity;
1560 ws_sodium = dataRecord.w2_sodium;
1561 ws_chloride = dataRecord.w2_chloride;
1562 ws_sulfate = dataRecord.w2_sulfate;
1563 Source_pH = dataRecord.w2_ph;
1564 $('#w2_button').jqxRadioButton({ checked: true });
1565 } else if ((dataRecord.sparge_source == 2) && (dataRecord.w2_ph > 0.0)) { // Mixed
1566 ws_calcium = dataRecord.wg_calcium;
1567 ws_magnesium = dataRecord.wg_magnesium;
1568 ws_total_alkalinity = dataRecord.wg_total_alkalinity;
1569 ws_sodium = dataRecord.wg_sodium;
1570 ws_chloride = dataRecord.wg_chloride;
1571 ws_sulfate = dataRecord.wg_sulfate;
1572 Source_pH = dataRecord.wg_ph;
1573 $('#wg_button').jqxRadioButton({ checked: true });
1574 } else {
1575 ws_calcium = dataRecord.w1_calcium;
1576 ws_magnesium = dataRecord.w1_magnesium;
1577 ws_total_alkalinity = dataRecord.w1_total_alkalinity;
1578 ws_sodium = dataRecord.w1_sodium;
1579 ws_chloride = dataRecord.w1_chloride;
1580 ws_sulfate = dataRecord.w1_sulfate;
1581 Source_pH = dataRecord.w1_ph;
1582 $('#w1_button').jqxRadioButton({ checked: true });
1583 }
1584
1585 if (dataRecord.sparge_volume > 0) {
1586 ws_calcium += (parseFloat($('#ss_cacl2').jqxNumberInput('decimal')) * MMCa / MMCaCl2 * 1000 +
1587 parseFloat($('#ss_caso4').jqxNumberInput('decimal')) * MMCa / MMCaSO4 * 1000) / dataRecord.sparge_volume;
1588 ws_magnesium += (parseFloat($('#ss_mgso4').jqxNumberInput('decimal')) * MMMg / MMMgSO4 * 1000 +
1589 parseFloat($('#ss_mgcl2').jqxNumberInput('decimal')) * MMMg / MMMgCl2 * 1000) / dataRecord.sparge_volume;
1590 ws_sodium += (parseFloat($('#ss_nacl').jqxNumberInput('decimal')) * MMNa / MMNaCl * 1000) / dataRecord.sparge_volume;
1591 ws_sulfate += (parseFloat($('#ss_caso4').jqxNumberInput('decimal')) * MMSO4 / MMCaSO4 * 1000 +
1592 parseFloat($('#ss_mgso4').jqxNumberInput('decimal')) * MMSO4 / MMMgSO4 * 1000) / dataRecord.sparge_volume;
1593 ws_chloride += (2 * parseFloat($('#ss_cacl2').jqxNumberInput('decimal')) * MMCl / MMCaCl2 * 1000 +
1594 parseFloat($('#ss_nacl').jqxNumberInput('decimal')) * MMCl / MMNaCl * 1000 +
1595 parseFloat($('#ss_mgcl2').jqxNumberInput('decimal')) * MMCl / MMMgCl2 * 1000) / dataRecord.sparge_volume;
1596 }
1597
1598 /* Show the spargewate with salt additions */
1599 $('#sw_calcium').val(Round(ws_calcium, 1));
1600 $('#sw_magnesium').val(Round(ws_magnesium, 1));
1601 $('#sw_sodium').val(Round(ws_sodium, 1));
1602 $('#sw_sulfate').val(Round(ws_sulfate, 1));
1603 $('#sw_chloride').val(Round(ws_chloride, 1));
1604 $('#sw_bicarbonate').val(Round(Bicarbonate(ws_total_alkalinity, Source_pH), 1));
1605 $('#sw_total_alkalinity').val(Round(ws_total_alkalinity, 1));
1606 $('#sw_ph').val(dataRecord.sparge_ph);
1607 $('#sw_hardness').val(Hardness(ws_calcium, ws_magnesium));
1608 $('#sw_ra').val(ResidualAlkalinity(ws_total_alkalinity, ws_calcium, ws_magnesium));
1609
1610 AT = dataRecord.sparge_acid_type;
1611 if (AT < 0 || AT >= AcidTypeData.length) {
1612 AT = 0;
1613 dataRecord.sparge_acid_type = 0;
1614 $('#sparge_acid_type').val(AcidTypeData[0].nl);
1615 dataRecord.sparge_acid_perc = AcidTypeData[0].AcidPrc;
1616 $('#sparge_acid_perc').val(dataRecord.sparge_acid_perc);
1617 }
1618
1619 /*
1620 * Auto calculate the required acid
1621 */
1622 if (dataRecord.calc_acid) {
1623 // Step 1: Compute the mole fractions of carbonic (f1o), bicarbonate (f2o) and carbonate(f3o) at the water pH
1624 var r1 = Math.pow(10, Source_pH - 6.35);
1625 var r2 = Math.pow(10, Source_pH - 10.33);
1626 var d = 1 + r1 + r1 * r2;
1627 var f1 = 1 / d;
1628 var f3 = r1 * r2 / d;
1629
1630 //Step 2. Compute the mole fractions at pH = 4.3 (the pH which defines alkalinity)
1631 var r143 = Math.pow(10, 4.3 - 6.35);
1632 var r243 = Math.pow(10, 4.3 - 10.33);
1633 var d43 = 1 + r143 + r143 * r243;
1634 var f143 = 1 / d43;
1635 var f343 = r143 * r243 / d43;
1636
1637 //Step 4. Solve
1638 var Ct = ws_total_alkalinity / 50 / ((f143 - f1) + (f3 - f343));
1639
1640 //Step 5. Compute mole fractions at desired pH
1641 var r1g = Math.pow(10, TargetpH - 6.35);
1642 var r2g = Math.pow(10, TargetpH - 10.33);
1643 var dg = 1 + r1g + r1g * r2g;
1644 var f1g = 1 / dg;
1645 var f3g = r1g * r2g / dg;
1646
1647 //Step 6. Use these to compute the milliequivalents acid required per liter (mEq/L)
1648 var Acid = Ct * ((f1g - f1) + (f3 - f3g)) + Math.pow(10, -TargetpH) - Math.pow(10, -Source_pH); //mEq/l
1649 Acid += 0.01; // Add acid that would be required for distilled water.
1650
1651 //Step 8. Get the acid data.
1652 var fract = CalcFrac(TargetpH, AcidTypeData[AT].pK1, AcidTypeData[AT].pK2, AcidTypeData[AT].pK3);
1653
1654 //Step 9. Now divide the mEq required by the "fraction". This is the required number of moles of acid.
1655 Acid /= fract;
1656
1657 //Step 10. Multiply by molecular weight of the acid
1658 Acid *= AcidTypeData[AT].MolWt; //mg
1659
1660 //Step 11. Divide by Specific Gravity and Percentage to get the final ml.
1661 var RealSG = Round(((AcidTypeData[AT].AcidSG - 1000) * (dataRecord.sparge_acid_perc / 100)) + 1000, 2);
1662 Acid = Acid / RealSG; //ml
1663 Acid *= dataRecord.sparge_volume; //ml acid total at 100%
1664 Acid /= AcidTypeData[AT].AcidPrc / 100; //ml acid at supplied strength
1665 Acid = Round(Acid, 2);
1666 dataRecord.sparge_acid_amount = Acid / 1000;
1667 $('#sparge_acid_amount').val(Acid);
1668 }
1669
1670 // Finally calculate the estimate preboil pH
1671 var ph = -Math.log10(((Math.pow(10, -dataRecord.wb_ph) * dataRecord.wg_amount) + (Math.pow(10, -dataRecord.sparge_ph) * dataRecord.sparge_volume)) /
1672 (dataRecord.wg_amount + dataRecord.sparge_volume));
1673 $('#preboil_ph').val(ph);
1674 }
1675
1676 function calcInit() {
1677 console.log('calc.init()');
1678
1679 calcWater();
1680 $('#w1_name').jqxDropDownList('selectItem', dataRecord.w1_name);
1681 $('#w2_name').jqxDropDownList('selectItem', dataRecord.w2_name);
1682 // Fix tap water if zero using mash infuse amount.
1683 if (parseFloat($('#w1_amount').jqxNumberInput('decimal')) == 0 && mash_infuse > 0) {
1684 $('#w1_amount').val(mash_infuse);
1685 dataRecord.w1_amount = mash_infuse;
1686 $('#wg_amount').val(mash_infuse);
1687 $('#w2_amount').val(0);
1688 dataRecord.w2_amount = 0;
1689 }
1690 calcWater();
1691
1692 };
1693
1694 function saveRecord(goback) {
1695 window.location.href = my_return;
1696 };
1697
1698 dataAdapter.dataBind();
1699
1700 // initialize the input fields.
1701 // Tab 1, Algemeen
1702 $('#name').jqxTooltip({ content: 'De naam voor dit recept.' });
1703 $('#name').jqxInput({ theme: theme, width: 640, height: 23 });
1704 $('#notes').jqxTooltip({ content: 'De uitgebreide opmerkingen over dit recept.' });
1705 $('#notes').jqxInput({ theme: theme, width: 960, height: 200 });
1706 $('#type').jqxTooltip({ content: 'Het brouw type van dit recept.' });
1707 $('#type').jqxInput({ theme: theme, width: 180, height: 23 });
1708 $('#efficiency').jqxTooltip({ content: 'Het rendement van maischen en koken.' });
1709 $('#efficiency').jqxNumberInput(Show1dec);
1710 $('#batch_size').jqxTooltip({ content: 'Het volume van het gekoelde wort na het koken.' });
1711 $('#batch_size').jqxNumberInput(Show1dec);
1712 $('#batch_size').jqxNumberInput({ min: 4 });
1713 $('#boil_size').jqxTooltip({ content: 'Het volume van het wort voor het koken.' });
1714 $('#boil_size').jqxNumberInput({ inputMode: 'simple', theme: theme, width: 90, height: 23, decimalDigits: 2, readOnly: true });
1715 $('#boil_time').jqxTooltip({ content: 'De kooktijd in minuten.' });
1716 $('#boil_time').jqxNumberInput(Show0dec);
1717 $('#boil_time').jqxNumberInput({ min: 4, max: 360 });
1718
1719 $('#st_name').jqxTooltip({ content: 'De bierstijl naam voor dit recept.'});
1720 $('#st_name').jqxInput({ theme: theme, width: 250, height: 23 });
1721 $('#st_letter').jqxTooltip({ content: 'De bierstijl letter voor dit recept.'});
1722 $('#st_letter').jqxInput({ theme: theme, width: 90, height: 23 });
1723 $('#st_guide').jqxTooltip({ content: 'De bierstijl gids voor dit recept.'});
1724 $('#st_guide').jqxInput({ theme: theme, width: 250, height: 23 });
1725 $('#st_category').jqxTooltip({ content: 'De Amerikaanse bierstijl categorie.'});
1726 $('#st_category').jqxInput({ theme: theme, width: 250, height: 23 });
1727 $('#st_category_number').jqxTooltip({ content: 'De Amerikaanse bierstijl categorie sub nummer.'});
1728 $('#st_category_number').jqxNumberInput(Smal0dec);
1729 $('#st_type').jqxTooltip({ content: 'Het bierstijl type.'});
1730 $('#st_type').jqxInput({ theme: theme, width: 250, height: 23 });
1731
1732 $('#est_og').jqxTooltip({ content: 'Het begin SG wat je wilt bereiken. De moutstort wordt automatisch herberekend.' });
1733 $('#est_og').jqxNumberInput(Show3dec);
1734 $('#st_og_min').jqxTooltip({ content: 'Het minimum begin SG voor deze bierstijl.'});
1735 $('#st_og_min').jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 3, readOnly: true });
1736 $('#st_og_max').jqxTooltip({ content: 'Het maximum begin SG voor deze bierstijl.'});
1737 $('#st_og_max').jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 3, readOnly: true });
1738
1739 $('#est_fg').jqxTooltip({ content: 'Het eind SG. Dit wordt automatisch berekend.' });
1740 $('#est_fg').jqxNumberInput(Show3dec);
1741 $('#st_fg_min').jqxTooltip({ content: 'Het minimum eind SG voor deze bierstijl.'});
1742 $('#st_fg_min').jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 3, readOnly: true });
1743 $('#st_fg_max').jqxTooltip({ content: 'Het maximum eind SG voor deze bierstijl.'});
1744 $('#st_fg_max').jqxNumberInput({ inputMode: 'simple', theme: theme, width: 50, height: 23, decimalDigits: 3, readOnly: true });
1745
1746 $('#est_abv').jqxTooltip({ content: 'Alcohol volume %. Dit wordt automatisch berekend.' });
1747 $('#est_abv').jqxNumberInput(Smal1dec);
1748 $('#st_abv_min').jqxTooltip({ content: 'Het minimum alcohol volume % voor deze bierstijl.'});
1749 $('#st_abv_min').jqxNumberInput(Smal1dec);
1750 $('#st_abv_max').jqxTooltip({ content: 'Het maximum alcohol volume % voor deze bierstijl.'});
1751 $('#st_abv_max').jqxNumberInput(Smal1dec);
1752
1753 $('#est_color').jqxTooltip({ content: 'De kleur in EBC. Dit wordt automatisch berekend.' });
1754 $('#est_color').jqxNumberInput(Show0dec);
1755 $('#st_color_min').jqxTooltip({ content: 'De minimum kleur voor deze bierstijl.'});
1756 $('#st_color_min').jqxNumberInput(Smal0dec);
1757 $('#st_color_max').jqxTooltip({ content: 'De maximum kleur voor deze bierstijl.'});
1758 $('#st_color_max').jqxNumberInput(Smal0dec);
1759 $('#color_method').jqxInput({ theme: theme, width: 180, height: 23 });
1760 $('#est_ibu').jqxTooltip({ content: 'De bitterheid in IBU. Dit wordt automatisch berekend.' });
1761 $('#est_ibu').jqxNumberInput(Show0dec);
1762 $('#st_ibu_min').jqxTooltip({ content: 'De minimum bitterheid voor deze bierstijl.'});
1763 $('#st_ibu_min').jqxNumberInput(Smal0dec);
1764 $('#st_ibu_max').jqxTooltip({ content: 'De maximum bitterheid voor deze bierstijl.'});
1765 $('#st_ibu_max').jqxNumberInput(Smal0dec);
1766
1767 $('#ibu_method').jqxInput({ theme: theme, width: 180, height: 23 });
1768 $('#kcal').jqxTooltip({ content: 'Energie-inhoud in kcal/liter.' });
1769 $('#kcal').jqxNumberInput(Smal0dec);
1770 $('#est_carb').jqxTooltip({ content: 'Koolzuur volume. Dit wordt automatisch berekend.' });
1771 $('#est_carb').jqxNumberInput(Smal1dec);
1772 $('#st_carb_min').jqxTooltip({ content: 'Het minimum koolzuur volume voor deze bierstijl.'});
1773 $('#st_carb_min').jqxNumberInput(Smal1dec);
1774 $('#st_carb_max').jqxTooltip({ content: 'Het maximum koolzuur volume voor deze bierstijl.'});
1775 $('#st_carb_max').jqxNumberInput(Smal1dec);
1776
1777 // Tab 2, Vergistbaar
1778 $('#est_color2').jqxTooltip({ content: 'De kleur in EBC. Dit wordt automatisch berekend.' });
1779 $('#est_color2').jqxNumberInput(Show0dec);
1780 $('#est_og2').jqxTooltip({ content: 'Het begin SG wat je wilt bereiken. De moutstort wordt automatisch herberekend.' });
1781 $('#est_og2').jqxNumberInput(Show3dec);
1782 $('#perc_malts').jqxProgressBar({
1783 width: 300,
1784 height: 23,
1785 theme: theme,
1786 showText: true,
1787 max: 120,
1788 animationDuration: 0,
1789 colorRanges: [
1790 { stop: 90, color: '#008C00' },
1791 { stop: 100, color: '#EB7331' },
1792 { stop: 120, color: '#FF0000' }
1793 ],
1794 renderText: function(text) {
1795 return (Math.round(parseInt(text) * 1.2)) + '%';
1796 }
1797 });
1798 $('#perc_sugars').jqxProgressBar({
1799 width: 300,
1800 height: 23,
1801 theme: theme,
1802 showText: true,
1803 max: 50,
1804 animationDuration: 0,
1805 colorRanges: [
1806 { stop: 20, color: '#008C00' },
1807 { stop: 50, color: '#FF0000' }
1808 ],
1809 renderText: function(text) {
1810 return (Math.round(parseInt(text) * 5) / 10) + '%';
1811 }
1812 });
1813 $('#perc_cara').jqxProgressBar({
1814 width: 300,
1815 height: 23,
1816 theme: theme,
1817 showText: true,
1818 max: 50,
1819 animationDuration: 0,
1820 colorRanges: [
1821 { stop: 25, color: '#008C00' },
1822 { stop: 50, color: '#FF0000' }
1823 ],
1824 renderText: function(text) {
1825 return (Math.round(parseInt(text) * 5) / 10) + '%';
1826 }
1827 });
1828 $('#ferm_lintner').jqxProgressBar({
1829 width: 300,
1830 height: 23,
1831 theme: theme,
1832 showText: true,
1833 max: 200,
1834 animationDuration: 0,
1835 colorRanges: [
1836 { stop: 30, color: '#FF0000' },
1837 { stop: 40, color: '#EB7331' },
1838 { stop: 200, color: '#008C00' }
1839 ],
1840 renderText: function(text) {
1841 return (parseInt(text) * 2) + ' lintner';
1842 }
1843 });
1844
1845 // Tab 3, Hoppen
1846 $('#est_ibu2').jqxTooltip({ content: 'De bitterheid in IBU. Dit wordt automatisch berekend.' });
1847 $('#est_ibu2').jqxNumberInput(Smal0dec);
1848 $('#hop_flavour').jqxProgressBar({
1849 width: 300,
1850 height: 23,
1851 theme: theme,
1852 showText: true,
1853 animationDuration: 0,
1854 colorRanges: [
1855 { stop: 20, color: '#004D00' },
1856 { stop: 40, color: '#008C00' },
1857 { stop: 60, color: '#00BF00' },
1858 { stop: 80, color: '#00FF00' },
1859 { stop: 100, color: '#80FF80' }
1860 ],
1861 renderText: function(text) {
1862 var val = parseInt(text);
1863 if (val < 20)
1864 return 'Weinig';
1865 else if (val < 40)
1866 return 'Matig';
1867 else if (val < 60)
1868 return 'Redelijk';
1869 else if (val < 80)
1870 return 'Veel';
1871 else
1872 return 'Zeer veel';
1873 }
1874 });
1875 $('#hop_aroma').jqxProgressBar({
1876 width: 300,
1877 height: 23,
1878 theme: theme,
1879 showText: true,
1880 animationDuration: 0,
1881 colorRanges: [
1882 { stop: 20, color: '#004D00' },
1883 { stop: 40, color: '#008C00' },
1884 { stop: 60, color: '#00BF00' },
1885 { stop: 80, color: '#00FF00' },
1886 { stop: 100, color: '#80FF80' }
1887 ],
1888 renderText: function(text) {
1889 var val = parseInt(text);
1890 if (val < 20)
1891 return 'Weinig';
1892 else if (val < 40)
1893 return 'Matig';
1894 else if (val < 60)
1895 return 'Redelijk';
1896 else if (val < 80)
1897 return 'Veel';
1898 else
1899 return 'Zeer veel';
1900 }
1901 });
1902
1903 // Tab 4, Diversen
1904
1905 // Tab 5, Gist
1906 $('#est_fg2').jqxTooltip({ content: 'Het eind SG. Dit wordt automatisch berekend.' });
1907 $('#est_fg2').jqxNumberInput(Show3dec);
1908 $('#est_abv2').jqxTooltip({ content: 'Alcohol volume %. Dit wordt automatisch berekend.' });
1909 $('#est_abv2').jqxNumberInput(Smal1dec);
1910
1911 // Tab 6, Maischen
1912 $('#mash_name').jqxInput({ theme: theme, width: 320, height: 23 });
1913
1914 // Tab 7, Water
1915 $('#tgt_bu').jqxNumberInput(Show2wat);
1916 $('#tgt_so4_cl,#got_so4_cl').jqxNumberInput(Show1wat);
1917 $('#preboil_ph').jqxNumberInput(Show2wat);
1918
1919 // Water source 1
1920 $('#w1_name').jqxInput({ theme: theme, width: 200, height: 23 });
1921 $('#w1_button').jqxRadioButton({ theme: theme, width: 50, height: 23, disabled: true });
1922 $('#w1_amount').jqxNumberInput(Show1wat);
1923 $('#w1_calcium').jqxNumberInput(Show1wat);
1924 $('#w1_magnesium').jqxNumberInput(Show1wat);
1925 $('#w1_sodium').jqxNumberInput(Show1wat);
1926 $('#w1_bicarbonate').jqxNumberInput(Show1wat);
1927 $('#w1_total_alkalinity').jqxNumberInput(Show1wat);
1928 $('#w1_chloride').jqxNumberInput(Show1wat);
1929 $('#w1_sulfate').jqxNumberInput(Show1wat);
1930 $('#w1_ph').jqxNumberInput(Show2wat);
1931 $('#w1_hardness').jqxNumberInput(Show1wat);
1932 $('#w1_ra').jqxNumberInput(Show1wat);
1933 // Water source 2
1934 $('#w2_name').jqxInput({ theme: theme, width: 200, height: 23 });
1935 $('#w2_button').jqxRadioButton({ theme: theme, width: 50, height: 23, disabled: true });
1936 $('#w2_amount').jqxNumberInput(Show1wat);
1937 $('#w2_calcium').jqxNumberInput(Show1wat);
1938 $('#w2_magnesium').jqxNumberInput(Show1wat);
1939 $('#w2_sodium').jqxNumberInput(Show1wat);
1940 $('#w2_bicarbonate').jqxNumberInput(Show1wat);
1941 $('#w2_total_alkalinity').jqxNumberInput(Show1wat);
1942 $('#w2_chloride').jqxNumberInput(Show1wat);
1943 $('#w2_sulfate').jqxNumberInput(Show1wat);
1944 $('#w2_ph').jqxNumberInput(Show2wat);
1945 $('#w2_hardness').jqxNumberInput(Show1wat);
1946 $('#w2_ra').jqxNumberInput(Show1wat);
1947 // Water mixed
1948 $('#wg_button').jqxRadioButton({ theme: theme, width: 50, height: 23, disabled: true });
1949 $('#wg_amount').jqxNumberInput(Show1wat);
1950 $('#wg_calcium').jqxNumberInput(Show1wat);
1951 $('#wg_magnesium').jqxNumberInput(Show1wat);
1952 $('#wg_sodium').jqxNumberInput(Show1wat);
1953 $('#wg_bicarbonate').jqxNumberInput(Show1wat);
1954 $('#wg_total_alkalinity').jqxNumberInput(Show1wat);
1955 $('#wg_chloride').jqxNumberInput(Show1wat);
1956 $('#wg_sulfate').jqxNumberInput(Show1wat);
1957 $('#wg_ph').jqxNumberInput(Show2wat);
1958 $('#wg_hardness').jqxNumberInput(Show1wat);
1959 $('#wg_ra').jqxNumberInput(Show1wat);
1960 // Water treated
1961 $('#wb_calcium').jqxTooltip({ content: 'De ideale hoeveelheid Calcium is tussen 40 en 150.'});
1962 $('#wb_calcium').jqxNumberInput(Show1wat);
1963 $('#wb_magnesium').jqxTooltip({ content: 'De ideale hoeveelheid Magnesium is tussen 5 en 40.'});
1964 $('#wb_magnesium').jqxNumberInput(Show1wat);
1965 $('#wb_sodium').jqxTooltip({ content: 'De ideale hoeveelheid Natrium is lager dan 150.'});
1966 $('#wb_sodium').jqxNumberInput(Show1wat);
1967 $('#wb_chloride').jqxTooltip({ content: 'De ideale hoeveelheid Chloride is tussen 50 en 150. Samen met Sulfaat minder dan 500.'});
1968 $('#wb_chloride').jqxNumberInput(Show1wat);
1969 $('#wb_sulfate').jqxTooltip({ content: 'De ideale hoeveelheid Sulfaat is tussen 50 en 400. Samen met Sulfaat minder dan 500.'});
1970 $('#wb_sulfate').jqxNumberInput(Show1wat);
1971 $('#wb_bicarbonate').jqxTooltip({ content: '0 tot 50 lichte bieren, 50 tot 150 amber bieren, 150 tot 250 donkere bieren.'});
1972 $('#wb_bicarbonate').jqxNumberInput(Show1wat);
1973 $('#wb_total_alkalinity').jqxNumberInput(Show1wat);
1974 $('#wb_ph').jqxNumberInput(Show2wat);
1975 $('#wb_hardness').jqxNumberInput(Show1wat);
1976 $('#wb_ra').jqxNumberInput(Show1wat);
1977 // Sparge water
1978 $('#sw_amount').jqxNumberInput(Show1wat);
1979 $('#sw_calcium').jqxNumberInput(Show1wat);
1980 $('#sw_magnesium').jqxNumberInput(Show1wat);
1981 $('#sw_sodium').jqxNumberInput(Show1wat);
1982 $('#sw_bicarbonate').jqxNumberInput(Show1wat);
1983 $('#sw_total_alkalinity').jqxNumberInput(Show1wat);
1984 $('#sw_chloride').jqxNumberInput(Show1wat);
1985 $('#sw_sulfate').jqxNumberInput(Show1wat);
1986 $('#sw_ph').jqxNumberInput(Show2wat);
1987 $('#sw_hardness').jqxNumberInput(Show1wat);
1988 $('#sw_ra').jqxNumberInput(Show1wat);
1989
1990 // Water agents
1991 $('#wa_cacl2').jqxTooltip({ content: 'Voor het maken van een ander waterprofiel. Voegt calcium en chloride toe. Voor het verbeteren van zoetere bieren.'});
1992 $('#wa_cacl2').jqxNumberInput(Show2wat);
1993 $('#ss_cacl2').jqxNumberInput(Show2wat);
1994
1995 $('#wa_caso4').jqxTooltip({
1996 content: 'Gips. Voor het maken van een ander waterprofiel. Voegt calcium en sulfaat toe. Voor het verbeteren van bittere bieren.'
1997 });
1998 $('#wa_caso4').jqxNumberInput(Show2wat);
1999 $('#ss_caso4').jqxNumberInput(Show2wat);
2000
2001 $('#wa_mgso4').jqxTooltip({ content: 'Epsom zout. Voor het maken van een ander waterprofiel. Voegt magnesium en sulfaat toe. Gebruik spaarzaam!'});
2002 $('#wa_mgso4').jqxNumberInput(Show2wat);
2003 $('#ss_mgso4').jqxNumberInput(Show2wat);
2004
2005 $('#wa_nacl').jqxTooltip({
2006 content: 'Keukenzout. Voor het maken van een ander waterprofiel. Voegt natrium en chloride toe. ' +
2007 'Voor het accentueren van zoetheid. Bij hoge dosering wordt het bier ziltig.'
2008 });
2009 $('#wa_nacl').jqxNumberInput(Show2wat);
2010 $('#ss_nacl').jqxNumberInput(Show2wat);
2011
2012 $('#wa_mgcl2').jqxTooltip({ content: 'Magnesiumchloride'});
2013 $('#wa_mgcl2').jqxNumberInput(Show2wat);
2014 $('#ss_mgcl2').jqxNumberInput(Show2wat);
2015
2016 $('#wa_nahco3').jqxTooltip({ content: 'Baksoda'});
2017 $('#wa_caco3').jqxTooltip({ content: 'Kalk'});
2018 $('#wa_nahco3,#wa_caco3').jqxNumberInput(Show2wat);
2019
2020 $('#mash_ph').jqxTooltip({ content: 'Maisch pH tussen 5.2 en 5.6. Gebruik 5.2 voor lichte en 5.5 voor donkere bieren.'});
2021 $('#mash_ph').jqxNumberInput(Show2dec);
2022
2023 $('#calc_acid').jqxCheckBox({ theme: theme, width: 120, height: 23, disabled: true });
2024
2025 $('#wa_acid_name').jqxInput({ theme: theme, width: 130, height: 23 });
2026 $('#wa_acid').jqxNumberInput(Show2dec);
2027 $('#wa_acid').jqxNumberInput({ symbol: ' ml', symbolPosition: 'right' });
2028 $('#wa_acid_perc').jqxNumberInput(Show0dec);
2029 $('#wa_acid_perc').jqxNumberInput({ symbol: '%', symbolPosition: 'right' });
2030
2031 // Sparge water
2032 $('#sparge_ph').jqxNumberInput(Show2dec);
2033 $('#sparge_acid_amount').jqxNumberInput(Show2dec);
2034 $('#sparge_acid_amount').jqxNumberInput({ symbol: ' ml', symbolPosition: 'right' });
2035 $('#sparge_acid_type').jqxInput({ theme: theme, width: 130, height: 23 });
2036 $('#sparge_acid_perc').jqxNumberInput(Show0dec);
2037 $('#sparge_acid_perc').jqxNumberInput({ symbol: '%', symbolPosition: 'right' });
2038
2039 // Tabs inside the popup window.
2040 $('#jqxTabs').jqxTabs({
2041 theme: theme,
2042 width: 1280,
2043 height: 660,
2044 autoHeight: false,
2045 position: 'top'
2046 });
2047
2048 // Button below
2049 $('#Terug').jqxButton({ template: 'primary', width: '80px', theme: theme });
2050 $('#Terug').bind('click', function() {
2051 window.location.href = my_return;
2052 });
2053
2054 });
2055

mercurial