Added console logging in the grid write callback functions. Removed grid sorting, it is done on the server side. Alert popup for block row edit functions. Better grid live updates. In recipe and product print show the whirlpool time. The checklist now shows misc ingredients added in the mash. Show hops added in the whirlpool. Most ingredient names are now quoted.

Tue, 04 Jun 2019 19:50:06 +0200

author
Michiel Broek <mbroek@mbse.eu>
date
Tue, 04 Jun 2019 19:50:06 +0200
changeset 396
804800d8e885
parent 395
463d64cce768
child 397
d3d2b277075b

Added console logging in the grid write callback functions. Removed grid sorting, it is done on the server side. Alert popup for block row edit functions. Better grid live updates. In recipe and product print show the whirlpool time. The checklist now shows misc ingredients added in the mash. Show hops added in the whirlpool. Most ingredient names are now quoted.

www/js/prod_edit.js file | annotate | diff | comparison | revisions
www/js/rec_edit.js file | annotate | diff | comparison | revisions
www/prod_print.php file | annotate | diff | comparison | revisions
www/rec_print.php file | annotate | diff | comparison | revisions
--- a/www/js/prod_edit.js	Tue Jun 04 16:38:53 2019 +0200
+++ b/www/js/prod_edit.js	Tue Jun 04 19:50:06 2019 +0200
@@ -3190,11 +3190,17 @@
 				{ name: 'f_avail', type: 'int' }
                         ],
                         addrow: function (rowid, rowdata, position, commit) {
+				console.log("fermentable addrow "+rowid);
                                 commit(true);
                         },
                         deleterow: function (rowid, commit) {
+				console.log("fermentable deleterow "+rowid);
                                 commit(true);
-                        }
+                        },
+			updaterow: function (rowid, rowdata, commit) {
+				console.log("fermentable updaterow "+rowid);
+				commit(true);
+			}
                 };
                 var fermentableAdapter = new $.jqx.dataAdapter(fermentableSource);
                 $("#fermentableGrid").jqxGrid({
@@ -3202,7 +3208,6 @@
                         height: 470,
                         source: fermentableAdapter,
                         theme: theme,
-                	sortmode: "many",
                         selectionmode: 'singlerow',
                         showtoolbar: true,
                         rendertoolbar: function (toolbar) {
@@ -3322,11 +3327,6 @@
                                 });
                         },
                         ready: function() {
-				var datainformation = $('#fermentableGrid').jqxGrid('getdatainformation');
-                                if (datainformation.rowscount) {
-					$("#fermentableGrid").jqxGrid('sortby', 'f_added', 'asc');
-					$("#fermentableGrid").jqxGrid('sortby', 'f_amount', 'desc');
-				}
 				calcFermentables();
                                 $('#jqxTabs').jqxTabs('next');
                         },
@@ -3379,7 +3379,9 @@
 				{ text: '', datafield: 'Edit', columntype: 'button', width: 100, align: 'center', cellsrenderer: function () {
 					return "Wijzig";
 					}, buttonclick: function (row) {
-						if (dataRecord.stage <= 3) {
+						if (dataRecord.stage > 3) {
+							alert("Ingredieënt is al verwerkt.");
+						} else {
 							fermentableRow = row;
 							fermentableData = $("#fermentableGrid").jqxGrid('getrowdata', fermentableRow);
 							$("#wf_name").val(fermentableData.f_name);
@@ -3425,11 +3427,17 @@
 				{ name: 'h_avail', type: 'int' }
                         ],
                         addrow: function (rowid, rowdata, position, commit) {
-                                commit(true);
-                        },
+				console.log("hop addrow "+rowid);
+				commit(true);
+			},
                         deleterow: function (rowid, commit) {
-                                commit(true);
-                        }
+				console.log("hop deleterow "+rowid);
+				commit(true);
+			},
+			updaterow: function (rowid, rowdata, commit) {
+				console.log("hop updaterow "+rowid);
+				commit(true);
+			}
                 };
                 var hopAdapter = new $.jqx.dataAdapter(hopSource);
                 $("#hopGrid").jqxGrid({
@@ -3437,7 +3445,6 @@
                         height: 560,
                         source: hopAdapter,
                         theme: theme,
-			sortmode: "many",
                         selectionmode: 'singlerow',
                         showtoolbar: true,
                         rendertoolbar: function (toolbar) {
@@ -3512,12 +3519,6 @@
                                 });
                         },
                         ready: function() {
-				var datainformation = $('#hopGrid').jqxGrid('getdatainformation');
-                                if (datainformation.rowscount) {
-					$("#hopGrid").jqxGrid('sortby', 'h_useat', 'asc');
-					$("#hopGrid").jqxGrid('sortby', 'h_time', 'desc');
-					$("#hopGrid").jqxGrid('sortby', 'h_amount', 'desc');
-				}
 				calcIBUs();
                                 $('#jqxTabs').jqxTabs('next');
                         },
@@ -3588,7 +3589,10 @@
 				{ text: '', datafield: 'Edit', columntype: 'button', width: 100, align: 'center', cellsrenderer: function () {
 					return "Wijzig";
 					}, buttonclick: function (row) {
-						if (dataRecord.stage <= 3) {
+						if (dataRecord.stage > 3) {
+                                                        alert("Ingredieënt is al verwerkt.");
+                                                } else {
+							console.log("edit button row "+row);
 							hopRow = row;
 							hopData = $("#hopGrid").jqxGrid('getrowdata', hopRow);
 							$("#wh_name").val(hopData.h_name);
@@ -3632,11 +3636,17 @@
 				{ name: 'm_avail', type: 'int' }
                         ],
                         addrow: function (rowid, rowdata, position, commit) {
+				console.log("misc addrow "+rowid);
                                 commit(true);
                         },
                         deleterow: function (rowid, commit) {
+				console.log("misc deleterow "+rowid);
                                 commit(true);
-                        }
+                        },
+			updaterow: function (rowid, rowdata, commit) {
+				console.log("misc updaterow "+rowid);
+				commit(true);
+			}
                 };
                 var miscAdapter = new $.jqx.dataAdapter(miscSource, {
                         beforeLoadComplete: function (records) {
@@ -3703,7 +3713,6 @@
                         height: 575,
                         source: miscAdapter,
                         theme: theme,
-			sortmode: "many",
                         selectionmode: 'singlerow',
                         showtoolbar: true,
                         rendertoolbar: function (toolbar) {
@@ -3761,11 +3770,6 @@
                                 });
                         },
                         ready: function() {
-				var datainformation = $('#miscGrid').jqxGrid('getdatainformation');
-                                if (datainformation.rowscount) {
-					$("#miscGrid").jqxGrid('sortby', 'm_use_use', 'asc');
-					$("#miscGrid").jqxGrid('sortby', 'm_type', 'asc');
-				}
 				calcMiscs();
                                 $('#jqxTabs').jqxTabs('next');
                         },
@@ -3818,9 +3822,14 @@
 				{ text: '', datafield: 'Edit', columntype: 'button', width: 100, align: 'center', cellsrenderer: function () {
 					return "Wijzig";
 					}, buttonclick: function (row) {
-						if (dataRecord.stage <= 3) {
-							miscRow = row;
-							miscData = $("#miscGrid").jqxGrid('getrowdata', miscRow);
+						miscRow = row;
+						miscData = $("#miscGrid").jqxGrid('getrowdata', miscRow);
+						if (dataRecord.stage > 3) {
+							alert("Ingredieënt is al verwerkt.");
+						} else if (miscData.m_type == 4) {
+							alert("Brouwzouten wijzigen in de water tab.");
+						} else {
+							console.log("edit button row "+row);
 							if (miscData.m_amount_is_weight)
 								$("#wm_pmpt_amount").html("Gewicht gram:");
 							else
@@ -3833,8 +3842,7 @@
 								$("#wm_time").val(miscData.m_time);
 							$("#wm_use_use").val(miscData.m_use_use);
 							// show the popup window.
-							if (miscData.m_type != 4)
-								$("#popupMisc").jqxWindow('open');
+							$("#popupMisc").jqxWindow('open');
 						}
 					}
 				}
@@ -3868,11 +3876,17 @@
 				{ name: 'y_avail', type: 'int' }
                         ],
                         addrow: function (rowid, rowdata, position, commit) {
+				console.log("yeast addrow "+rowid);
                                 commit(true);
                         },
                         deleterow: function (rowid, commit) {
+				console.log("yeast deleterow "+rowid);
                                 commit(true);
-                        }
+                        },
+			updaterow: function (rowid, rowdata, commit) {
+				console.log("yeast updaterow "+rowid);
+				commit(true);
+			}
                 };
                 var yeastAdapter = new $.jqx.dataAdapter(yeastSource);
                 $("#yeastGrid").jqxGrid({
@@ -3880,7 +3894,6 @@
                         height: 350,
                         source: yeastAdapter,
                         theme: theme,
-			sortmode: "many",
                         selectionmode: 'singlerow',
                         showtoolbar: true,
                         rendertoolbar: function (toolbar) {
@@ -3951,10 +3964,6 @@
                                 });
                         },
                         ready: function() {
-				var datainformation = $('#yeastGrid').jqxGrid('getdatainformation');
-                                if (datainformation.rowscount) {
-					$("#yeastGrid").jqxGrid('sortby', 'y_use', 'asc');
-				}
 				calcFermentables();
 				showStarter();
 				calcYeast();
@@ -4022,7 +4031,9 @@
 				{ text: '', datafield: 'Edit', columntype: 'button', width: 90, align: 'center', cellsrenderer: function () {
 					return "Wijzig";
 					}, buttonclick: function (row) {
-						if (dataRecord.stage <= 3) {
+						if (dataRecord.stage > 3) {
+                                                        alert("Ingredieënt is al verwerkt.");
+                                                } else {
 							yeastRow = row;
 							yeastData = $("#yeastGrid").jqxGrid('getrowdata', yeastRow);
 							if (yeastData.y_form == 0) {
@@ -4152,7 +4163,9 @@
 				{ text: '', datafield: 'Edit', columntype: 'button', width: 100, align: 'center', cellsrenderer: function () {
 					return "Wijzig";
 					}, buttonclick: function (row) {
-						if (dataRecord.stage <= 3) {
+						if (dataRecord.stage > 3) {
+                                                        alert("Het maichen is al gedaan.");
+                                                } else {
 							mashRow = row;
 							mashData = $("#mashGrid").jqxGrid('getrowdata', mashRow);
 							$("#wstep_name").val(mashData.step_name);
@@ -4418,6 +4431,35 @@
 	});
 	$("#FermentableReady").jqxButton({ template: "success", width: '90px', theme: theme });
 	$("#FermentableReady").click(function () {
+		var rowID = $("#fermentableGrid").jqxGrid('getrowid', fermentableRow);
+		console.log("FermentableReady row:"+fermentableRow+" ID:"+rowID);
+		var row = {
+			f_name: fermentableData.f_name,
+			f_origin: fermentableData.f_origin,
+			f_supplier: fermentableData.f_supplier,
+			f_amount: fermentableData.f_amount,
+			f_cost: fermentableData.f_cost,
+			f_type: fermentableData.f_type,
+			f_yield: fermentableData.f_yield,
+			f_color: fermentableData.f_color,
+			f_coarse_fine_diff: fermentableData.f_coarse_fine_diff,
+			f_moisture: fermentableData.f_moisture,
+			f_diastatic_power: fermentableData.f_diastatic_power,
+			f_protein: fermentableData.f_protein,
+			f_max_in_batch: fermentableData.f_max_in_batch,
+			f_graintype: fermentableData.f_graintype,
+			f_added: fermentableData.f_added,
+			f_dissolved_protein: fermentableData.f_dissolved_protein,
+			f_recommend_mash: fermentableData.f_recommend_mash,
+			f_add_after_boil: fermentableData.f_add_after_boil,
+			f_adjust_to_total_100: fermentableData.f_adjust_to_total_100,
+			f_percentage: fermentableData.f_percentage,
+			f_di_ph: fermentableData.f_di_ph,
+			f_acid_to_ph_57: fermentableData.f_acid_to_ph_57,
+			f_inventory: fermentableData.f_inventory,
+			f_avail: fermentableData.f_avail
+		};
+		$("#fermentableGrid").jqxGrid('updaterow', rowID, row);
 		// Recalc percentages
 		calcFermentables();
 		calcIBUs();
@@ -4448,33 +4490,33 @@
 		if (event.args) {
 			var index = event.args.index;
 			var datarecord = fermentablelist.records[index];
-			var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', fermentableRow);
 			$("#wf_name").val(datarecord.name);
-			rowdata.f_name = datarecord.name;
-			rowdata.f_origin = datarecord.origin;
-			rowdata.f_supplier = datarecord.supplier;
-			rowdata.f_type = datarecord.type;
-			rowdata.f_cost = datarecord.cost;
-			rowdata.f_yield = datarecord.yield;
-			rowdata.f_color = datarecord.color;
-			rowdata.f_coarse_fine_diff = datarecord.coarse_fine_diff;
-			rowdata.f_moisture = datarecord.moisture;
-			rowdata.f_diastatic_power = datarecord.diastatic_power;
-			rowdata.f_protein = datarecord.protein;
-			rowdata.f_max_in_batch = datarecord.max_in_batch;
-			rowdata.f_graintype = datarecord.graintype;
-			rowdata.f_dissolved_protein = datarecord.dissolved_protein;
-			rowdata.f_recommend_mash = datarecord.recommend_mash;
-			rowdata.f_add_after_boil = datarecord.add_after_boil;
-			rowdata.f_di_ph = datarecord.di_ph;
-			rowdata.f_acid_to_ph_57 = datarecord.acid_to_ph_57;
-			rowdata.f_inventory = datarecord.inventory;
+			fermentableData.f_name = datarecord.name;
+			fermentableData.f_origin = datarecord.origin;
+			fermentableData.f_supplier = datarecord.supplier;
+			fermentableData.f_type = datarecord.type;
+			fermentableData.f_cost = datarecord.cost;
+			fermentableData.f_yield = datarecord.yield;
+			fermentableData.f_color = datarecord.color;
+			fermentableData.f_coarse_fine_diff = datarecord.coarse_fine_diff;
+			fermentableData.f_moisture = datarecord.moisture;
+			fermentableData.f_diastatic_power = datarecord.diastatic_power;
+			fermentableData.f_protein = datarecord.protein;
+			fermentableData.f_max_in_batch = datarecord.max_in_batch;
+			fermentableData.f_graintype = datarecord.graintype;
+			fermentableData.f_dissolved_protein = datarecord.dissolved_protein;
+			fermentableData.f_recommend_mash = datarecord.recommend_mash;
+			fermentableData.f_add_after_boil = datarecord.add_after_boil;
+			fermentableData.f_di_ph = datarecord.di_ph;
+			fermentableData.f_acid_to_ph_57 = datarecord.acid_to_ph_57;
+			fermentableData.f_inventory = datarecord.inventory;
 		}
 	});
 	$("#wf_amount").jqxNumberInput( Spin3dec );
 	$('#wf_amount').on('change', function (event) {
 		console.log("amount changed: "+event.args.value);
 		$("#fermentableGrid").jqxGrid('setcellvalue', fermentableRow, 'f_amount', event.args.value);
+		fermentableData.f_amount = event.args.value;
 		if (! to_100) {
 			// Recalculate percentages
 			console.log("adjust percentages");
@@ -4505,6 +4547,7 @@
 		var oldvalue = Math.round(fermentableData.f_percentage * 10) / 10.0;
 		var newvalue = event.args.value;
 		console.log("percentage changed: "+newvalue+" old: "+oldvalue);
+		fermentableData.f_percent = newvalue;
 		var rowscount = $("#fermentableGrid").jqxGrid('getdatainformation').rowscount;
 		if ((oldvalue != newvalue) && (rowscount > 1)) {
 			var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', fermentableRow);
@@ -4670,6 +4713,29 @@
 	});
 	$("#HopReady").jqxButton({ template: "success", width: '90px', theme: theme });
 	$("#HopReady").click(function () {
+		var rowID = $("#hopGrid").jqxGrid('getrowid', hopRow);
+		console.log("HopReady row:"+hopRow+" ID:"+rowID);
+		var row = {
+			h_name: $("#wh_name").val(),
+			h_origin: hopData.h_origin,
+			h_amount: parseFloat($("#wh_amount").jqxNumberInput('decimal')) / 1000,
+			h_cost: hopData.h_cost,
+			h_type: hopData.h_type,
+			h_form: hopData.h_form,
+			h_useat: $("#wh_useat").val(),
+			h_time: hopData.h_time,
+			h_alpha: hopData.h_alpha,
+			h_beta: hopData.h_beta,
+			h_hsi: hopData.h_hsi,
+			h_humulene: hopData.h_humulene,
+			h_caryophyllene: hopData.h_caryophyllene,
+			h_cohumulone: hopData.h_cohumulone,
+			h_myrcene: hopData.h_myrcene,
+			h_total_oil: hopData.h_total_oil,
+			h_inventory: hopData.h_inventory,
+			h_avail: hopData.h_avail
+		};
+		$("#hopGrid").jqxGrid('updaterow', rowID, row);
 		calcIBUs();
 	});
 	$("#wh_name").jqxInput({ theme: theme, width: 320, height: 23 });
@@ -4696,70 +4762,64 @@
 		if (event.args) {
 			var index = event.args.index;
 			var datarecord = hoplist.records[index];
-			var rowdata = $("#hopGrid").jqxGrid('getrowdata', hopRow);
+			// console.log("select another hop:"+index+" "+datarecord.name);
 			$("#wh_name").val(datarecord.name);
-			rowdata.h_name = datarecord.name;
-			rowdata.h_origin = datarecord.origin;
-			rowdata.h_cost = datarecord.cost;
-			rowdata.h_type = datarecord.type;
-			rowdata.h_form = datarecord.form;
-			rowdata.h_alpha = datarecord.alpha;
-			rowdata.h_beta = datarecord.beta;
-			rowdata.h_hsi = datarecord.hsi;
-			rowdata.h_humulene = datarecord.humulene;
-			rowdata.h_caryophyllene = datarecord.caryophyllene;
-			rowdata.h_cohumulone = datarecord.cohumulone;
-			rowdata.h_myrcene = datarecord.myrcene;
-			rowdata.h_total_oil = datarecord.total_oil;
-			rowdata.h_inventory = datarecord.inventory;
+			hopData.h_name = datarecord.name;
+			hopData.h_origin = datarecord.origin;
+			hopData.h_cost = datarecord.cost;
+			hopData.h_type = datarecord.type;
+			hopData.h_form = datarecord.form;
+			hopData.h_alpha = datarecord.alpha;
+			hopData.h_beta = datarecord.beta;
+			hopData.h_hsi = datarecord.hsi;
+			hopData.h_humulene = datarecord.humulene;
+			hopData.h_caryophyllene = datarecord.caryophyllene;
+			hopData.h_cohumulone = datarecord.cohumulone;
+			hopData.h_myrcene = datarecord.myrcene;
+			hopData.h_total_oil = datarecord.total_oil;
+			hopData.h_inventory = datarecord.inventory;
 		}
 	});
 	$("#wh_amount").jqxNumberInput( Spin1dec );
 	$('#wh_amount').on('change', function (event) {
-		console.log("amount changed: "+event.args.value);
+		console.log("amount changed: "+event.args.value+" time:"+hopData.h_time+" alpha:"+hopData.h_alpha);
 		var amount = parseFloat(event.args.value) / 1000;
-		var rowdata = $("#hopGrid").jqxGrid('getrowdata', hopRow);
-		var ibu = toIBU(rowdata.h_useat, rowdata.h_form, preboil_sg,
+		var ibu = toIBU(hopData.h_useat, hopData.h_form, preboil_sg,
 			parseFloat($("#batch_size").jqxNumberInput('decimal')),
-			amount, parseFloat(rowdata.h_time),
-			parseFloat(rowdata.h_alpha), $("#ibu_method").val()
+			amount, parseFloat(hopData.h_time),
+			parseFloat(hopData.h_alpha), $("#ibu_method").val()
 		);
-		rowdata.h_amount = amount;
-		var ibu = toIBU(rowdata.h_useat, rowdata.h_form, preboil_sg, parseFloat($("#batch_size").jqxNumberInput('decimal')),
-				parseFloat(rowdata.h_amount), parseFloat(rowdata.h_time), parseFloat(rowdata.h_alpha), $("#ibu_method").val());
+		hopData.h_amount = amount;
 		$("#wh_ibu").val(ibu);
-		calcIBUs();
 	});
 	$("#wh_ibu").jqxNumberInput( Show1dec );
 	$("#wh_time").jqxNumberInput( PosInt );
 	$("#wh_time").on('change', function (event) {
-		console.log("time changed: "+event.args.value);
-		var rowdata = $("#hopGrid").jqxGrid('getrowdata', hopRow);
 		var newtime = parseFloat(event.args.value);
 		// Check limits and correct
-		if (rowdata.h_useat == 2) {     // Boil
+		if (hopData.h_useat == 2) {     // Boil
 			if (newtime > parseFloat($("#boil_time").jqxNumberInput('decimal'))) {
 				newtime = parseFloat($("#boil_time").jqxNumberInput('decimal'));
 				$("#wh_time").val(newtime);
 			}
-			rowdata.h_time = newtime;
-		} else if (rowdata.h_useat == 4) {      // Whirlpool
+			hopData.h_time = newtime;
+		} else if (hopData.h_useat == 4) {      // Whirlpool
 			if (newtime > 120) {
 				newtime = 120;
 				$("#wh_time").val(newtime);
 			}
-			rowdata.h_time = newtime;
-		} else if (rowdata.h_useat == 5) {      // Dry hop
+			hopData.h_time = newtime;
+		} else if (hopData.h_useat == 5) {      // Dry hop
 			if (newtime > 21) {
 				newtime = 21;
 				$("#wh_time").val(newtime);
 			}
-			rowdata.h_time = newtime * 1440;
+			hopData.h_time = newtime * 1440;
 		}
-		var ibu = toIBU(rowdata.h_useat, rowdata.h_form, preboil_sg, parseFloat($("#batch_size").jqxNumberInput('decimal')),
-				parseFloat(rowdata.h_amount), parseFloat(rowdata.h_time), parseFloat(rowdata.h_alpha), $("#ibu_method").val());
+		var ibu = toIBU(hopData.h_useat, hopData.h_form, preboil_sg, parseFloat($("#batch_size").jqxNumberInput('decimal')),
+				parseFloat(hopData.h_amount), parseFloat(hopData.h_time), parseFloat(hopData.h_alpha), $("#ibu_method").val());
+		// console.log("time changed: "+newtime+" final:"+hopData.h_time+" ibu:"+ibu);
 		$("#wh_ibu").val(ibu);
-		calcIBUs();
 	});
 	$("#wh_useat").jqxDropDownList({
 		theme: theme,
@@ -4774,14 +4834,13 @@
 	$("#wh_useat").on('select', function (event) {
 		if (event.args) {
 			var index = event.args.index;
-			var rowdata = $("#hopGrid").jqxGrid('getrowdata', hopRow);
-			rowdata.h_useat = index;
+			hopData.h_useat = index;
 			if ((index == 0) || (index == 1)) {     // Mashhop or First wort hop
-				rowdata.h_time = parseFloat(dataRecord.boil_time);
+				hopData.h_time = parseFloat(dataRecord.boil_time);
 				$("#wh_time").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
-				$("#wh_time").val(rowdata.h_time);
+				$("#wh_time").val(hopData.h_time);
 			} else if (index == 3) {        // Aroma
-				rowdata.h_time = 0;
+				hopData.h_time = 0;
 				$("#wh_time").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
 				$("#wh_time").val(0);
 			} else {        // Boil, Whirlpool or Dry hop
@@ -4808,6 +4867,20 @@
 	});
 	$("#MiscReady").jqxButton({ template: "success", width: '90px', theme: theme });
 	$("#MiscReady").click(function () {
+		var rowID = $("#miscGrid").jqxGrid('getrowid', miscRow);
+		console.log("MiscReady row:"+miscRow+" ID:"+rowID);
+		var row = {
+			m_name: miscData.m_name,
+			m_amount: miscData.m_amount,
+			m_cost: miscData.m_cost,
+			m_type: miscData.m_type,
+			m_use_use: miscData.m_use_use,
+			m_time: miscData.m_time,
+			m_amount_is_weight: miscData.m_amount_is_weight,
+			m_inventory: miscData.m_inventory,
+			m_avail:  miscData.m_avail
+		};
+		$("#miscGrid").jqxGrid('updaterow', rowID, row);
 		calcMiscs();
 	});
 	$("#wm_name").jqxInput({ theme: theme, width: 320, height: 23 });
@@ -4830,41 +4903,37 @@
 		if (event.args) {
 			var index = event.args.index;
 			var datarecord = misclist.records[index];
-			var rowdata = $("#miscGrid").jqxGrid('getrowdata', miscRow);
 			$("#wm_name").val(datarecord.name);
-			rowdata.m_name = datarecord.name;
-			rowdata.m_cost = datarecord.cost;
-			rowdata.m_type = datarecord.type;
-			rowdata.m_use_use = datarecord.use_use;
-			rowdata.m_amount_is_weight = datarecord.amount_is_weight;
-			rowdata.m_inventory = datarecord.inventory;
+			miscData.m_name = datarecord.name;
+			miscData.m_cost = datarecord.cost;
+			miscData.m_type = datarecord.type;
+			miscData.m_use_use = datarecord.use_use;
+			miscData.m_amount_is_weight = datarecord.amount_is_weight;
+			miscData.m_inventory = datarecord.inventory;
 		}
 	});
 	$("#wm_amount").jqxNumberInput( Spin1dec );
 	$('#wm_amount').on('change', function (event) {
 		console.log("amount changed: "+event.args.value);
-		var amount = parseFloat(event.args.value) / 1000;
-		var rowdata = $("#miscGrid").jqxGrid('getrowdata', miscRow);
-		rowdata.m_amount = amount;
+		miscData.m_amount = parseFloat(event.args.value) / 1000;
 	});
 	$("#wm_time").jqxNumberInput( PosInt );
 	$("#wm_time").on('change', function (event) {
 		console.log("time changed: "+event.args.value);
-		var rowdata = $("#miscGrid").jqxGrid('getrowdata', miscRow);
 		var newtime = parseFloat(event.args.value);
 
-		if (rowdata.m_use_use == 2) {   // Boil
+		if (miscData.m_use_use == 2) {   // Boil
 			if (newtime > parseFloat($("#boil_time").jqxNumberInput('decimal'))) {
 				newtime = parseFloat($("#boil_time").jqxNumberInput('decimal'));
 				$("#wm_time").val(newtime);
 			}
-			rowdata.m_time = newtime;
-		} else if ((rowdata.m_use_use == 3) || (rowdata.m_use_use == 4)) {      // Primary or Secondary
+			miscData.m_time = newtime;
+		} else if ((miscData.m_use_use == 3) || (miscData.m_use_use == 4)) {      // Primary or Secondary
 			if (newtime > 21) {
 				newtime = 21;
 				$("#wm_time").val(newtime);
 			}
-			rowdata.m_time = newtime * 1440;
+			miscData.m_time = newtime * 1440;
 		}
 	});
 	$("#wm_use_use").jqxDropDownList({
@@ -4880,14 +4949,13 @@
 	$("#wm_use_use").on('select', function (event) {
 		if (event.args) {
 			var index = event.args.index;
-			var rowdata = $("#miscGrid").jqxGrid('getrowdata', miscRow);
-			rowdata.m_use_use = index;
+			miscData.m_use_use = index;
 			if ((index == 2) || (index == 3) || (index == 4)) {     // Boil, Primary or Secondary
 				$("#wm_time").jqxNumberInput({ spinButtons: true, readOnly: false, width: 110 });
 			} else {
-				rowdata.m_time = 0;
 				$("#wm_time").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
 				$("#wm_time").val(0);
+				miscData.m_time = 0;
 			}
 		}
 	});
@@ -4913,6 +4981,27 @@
 	});
 	$("#YeastReady").jqxButton({ template: "success", width: '90px', theme: theme });
 	$("#YeastReady").click(function () {
+		var rowID = $("#yeastGrid").jqxGrid('getrowid', yeastRow);
+		console.log("YeastReady row:"+yeastRow+" ID:"+rowID);
+		var row = {
+			y_name: yeastData.y_name,
+			y_laboratory: yeastData.y_laboratory,
+			y_product_id: yeastData.y_product_id,
+			y_amount: yeastData.y_amount,
+			y_cost: yeastData.y_cost,
+			y_type: yeastData.y_type,
+			y_form: yeastData.y_form,
+			y_flocculation: yeastData.y_flocculation,
+			y_min_temperature: yeastData.y_min_temperature,
+			y_max_temperature: yeastData.y_max_temperature,
+			y_attenuation: yeastData.y_attenuation,
+			y_use: yeastData.y_use,
+			y_cells: yeastData.y_cells,
+			y_tolerance: yeastData.y_tolerance,
+			y_inventory: yeastData.y_inventory,
+			y_avail: yeastData.y_avail
+		};
+		$("#yeastGrid").jqxGrid('updaterow', rowID, row);
 		calcFermentables();
 		calcYeast();
 	});
@@ -4942,25 +5031,24 @@
 		if (event.args) {
 			var index = event.args.index;
 			var datarecord = yeastlist.records[index];
-			var rowdata = $("#yeastGrid").jqxGrid('getrowdata', yeastRow);
 			$("#wy_name").val(datarecord.name);
 			$("#wy_laboratory").val(datarecord.laboratory);
 			$("#wy_product_id").val(datarecord.product_id);
-			rowdata.y_name = datarecord.name;
-			rowdata.y_cost = datarecord.cost;
-			rowdata.y_type = datarecord.type;
-			rowdata.y_form = datarecord.form;
-			rowdata.y_laboratory = datarecord.laboratory;
-			rowdata.y_product_id = datarecord.product_id;
-			rowdata.y_min_temperature = datarecord.min_temperature;
-			rowdata.y_max_temperature = datarecord.max_temperature;
-			rowdata.y_flocculation = datarecord.flocculation;
-			rowdata.y_attenuation = datarecord.attenuation;
-			rowdata.y_cells = datarecord.cells;
-			rowdata.y_inventory = datarecord.inventory;
-			if (rowdata.y_form == 0) {
+			yeastData.y_name = datarecord.name;
+			yeastData.y_cost = datarecord.cost;
+			yeastData.y_type = datarecord.type;
+			yeastData.y_form = datarecord.form;
+			yeastData.y_laboratory = datarecord.laboratory;
+			yeastData.y_product_id = datarecord.product_id;
+			yeastData.y_min_temperature = datarecord.min_temperature;
+			yeastData.y_max_temperature = datarecord.max_temperature;
+			yeastData.y_flocculation = datarecord.flocculation;
+			yeastData.y_attenuation = datarecord.attenuation;
+			yeastData.y_cells = datarecord.cells;
+			yeastData.y_inventory = datarecord.inventory;
+			if (yeastData.y_form == 0) {
 				$("#wy_pmpt_amount").html("Pak(ken):");
-			} else if (rowdata.y_form == 1) {
+			} else if (yeastData.y_form == 1) {
 				$("#wy_pmpt_amount").html("Gewicht gram:");
 			} else {
 				$("#wy_pmpt_amount").html("Volume ml:");
@@ -4972,12 +5060,11 @@
 	$("#wy_amount").jqxNumberInput( Spin1dec );
 	$('#wy_amount').on('change', function (event) {
 		console.log("amount changed: "+event.args.value);
-		var rowdata = $("#yeastGrid").jqxGrid('getrowdata', yeastRow);
-		if (rowdata.y_form == 0)        // Liquid
+		if (yeastData.y_form == 0)        // Liquid
 			var amount = parseFloat(event.args.value);
 		else
 			var amount = parseFloat(event.args.value) / 1000;
-		rowdata.y_amount = amount;
+		yeastData.y_amount = amount;
 		calcFermentables();
 		calcYeast();
 	});
@@ -4994,8 +5081,7 @@
 	$("#wy_use").on('select', function (event) {
 		if (event.args) {
 			var index = event.args.index;
-			var rowdata = $("#yeastGrid").jqxGrid('getrowdata', yeastRow);
-			rowdata.y_use = index;
+			yeastData.y_use = index;
 			calcFermentables();
 			calcYeast();
 		}
@@ -5100,7 +5186,6 @@
 	});
 	$("#MashReady").jqxButton({ template: "success", width: '90px', theme: theme });
 	$("#MashReady").click(function () {
-		$("#mashGrid").jqxGrid('sortby', 'step_temp', 'asc');
 		calcMash();
 	});
 	$("#wstep_name").jqxInput({ theme: theme, width: 320, height: 23 });
--- a/www/js/rec_edit.js	Tue Jun 04 16:38:53 2019 +0200
+++ b/www/js/rec_edit.js	Tue Jun 04 19:50:06 2019 +0200
@@ -1809,9 +1809,15 @@
 				{ name: 'f_avail', type: 'int' }
 			],
 			addrow: function (rowid, rowdata, position, commit) {
+				console.log("fermentable addrow "+rowid);
 				commit(true);
 			},
 			deleterow: function (rowid, commit) {
+				console.log("fermentable deleterow "+rowid);
+				commit(true);
+			},
+			updaterow: function (rowid, rowdata, commit) {
+				console.log("fermentable updaterow "+rowid);
 				commit(true);
 			}
 		};
@@ -1821,7 +1827,6 @@
 			height: 470,
 			source: fermentableAdapter,
 			theme: theme,
-			sortmode: "many",
 			selectionmode: 'singlerow',
 			showtoolbar: true,
 			rendertoolbar: function (toolbar) {
@@ -1940,11 +1945,6 @@
 				});
 			},
 			ready: function() {
-				var datainformation = $('#fermentableGrid').jqxGrid('getdatainformation');
-                                if (datainformation.rowscount) {
-					$("#fermentableGrid").jqxGrid('sortby', 'f_added', 'asc');
-					$("#fermentableGrid").jqxGrid('sortby', 'f_amount', 'desc');
-				}
 				calcFermentables();
 				$('#jqxTabs').jqxTabs('next');
 			},
@@ -2034,11 +2034,17 @@
 				{ name: 'h_avail', type: 'int' }
                         ],
                         addrow: function (rowid, rowdata, position, commit) {
+				console.log("hop addrow "+rowid);
                                 commit(true);
                         },
                         deleterow: function (rowid, commit) {
+				console.log("hop deleterow "+rowid);
                                 commit(true);
-                        }
+                        },
+			updaterow: function (rowid, rowdata, commit) {
+				console.log("hop updaterow "+rowid);
+				commit(true);
+			}
                 };
                 var hopAdapter = new $.jqx.dataAdapter(hopSource);
                 $("#hopGrid").jqxGrid({
@@ -2046,7 +2052,6 @@
                         height: 560,
                         source: hopAdapter,
                         theme: theme,
-			sortmode: "many",
                         selectionmode: 'singlerow',
                         showtoolbar: true,
                         rendertoolbar: function (toolbar) {
@@ -2119,12 +2124,6 @@
                                 });
                         },
 			ready: function() {
-				var datainformation = $('#hopGrid').jqxGrid('getdatainformation');
-                                if (datainformation.rowscount) {
-					$("#hopGrid").jqxGrid('sortby', 'h_useat', 'asc');
-					$("#hopGrid").jqxGrid('sortby', 'h_time', 'desc');
-					$("#hopGrid").jqxGrid('sortby', 'h_amount', 'desc');
-				}
 				calcIBUs();
 				$('#jqxTabs').jqxTabs('next');
 			},
@@ -2232,11 +2231,17 @@
 				{ name: 'm_avail', type: 'int' }
                         ],
                         addrow: function (rowid, rowdata, position, commit) {
+				console.log("misc addrow "+rowid);
                                 commit(true);
                         },
                         deleterow: function (rowid, commit) {
+				console.log("misc deleterow "+rowid);
                                 commit(true);
-                        }
+                        },
+			updaterow: function (rowid, rowdata, commit) {
+				console.log("misc updaterow "+rowid);
+				commit(true);
+			}
                 };
                 var miscAdapter = new $.jqx.dataAdapter(miscSource, {
 			beforeLoadComplete: function (records) {
@@ -2303,7 +2308,6 @@
                         height: 575,
                         source: miscAdapter,
                         theme: theme,
-			sortmode: "many",
                         selectionmode: 'singlerow',
                         showtoolbar: true,
                         rendertoolbar: function (toolbar) {
@@ -2360,11 +2364,6 @@
                                 });
                         },
 			ready: function() {
-				var datainformation = $('#miscGrid').jqxGrid('getdatainformation');
-				if (datainformation.rowscount) {
-					$("#miscGrid").jqxGrid('sortby', 'm_use_use', 'asc');
-					$("#miscGrid").jqxGrid('sortby', 'm_type', 'asc');
-				}
 				$('#jqxTabs').jqxTabs('next');
 			},
 			columns: [
@@ -2411,20 +2410,23 @@
 					}, buttonclick: function (row) {
 						miscRow = row;
 						miscData = $("#miscGrid").jqxGrid('getrowdata', miscRow);
-						if (miscData.m_amount_is_weight)
-							$("#wm_pmpt_amount").html("Gewicht gram:");
-						else
-							$("#wm_pmpt_amount").html("Volume ml:");
-						$("#wm_name").val(miscData.m_name);
-						$("#wm_amount").val(miscData.m_amount * 1000);
-						if ((miscData.m_use_use == 3) || (miscData.m_use_use == 4))	// Primary or Secondary
-							$("#wm_time").val(miscData.m_time / 1440);
-						else
-							$("#wm_time").val(miscData.m_time);
-						$("#wm_use_use").val(miscData.m_use_use);
-						// show the popup window.
-						if (miscData.m_type != 4)
+						if (miscData.m_type == 4) {
+							alert("Brouwzouten wijzigen in de water tab.");
+						} else {
+							if (miscData.m_amount_is_weight)
+								$("#wm_pmpt_amount").html("Gewicht gram:");
+							else
+								$("#wm_pmpt_amount").html("Volume ml:");
+							$("#wm_name").val(miscData.m_name);
+							$("#wm_amount").val(miscData.m_amount * 1000);
+							if ((miscData.m_use_use == 3) || (miscData.m_use_use == 4))	// Primary or Secondary
+								$("#wm_time").val(miscData.m_time / 1440);
+							else
+								$("#wm_time").val(miscData.m_time);
+							$("#wm_use_use").val(miscData.m_use_use);
+							// show the popup window.
 							$("#popupMisc").jqxWindow('open');
+						}
 					}
 				}
                         ]
@@ -2457,11 +2459,17 @@
 				{ name: 'y_avail', type: 'int' }
                         ],
                         addrow: function (rowid, rowdata, position, commit) {
+				console.log("yeast addrow "+rowid);
                                 commit(true);
                         },
                         deleterow: function (rowid, commit) {
+				console.log("yeast deleterow "+rowid);
                                 commit(true);
-                        }
+                        },
+			updaterow: function (rowid, rowdata, commit) {
+				console.log("yeast updaterow "+rowid);
+				commit(true);
+			}
                 };
                 var yeastAdapter = new $.jqx.dataAdapter(yeastSource);
                 $("#yeastGrid").jqxGrid({
@@ -2469,7 +2477,6 @@
                         height: 350,
                         source: yeastAdapter,
                         theme: theme,
-			sortmode: "many",
                         selectionmode: 'singlerow',
                         showtoolbar: true,
                         rendertoolbar: function (toolbar) {
@@ -2537,10 +2544,6 @@
                                 });
                         },
 			ready: function() {
-				var datainformation = $('#yeastGrid').jqxGrid('getdatainformation');
-                                if (datainformation.rowscount) {
-					$("#yeastGrid").jqxGrid('sortby', 'y_use', 'asc');
-				}
 				calcFermentables();
 				$('#jqxTabs').jqxTabs('next');
 			},
@@ -2933,6 +2936,35 @@
 	});
 	$("#FermentableReady").jqxButton({ template: "success", width: '90px', theme: theme });
 	$("#FermentableReady").click(function () {
+		var rowID = $("#fermentableGrid").jqxGrid('getrowid', fermentableRow);
+		console.log("FermentableReady row:"+fermentableRow+" ID:"+rowID);
+		var row = {
+			f_name: fermentableData.f_name,
+			f_origin: fermentableData.f_origin,
+			f_supplier: fermentableData.f_supplier,
+			f_amount: fermentableData.f_amount,
+			f_cost: fermentableData.f_cost,
+			f_type: fermentableData.f_type,
+			f_yield: fermentableData.f_yield,
+			f_color: fermentableData.f_color,
+			f_coarse_fine_diff: fermentableData.f_coarse_fine_diff,
+			f_moisture: fermentableData.f_moisture,
+			f_diastatic_power: fermentableData.f_diastatic_power,
+			f_protein: fermentableData.f_protein,
+			f_max_in_batch: fermentableData.f_max_in_batch,
+			f_graintype: fermentableData.f_graintype,
+			f_added: fermentableData.f_added,
+			f_dissolved_protein: fermentableData.f_dissolved_protein,
+			f_recommend_mash: fermentableData.f_recommend_mash,
+			f_add_after_boil: fermentableData.f_add_after_boil,
+			f_adjust_to_total_100: fermentableData.f_adjust_to_total_100,
+			f_percentage: fermentableData.f_percentage,
+			f_di_ph: fermentableData.f_di_ph,
+			f_acid_to_ph_57: fermentableData.f_acid_to_ph_57,
+			f_inventory: fermentableData.f_inventory,
+			f_avail: fermentableData.f_avail
+		};
+		$("#fermentableGrid").jqxGrid('updaterow', rowID, row);
 		// Recalc percentages
 		calcFermentables();
 		calcIBUs();
@@ -2963,33 +2995,33 @@
 		if (event.args) {
 			var index = event.args.index;
 			var datarecord = fermentablelist.records[index];
-			var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', fermentableRow);
 			$("#wf_name").val(datarecord.name);
-			rowdata.f_name = datarecord.name;
-			rowdata.f_origin = datarecord.origin;
-			rowdata.f_supplier = datarecord.supplier;
-			rowdata.f_type = datarecord.type;
-			rowdata.f_cost = datarecord.cost;
-			rowdata.f_yield = datarecord.yield;
-			rowdata.f_color = datarecord.color;
-			rowdata.f_coarse_fine_diff = datarecord.coarse_fine_diff;
-			rowdata.f_moisture = datarecord.moisture;
-			rowdata.f_diastatic_power = datarecord.diastatic_power;
-			rowdata.f_protein = datarecord.protein;
-			rowdata.f_max_in_batch = datarecord.max_in_batch;
-			rowdata.f_graintype = datarecord.graintype;
-			rowdata.f_dissolved_protein = datarecord.dissolved_protein;
-			rowdata.f_recommend_mash = datarecord.recommend_mash;
-			rowdata.f_add_after_boil = datarecord.add_after_boil;
-			rowdata.f_di_ph = datarecord.di_ph;
-			rowdata.f_acid_to_ph_57 = datarecord.acid_to_ph_57;
-			rowdata.f_inventory = datarecord.inventory;
+			fermentableData.f_name = datarecord.name;
+			fermentableData.f_origin = datarecord.origin;
+			fermentableData.f_supplier = datarecord.supplier;
+			fermentableData.f_type = datarecord.type;
+			fermentableData.f_cost = datarecord.cost;
+			fermentableData.f_yield = datarecord.yield;
+			fermentableData.f_color = datarecord.color;
+			fermentableData.f_coarse_fine_diff = datarecord.coarse_fine_diff;
+			fermentableData.f_moisture = datarecord.moisture;
+			fermentableData.f_diastatic_power = datarecord.diastatic_power;
+			fermentableData.f_protein = datarecord.protein;
+			fermentableData.f_max_in_batch = datarecord.max_in_batch;
+			fermentableData.f_graintype = datarecord.graintype;
+			fermentableData.f_dissolved_protein = datarecord.dissolved_protein;
+			fermentableData.f_recommend_mash = datarecord.recommend_mash;
+			fermentableData.f_add_after_boil = datarecord.add_after_boil;
+			fermentableData.f_di_ph = datarecord.di_ph;
+			fermentableData.f_acid_to_ph_57 = datarecord.acid_to_ph_57;
+			fermentableData.f_inventory = datarecord.inventory;
 		}
 	});
 	$("#wf_amount").jqxNumberInput( Spin3dec );
 	$('#wf_amount').on('change', function (event) {
 		console.log("amount changed: "+event.args.value);
 		$("#fermentableGrid").jqxGrid('setcellvalue', fermentableRow, 'f_amount', event.args.value);
+		fermentableData.f_amount = event.args.value;
 		if (! to_100) {
 			// Recalculate percentages
 			console.log("adjust percentages");
@@ -3019,6 +3051,7 @@
 		var oldvalue = Math.round(fermentableData.f_percentage * 10) / 10.0;
 		var newvalue = event.args.value;
 		console.log("percentage changed: "+newvalue+" old: "+oldvalue);
+		fermentableData.f_percent = newvalue;
 		var rowscount = $("#fermentableGrid").jqxGrid('getdatainformation').rowscount;
 		if ((oldvalue != newvalue) && (rowscount > 1)) {
 			var rowdata = $("#fermentableGrid").jqxGrid('getrowdata', fermentableRow);
@@ -3186,6 +3219,29 @@
 	});
 	$("#HopReady").jqxButton({ template: "success", width: '90px', theme: theme });
 	$("#HopReady").click(function () {
+		var rowID = $("#hopGrid").jqxGrid('getrowid', hopRow);
+		console.log("HopReady row:"+hopRow+" ID:"+rowID);
+		var row = {
+			h_name: $("#wh_name").val(),
+			h_origin: hopData.h_origin,
+			h_amount: parseFloat($("#wh_amount").jqxNumberInput('decimal')) / 1000,
+			h_cost: hopData.h_cost,
+			h_type: hopData.h_type,
+			h_form: hopData.h_form,
+			h_useat: $("#wh_useat").val(),
+			h_time: hopData.h_time,
+			h_alpha: hopData.h_alpha,
+			h_beta: hopData.h_beta,
+			h_hsi: hopData.h_hsi,
+			h_humulene: hopData.h_humulene,
+			h_caryophyllene: hopData.h_caryophyllene,
+			h_cohumulone: hopData.h_cohumulone,
+			h_myrcene: hopData.h_myrcene,
+			h_total_oil: hopData.h_total_oil,
+			h_inventory: hopData.h_inventory,
+			h_avail: hopData.h_avail
+		};
+		$("#hopGrid").jqxGrid('updaterow', rowID, row);
 		calcIBUs();
 	});
 	$("#wh_name").jqxInput({ theme: theme, width: 320, height: 23 });
@@ -3212,71 +3268,63 @@
 		if (event.args) {
 			var index = event.args.index;
 			var datarecord = hoplist.records[index];
-			var rowdata = $("#hopGrid").jqxGrid('getrowdata', hopRow);
 			$("#wh_name").val(datarecord.name);
-			rowdata.h_name = datarecord.name;
-			rowdata.h_origin = datarecord.origin;
-			rowdata.h_cost = datarecord.cost;
-			rowdata.h_type = datarecord.type;
-			rowdata.h_form = datarecord.form;
-			rowdata.h_alpha = datarecord.alpha;
-			rowdata.h_beta = datarecord.beta;
-			rowdata.h_hsi = datarecord.hsi;
-			rowdata.h_humulene = datarecord.humulene;
-			rowdata.h_caryophyllene = datarecord.caryophyllene;
-			rowdata.h_cohumulone = datarecord.cohumulone;
-			rowdata.h_myrcene = datarecord.myrcene;
-			rowdata.h_total_oil = datarecord.total_oil;
-			rowdata.h_inventory = datarecord.inventory;
+			hopData.h_name = datarecord.name;
+			hopData.h_origin = datarecord.origin;
+			hopData.h_cost = datarecord.cost;
+			hopData.h_type = datarecord.type;
+			hopData.h_form = datarecord.form;
+			hopData.h_alpha = datarecord.alpha;
+			hopData.h_beta = datarecord.beta;
+			hopData.h_hsi = datarecord.hsi;
+			hopData.h_humulene = datarecord.humulene;
+			hopData.h_caryophyllene = datarecord.caryophyllene;
+			hopData.h_cohumulone = datarecord.cohumulone;
+			hopData.h_myrcene = datarecord.myrcene;
+			hopData.h_total_oil = datarecord.total_oil;
+			hopData.h_inventory = datarecord.inventory;
 		}
 	});
 	$("#wh_amount").jqxNumberInput( Spin1dec );
 	$('#wh_amount').on('change', function (event) {
-		console.log("amount changed: "+event.args.value);
+		console.log("amount changed: "+event.args.value+" time:"+hopData.h_time+" alpha:"+hopData.h_alpha);
 		var amount = parseFloat(event.args.value) / 1000;
-		var rowdata = $("#hopGrid").jqxGrid('getrowdata', hopRow);
 
-		var ibu = toIBU(rowdata.h_useat, rowdata.h_form, preboil_sg,
+		var ibu = toIBU(hopData.h_useat, hopData.h_form, preboil_sg,
 			parseFloat($("#batch_size").jqxNumberInput('decimal')),
-			amount, parseFloat(rowdata.h_time),
-			parseFloat(rowdata.h_alpha), $("#ibu_method").val()
+			amount, parseFloat(hopData.h_time),
+			parseFloat(hopData.h_alpha), $("#ibu_method").val()
 		);
-		rowdata.h_amount = amount;
-		var ibu = toIBU(rowdata.h_useat, rowdata.h_form, preboil_sg, parseFloat($("#batch_size").jqxNumberInput('decimal')),
-				parseFloat(rowdata.h_amount), parseFloat(rowdata.h_time), parseFloat(rowdata.h_alpha), $("#ibu_method").val());
+		hopData.h_amount = amount;
 		$("#wh_ibu").val(ibu);
-		calcIBUs();
 	});
 	$("#wh_ibu").jqxNumberInput( Show1dec );
 	$("#wh_time").jqxNumberInput( PosInt );
 	$("#wh_time").on('change', function (event) {
-		console.log("time changed: "+event.args.value);
-		var rowdata = $("#hopGrid").jqxGrid('getrowdata', hopRow);
 		var newtime = parseFloat(event.args.value);
 		// Check limits and correct
-		if (rowdata.h_useat == 2) {	// Boil
+		if (hopData.h_useat == 2) {	// Boil
 			if (newtime > parseFloat($("#boil_time").jqxNumberInput('decimal'))) {
 				newtime = parseFloat($("#boil_time").jqxNumberInput('decimal'));
 				$("#wh_time").val(newtime);
 			}
-			rowdata.h_time = newtime;
-		} else if (rowdata.h_useat == 4) {	// Whirlpool
+			hopData.h_time = newtime;
+		} else if (hopData.h_useat == 4) {	// Whirlpool
 			if (newtime > 120) {
 				newtime = 120;
 				$("#wh_time").val(newtime);
 			}
-			rowdata.h_time = newtime;
-		} else if (rowdata.h_useat == 5) {	// Dry hop
+			hopData.h_time = newtime;
+		} else if (hopData.h_useat == 5) {	// Dry hop
 			if (newtime > 21) {
 				newtime = 21;
 				$("#wh_time").val(newtime);
 			}
-			rowdata.h_time = newtime * 1440;
+			hopData.h_time = newtime * 1440;
 		}
-		var ibu = toIBU(rowdata.h_useat, rowdata.h_form, preboil_sg, parseFloat($("#batch_size").jqxNumberInput('decimal')),
-			parseFloat(rowdata.h_amount), parseFloat(rowdata.h_time), parseFloat(rowdata.h_alpha), $("#ibu_method").val());
+		var ibu = toIBU(hopData.h_useat, hopData.h_form, preboil_sg, parseFloat($("#batch_size").jqxNumberInput('decimal')),
+			parseFloat(hopData.h_amount), parseFloat(hopData.h_time), parseFloat(hopData.h_alpha), $("#ibu_method").val());
 		$("#wh_ibu").val(ibu);
-		calcIBUs();
 	});
 	$("#wh_useat").jqxDropDownList({
 		theme: theme,
@@ -3291,14 +3339,13 @@
 	$("#wh_useat").on('select', function (event) {
 		if (event.args) {
 			var index = event.args.index;
-			var rowdata = $("#hopGrid").jqxGrid('getrowdata', hopRow);
-			rowdata.h_useat = index;
+			hopData.h_useat = index;
 			if ((index == 0) || (index == 1)) {	// Mashhop or First wort hop
-				rowdata.h_time = parseFloat(dataRecord.boil_time);
+				hopData.h_time = parseFloat(dataRecord.boil_time);
 				$("#wh_time").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
-				$("#wh_time").val(rowdata.h_time);
+				$("#wh_time").val(hopData.h_time);
 			} else if (index == 3) {	// Aroma
-				rowdata.h_time = 0;
+				hopData.h_time = 0;
 				$("#wh_time").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
 				$("#wh_time").val(0);
 			} else {	// Boil, Whirlpool or Dry hop
@@ -3324,6 +3371,22 @@
 		modalOpacity: 0.40
 	});
 	$("#MiscReady").jqxButton({ template: "success", width: '90px', theme: theme });
+	$("#MiscReady").click(function () {
+		var rowID = $("#miscGrid").jqxGrid('getrowid', miscRow);
+		console.log("MiscReady row:"+miscRow+" ID:"+rowID);
+		var row = {
+			m_name: miscData.m_name,
+			m_amount: miscData.m_amount,
+			m_cost: miscData.m_cost,
+			m_type: miscData.m_type,
+			m_use_use: miscData.m_use_use,
+			m_time: miscData.m_time,
+			m_amount_is_weight: miscData.m_amount_is_weight,
+			m_inventory: miscData.m_inventory,
+			m_avail:  miscData.m_avail
+		};
+		$("#miscGrid").jqxGrid('updaterow', rowID, row);
+        });
 	$("#wm_name").jqxInput({ theme: theme, width: 320, height: 23 });
 	$("#wm_instock").jqxCheckBox({ theme: theme, height: 23 });
 	$("#wm_instock").on('change', function (event) {
@@ -3344,41 +3407,37 @@
 		if (event.args) {
 			var index = event.args.index;
 			var datarecord = misclist.records[index];
-			var rowdata = $("#miscGrid").jqxGrid('getrowdata', miscRow);
 			$("#wm_name").val(datarecord.name);
-			rowdata.m_name = datarecord.name;
-			rowdata.m_cost = datarecord.cost;
-			rowdata.m_type = datarecord.type;
-			rowdata.m_use_use = datarecord.use_use;
-			rowdata.m_amount_is_weight = datarecord.amount_is_weight;
-			rowdata.m_inventory = datarecord.inventory;
+			miscData.m_name = datarecord.name;
+			miscData.m_cost = datarecord.cost;
+			miscData.m_type = datarecord.type;
+			miscData.m_use_use = datarecord.use_use;
+			miscData.m_amount_is_weight = datarecord.amount_is_weight;
+			miscData.m_inventory = datarecord.inventory;
 		}
 	});
 	$("#wm_amount").jqxNumberInput( Spin1dec );
 	$('#wm_amount').on('change', function (event) {
 		console.log("amount changed: "+event.args.value);
-		var amount = parseFloat(event.args.value) / 1000;
-		var rowdata = $("#miscGrid").jqxGrid('getrowdata', miscRow);
-		rowdata.m_amount = amount;
+		miscData.m_amount = parseFloat(event.args.value) / 1000;
 	});
 	$("#wm_time").jqxNumberInput( PosInt );
 	$("#wm_time").on('change', function (event) {
 		console.log("time changed: "+event.args.value);
-		var rowdata = $("#miscGrid").jqxGrid('getrowdata', miscRow);
 		var newtime = parseFloat(event.args.value);
 
-		if (rowdata.m_use_use == 2) {	// Boil
+		if (miscData.m_use_use == 2) {	// Boil
 			if (newtime > parseFloat($("#boil_time").jqxNumberInput('decimal'))) {
 				newtime = parseFloat($("#boil_time").jqxNumberInput('decimal'));
 				$("#wm_time").val(newtime);
 			}
-		        rowdata.m_time = newtime;
-		} else if ((rowdata.m_use_use == 3) || (rowdata.m_use_use == 4)) {	// Primary or Secondary
+		        miscData.m_time = newtime;
+		} else if ((miscData.m_use_use == 3) || (miscData.m_use_use == 4)) {	// Primary or Secondary
 			if (newtime > 21) {
 				newtime = 21;
 				$("#wm_time").val(newtime);
 			}
-			rowdata.m_time = newtime * 1440;
+			miscData.m_time = newtime * 1440;
 		}
 	});
 	$("#wm_use_use").jqxDropDownList({
@@ -3394,12 +3453,11 @@
 	$("#wm_use_use").on('select', function (event) {
 		if (event.args) {
 			var index = event.args.index;
-			var rowdata = $("#miscGrid").jqxGrid('getrowdata', miscRow);
-			rowdata.m_use_use = index;
+			miscData.m_use_use = index;
 			if ((index == 2) || (index == 3) || (index == 4)) {	// Boil, Primary or Secondary
 				$("#wm_time").jqxNumberInput({ spinButtons: true, readOnly: false, width: 110 });
 			} else {
-				rowdata.m_time = 0;
+				miscData.m_time = 0;
 				$("#wm_time").jqxNumberInput({ spinButtons: false, readOnly: true, width: 90 });
 				$("#wm_time").val(0);
 			}
@@ -3424,6 +3482,27 @@
 	});
 	$("#YeastReady").jqxButton({ template: "success", width: '90px', theme: theme });
 	$("#YeastReady").click(function () {
+		var rowID = $("#yeastGrid").jqxGrid('getrowid', yeastRow);
+		console.log("YeastReady row:"+yeastRow+" ID:"+rowID);
+		var row = {
+			y_name: yeastData.y_name,
+			y_laboratory: yeastData.y_laboratory,
+			y_product_id: yeastData.y_product_id,
+			y_amount: yeastData.y_amount,
+			y_cost: yeastData.y_cost,
+			y_type: yeastData.y_type,
+			y_form: yeastData.y_form,
+			y_flocculation: yeastData.y_flocculation,
+			y_min_temperature: yeastData.y_min_temperature,
+			y_max_temperature: yeastData.y_max_temperature,
+			y_attenuation: yeastData.y_attenuation,
+			y_use: yeastData.y_use,
+			y_cells: yeastData.y_cells,
+			y_tolerance: yeastData.y_tolerance,
+			y_inventory: yeastData.y_inventory,
+			y_avail: yeastData.y_avail
+		};
+		$("#yeastGrid").jqxGrid('updaterow', rowID, row);
 		calcFermentables();
 	});
 	$("#wy_name").jqxInput({ theme: theme, width: 320, height: 23 });
@@ -3452,25 +3531,24 @@
 		if (event.args) {
 			var index = event.args.index;
 			var datarecord = yeastlist.records[index];
-			var rowdata = $("#yeastGrid").jqxGrid('getrowdata', yeastRow);
 			$("#wy_name").val(datarecord.name);
 			$("#wy_laboratory").val(datarecord.laboratory);
 			$("#wy_product_id").val(datarecord.product_id);
-			rowdata.y_name = datarecord.name;
-			rowdata.y_cost = datarecord.cost;
-			rowdata.y_type = datarecord.type;
-			rowdata.y_form = datarecord.form;
-			rowdata.y_laboratory = datarecord.laboratory;
-			rowdata.y_product_id = datarecord.product_id;
-			rowdata.y_min_temperature = datarecord.min_temperature;
-			rowdata.y_max_temperature = datarecord.max_temperature;
-			rowdata.y_flocculation = datarecord.flocculation;
-			rowdata.y_attenuation = datarecord.attenuation;
-			rowdata.y_cells = datarecord.cells;
-			rowdata.y_inventory = datarecord.inventory;
-			if (rowdata.y_form == 0) {
+			yeastData.y_name = datarecord.name;
+			yeastData.y_cost = datarecord.cost;
+			yeastData.y_type = datarecord.type;
+			yeastData.y_form = datarecord.form;
+			yeastData.y_laboratory = datarecord.laboratory;
+			yeastData.y_product_id = datarecord.product_id;
+			yeastData.y_min_temperature = datarecord.min_temperature;
+			yeastData.y_max_temperature = datarecord.max_temperature;
+			yeastData.y_flocculation = datarecord.flocculation;
+			yeastData.y_attenuation = datarecord.attenuation;
+			yeastData.y_cells = datarecord.cells;
+			yeastData.y_inventory = datarecord.inventory;
+			if (yeastData.y_form == 0) {
 				$("#wy_pmpt_amount").html("Pak(ken):");
-			} else if (rowdata.y_form == 1) {
+			} else if (yeastData.y_form == 1) {
 				$("#wy_pmpt_amount").html("Gewicht gram:");
 			} else {
 				$("#wy_pmpt_amount").html("Volume ml:");
@@ -3481,12 +3559,11 @@
 	$("#wy_amount").jqxNumberInput( Spin1dec );
 	$('#wy_amount').on('change', function (event) {
 		console.log("amount changed: "+event.args.value);
-		var rowdata = $("#yeastGrid").jqxGrid('getrowdata', yeastRow);
-		if (rowdata.y_form == 0)	// Liquid
+		if (yeastData.y_form == 0)	// Liquid
 			var amount = parseFloat(event.args.value);
 		else
 			var amount = parseFloat(event.args.value) / 1000;
-		rowdata.y_amount = amount;
+		yeastData.y_amount = amount;
 		calcFermentables();
 	});
 	$("#wy_use").jqxDropDownList({
@@ -3502,8 +3579,7 @@
 	$("#wy_use").on('select', function (event) {
 		if (event.args) {
 			var index = event.args.index;
-			var rowdata = $("#yeastGrid").jqxGrid('getrowdata', yeastRow);
-			rowdata.y_use = index;
+			yeastData.y_use = index;
 			calcFermentabes();
 		}
 	});
@@ -3572,7 +3648,6 @@
 	});
 	$("#MashReady").jqxButton({ template: "success", width: '90px', theme: theme });
 	$("#MashReady").click(function () {
-		$("#mashGrid").jqxGrid('sortby', 'step_temp', 'asc');
 		calcMash();
 	});
 	$("#wstep_name").jqxInput({ theme: theme, width: 320, height: 23 });
--- a/www/prod_print.php	Tue Jun 04 16:38:53 2019 +0200
+++ b/www/prod_print.php	Tue Jun 04 19:50:06 2019 +0200
@@ -237,10 +237,10 @@
 			$total_hops += $amount;
 
 			$moment = $hopuse[$item['h_useat']];
-			if ($item['h_useat'] == 2) {    // Boil
-				$moment   = "Koken ".$time." min";
+			if (($item['h_useat'] == 2) || ($item['h_useat'] == 4)) {    // Boil or Whirlpool
+				$moment = $hopuse[$item['h_useat']].' '.$time." min";
 			} else if ($item['h_useat'] == 5) {	// Dryhop
-				$moment   = 'Koudhop '.sprintf("%.0f", $time / 1440).' dagen';
+				$moment = $hopuse[$item['h_useat']].' '.sprintf("%.0f", $time / 1440).' dagen';
 			}
 			$ibu = calc_IBU($item['h_useat'], $item['h_form'], $preboil_sg, floatval($row['batch_size']), $mass, $time, $alpha, $row['ibu_method']);
 			$total_ibus += $ibu;
@@ -734,9 +734,9 @@
 		$arr = json_decode($row['json_fermentables'], true);
 		foreach($arr as $item) {
 			if ($item['f_added'] == 0) {	// to mash
-				$s = sprintf("%.3f",floatval($item['f_amount'])).' kg ';
+				$s = sprintf("%.3f",floatval($item['f_amount'])).' kg `';
 				$s .= iconv('UTF-8','windows-1252',$item['f_name']);
-				$s .= ' ('.iconv('UTF-8','windows-1252',$item['f_supplier']).')';
+				$s .= '` ('.iconv('UTF-8','windows-1252',$item['f_supplier']).')';
 				$this->Checkline($s);
 			}
 		}
@@ -769,8 +769,16 @@
 					$hops = json_decode($row['json_hops'], true);
 					foreach($hops as $item2) {
 						if ($item2['h_useat'] == 0) {
-							$s = sprintf("%.1f",$item2['h_amount']*1000).' gr ';
-							$s .= iconv('UTF-8','windows-1252',$item2['h_name']).' toevoegen';
+							$s = sprintf("%.1f",$item2['h_amount']*1000).' gr `';
+							$s .= iconv('UTF-8','windows-1252',$item2['h_name']).'` toevoegen';
+							$this->Checkline($s);
+						}
+					}
+					$miscs = json_decode($row['json_miscs'], true);
+					foreach($miscs as $item3) {
+						if ($item3['m_use_use'] == 1 && $item3['m_type'] != 4) {	// Only if not a water agent
+							$s = sprintf("%.2f",$item3['m_amount']*1000).' gr `';
+							$s .= iconv('UTF-8','windows-1252',$item3['m_name']).'` toevoegen';
 							$this->Checkline($s);
 						}
 					}
@@ -827,8 +835,8 @@
 		$hops = json_decode($row['json_hops'], true);
 		foreach($hops as $item2) {
 			if ($item2['h_useat'] == 1) {
-				$s = sprintf("%.1f",$item2['h_amount']*1000).' gr ';
-				$s .= iconv('UTF-8','windows-1252',$item2['h_name']).' toevoegen na het spoelen';
+				$s = sprintf("%.1f",$item2['h_amount']*1000).' gr `';
+				$s .= iconv('UTF-8','windows-1252',$item2['h_name']).'` toevoegen na het spoelen';
 				$this->Checkline($s);
 			}
 		}
@@ -844,8 +852,8 @@
 				$ferms = json_decode($row['json_fermentables'], true);
 				foreach($ferms as $item1) {
 					if ($item1['f_added'] == 1) {
-						$s = sprintf("%.3f",$item1['f_amount']).' kg ';
-						$s .= iconv('UTF-8','windows-1252',$item1['f_name']).' bij 10 minuten voor einde koken';
+						$s = sprintf("%.3f",$item1['f_amount']).' kg `';
+						$s .= iconv('UTF-8','windows-1252',$item1['f_name']).'` bij 10 minuten voor einde koken';
 						$this->Checkline($s);
 					}
 				}
@@ -855,8 +863,8 @@
 			$hops = json_decode($row['json_hops'], true);
 			foreach($hops as $item2) {
 				if (($item2['h_useat'] == 2 || $item2['h_useat'] == 3) && ($item2['h_time'] == $i)) {
-					$s = sprintf("%.1f",$item2['h_amount']*1000).' gr ';
-					$s .= iconv('UTF-8','windows-1252',$item2['h_name']).' bij ';
+					$s = sprintf("%.1f",$item2['h_amount']*1000).' gr `';
+					$s .= iconv('UTF-8','windows-1252',$item2['h_name']).'` bij ';
 					if ($i > 0)
 						$s .= $i.' minuten voor einde koken';
 					else
@@ -867,8 +875,8 @@
 			$miscs = json_decode($row['json_miscs'], true);
 			foreach($miscs as $item3) {
 				if ($item3['m_use_use'] == 2 && $item3['m_time'] == $i) {
-					$s = sprintf("%.1f",$item3['m_amount']*1000).' gr ';
-					$s .= iconv('UTF-8','windows-1252',$item3['m_name']).' bij ';
+					$s = sprintf("%.1f",$item3['m_amount']*1000).' gr `';
+					$s .= iconv('UTF-8','windows-1252',$item3['m_name']).'` bij ';
 					if ($i > 0)
 						$s .= $i.' minuten voor einde koken';
 					else
@@ -904,6 +912,15 @@
 				$s = 'Whirlpool voor '.$row['brew_whirlpool6'].' min. Temperatuur tussen 60 en 66 '.DEG.'C houden';
 				$this->Checkline($s);
 			}
+			$hops = json_decode($row['json_hops'], true);
+			foreach($hops as $item2) {
+				if ($item2['h_useat'] == 4) {
+					$s = sprintf("%.1f",$item2['h_amount']*1000).' gr `';
+					$s .= iconv('UTF-8','windows-1252',$item2['h_name']).'` voor ';
+					$s .= $item2['h_time'].' minuten in de whirlpool';
+					$this->Checkline($s);
+				}
+			}
 			$this->Checkline('koelen tot '.sprintf("%.1f",$row['brew_cooling_to']).' '.DEG.'C');
 			if ($row['brew_whirlpool2'] > 0) {
 				$s = 'Whirlpool voor '.$row['brew_whirlpool2'].' min.';
--- a/www/rec_print.php	Tue Jun 04 16:38:53 2019 +0200
+++ b/www/rec_print.php	Tue Jun 04 19:50:06 2019 +0200
@@ -224,10 +224,10 @@
 			$total_hops += $amount;
 
 			$moment = $hopuse[$item['h_useat']];
-			if ($item['h_useat'] == 2) {	// Boil
-				$moment   = "Koken ".$time." min";
+			if (($item['h_useat'] == 2) || ($item['h_useat'] == 4)) {	// Boil or Whirlpool
+				$moment  = $hopuse[$item['h_useat']].' '.$time." min";
 			} else if ($item['h_useat'] == 5) {	// Dryhop
-				$moment   = 'Koudhop '.sprintf("%.0f", $time / 1440).' dagen';
+				$moment  = $hopuse[$item['h_useat']].' '.sprintf("%.0f", $time / 1440).' dagen';
 			}
 			$ibu = calc_IBU($item['h_useat'], $item['h_form'], $preboil_sg, floatval($row['batch_size']), $mass, $time, $alpha, $row['ibu_method']);
 			$total_ibus += $ibu;

mercurial