Recipe templates

Fractions of the total ingredients required can be mentioned in recipes. This can be helpful when, for example, only half of some ingredient is needed at the start of the recipe. The proper values are automatically calculated when the number of servings is adjusted.
This commit is contained in:
M-Byte 2020-10-04 23:02:01 +02:00
parent 4b5b7bcb19
commit 48e300bba6
4 changed files with 121 additions and 10 deletions

View File

@ -28,6 +28,9 @@ $('.save-recipe').on('click', function(e)
{ {
e.preventDefault(); e.preventDefault();
$(".note-editable span.ingredient").removeClass(["badge", "btn", "btn-secondary"]);
$("#description").text($("#description").siblings(".note-editor").find(".note-editable").html());
var jsonData = $('#recipe-form').serializeJSON(); var jsonData = $('#recipe-form').serializeJSON();
Grocy.FrontendHelpers.BeginUiBusy("recipe-form"); Grocy.FrontendHelpers.BeginUiBusy("recipe-form");
@ -230,6 +233,62 @@ $(document).on('click', '.recipe-pos-edit-button', function(e)
}); });
}); });
$(document).on('click', '.recipe-pos-insert-button', function(e)
{
e.preventDefault();
var recipePosId = $(e.currentTarget).attr('data-recipe-pos-id').toString();
var recipePosName = $(e.currentTarget).attr('data-recipe-pos-name').toString();
var recipePosAmount = parseFloat($(e.currentTarget).attr('data-recipe-pos-amount').toString());
var recipePosQu = $(e.currentTarget).attr('data-recipe-pos-qu').toString();
var recipePosQuPlural = $(e.currentTarget).attr('data-recipe-pos-qu-plural').toString();
var range = $.summernote.range.create();
bootbox.dialog({
message: '<div>Factor?</div><input type="number" class="form-control" value="1" min="0" max="1">',
size: 'large',
backdrop: true,
closeButton: false,
buttons: {
cancel: {
label: __t('Cancel'),
className: 'btn-secondary responsive-button',
callback: function()
{
bootbox.hideAll();
}
},
ok: {
label: __t('Insert'),
className: 'btn-success responsive-button',
callback: function(e)
{
var factor = $(e.delegateTarget).find('input').val();
var amount = parseFloat(factor) * recipePosAmount;
amount = amount.toFixed(2).replace(/([0-9]+(\.[0-9]+[1-9])?)(\.?0+$)/,'$1');
var html = '&nbsp;<span class="ingredient" data-ingredient-id="' + recipePosId + '" data-ingredient-factor="' + factor + '">' + [amount, __n(amount, recipePosQu, recipePosQuPlural), recipePosName].join(' ') + '</span>&nbsp;';
if (range.so !== range.eo || range.sc !== range.ec)
{
range.deleteContents();
range = $.summernote.range.create();
var check = range.getWordRange(true);
if (check.toString().trim().length === 0)
check.deleteContents();
check = range.getWordRange(false);
if (check.toString().trim().length === 0)
check.deleteContents();
range = $.summernote.range.create();
}
range.pasteHTML(html);
updateIngredientTags();
bootbox.hideAll();
$("#description").summernote('focus');
}
}
}
});
});
$(document).on('click', '.recipe-include-edit-button', function(e) $(document).on('click', '.recipe-include-edit-button', function(e)
{ {
var id = $(e.currentTarget).attr('data-recipe-include-id'); var id = $(e.currentTarget).attr('data-recipe-include-id');
@ -379,6 +438,19 @@ $(window).on("message", function(e)
} }
}); });
function updateIngredientTags()
{
$("#description").siblings(".note-editable").find("span.ingredient").not(".badge").addClass(["badge", "btn", "btn-secondary"]).on("click", function(evt)
{
$.summernote.range.createFromNode(evt.target).select();
});
}
$(".wysiwyg-editor").on("summernote.init", function()
{
updateIngredientTags();
});
updateIngredientTags();
// Grocy.Components.RecipePicker.GetPicker().on('change', function (e) // Grocy.Components.RecipePicker.GetPicker().on('change', function (e)
// { // {
// var value = Grocy.Components.RecipePicker.GetValue(); // var value = Grocy.Components.RecipePicker.GetValue();

View File

@ -37,6 +37,35 @@ if (typeof recipe !== "undefined")
// Scroll to recipe card on mobile // Scroll to recipe card on mobile
$("#selectedRecipeCard")[0].scrollIntoView(); $("#selectedRecipeCard")[0].scrollIntoView();
} }
$("#selectedRecipeCard .ingredient").each(function(id, element)
{
var data = $(element).closest(".tab-pane").data("ingredients");
if (!data)
{
$(element).text('<???>');
return;
}
var ingredient = FindObjectInArrayByPropertyValue(data.recipePositions, 'recipe_pos_id', element.dataset.ingredientId);
if (!ingredient)
{
$(element).text('<???>');
}
var product = FindObjectInArrayByPropertyValue(data.products, 'id', ingredient.product_id);
var amount = ingredient.recipe_amount;
if (element.dataset.ingredientFactor && parseFloat(element.dataset.ingredientFactor))
{
amount *= parseFloat(element.dataset.ingredientFactor);
}
amount = amount.toFixed(2).replace(/([0-9]+(\.[0-9]+[1-9])?)(\.?0+$)/,'$1');
var qu = FindObjectInArrayByPropertyValue(data.quantityUnits, 'id', ingredient.qu_id);
if (!qu || !product)
{
$(element).text('<???>');
return;
}
$(element).text([amount, __n(amount, qu.name, qu.name_plural), product.name].join(' '));
});
} }
if (GetUriParam("search") !== undefined) if (GetUriParam("search") !== undefined)

View File

@ -192,6 +192,16 @@
@if($mode == "edit") @if($mode == "edit")
@foreach($recipePositions as $recipePosition) @foreach($recipePositions as $recipePosition)
<tr> <tr>
@php
$product = FindObjectInArrayByPropertyValue($products, 'id', $recipePosition->product_id);
$productQuConversions = FindAllObjectsInArrayByPropertyValue($quantityUnitConversionsResolved, 'product_id', $product->id);
$productQuConversions = FindAllObjectsInArrayByPropertyValue($productQuConversions, 'from_qu_id', $product->qu_id_stock);
$productQuConversion = FindObjectInArrayByPropertyValue($productQuConversions, 'to_qu_id', $recipePosition->qu_id);
if ($productQuConversion)
{
$recipePosition->amount = $recipePosition->amount * $productQuConversion->factor;
}
@endphp
<td class="fit-content border-right"> <td class="fit-content border-right">
<a class="btn btn-sm btn-info recipe-pos-edit-button" <a class="btn btn-sm btn-info recipe-pos-edit-button"
type="button" type="button"
@ -200,6 +210,15 @@
data-product-id="{{ $recipePosition->product_id }}"> data-product-id="{{ $recipePosition->product_id }}">
<i class="fas fa-edit"></i> <i class="fas fa-edit"></i>
</a> </a>
<a class="btn btn-sm btn-info recipe-pos-insert-button"
href="#"
data-recipe-pos-id="{{ $recipePosition->id }}"
data-recipe-pos-name="{{ FindObjectInArrayByPropertyValue($products, 'id', $recipePosition->product_id)->name }}"
data-recipe-pos-amount="{{ $recipePosition->amount }}"
data-recipe-pos-qu="{{ FindObjectInArrayByPropertyValue($quantityunits, 'id', $recipePosition->qu_id)->name }}"
data-recipe-pos-qu-plural="{{ FindObjectInArrayByPropertyValue($quantityunits, 'id', $recipePosition->qu_id)->name_plural }}">
<i class="fas fa-map-marker"></i>
</a>
<a class="btn btn-sm btn-danger recipe-pos-delete-button" <a class="btn btn-sm btn-danger recipe-pos-delete-button"
href="#" href="#"
data-recipe-pos-id="{{ $recipePosition->id }}" data-recipe-pos-id="{{ $recipePosition->id }}"
@ -211,16 +230,6 @@
{{ FindObjectInArrayByPropertyValue($products, 'id', $recipePosition->product_id)->name }} {{ FindObjectInArrayByPropertyValue($products, 'id', $recipePosition->product_id)->name }}
</td> </td>
<td> <td>
@php
$product = FindObjectInArrayByPropertyValue($products, 'id', $recipePosition->product_id);
$productQuConversions = FindAllObjectsInArrayByPropertyValue($quantityUnitConversionsResolved, 'product_id', $product->id);
$productQuConversions = FindAllObjectsInArrayByPropertyValue($productQuConversions, 'from_qu_id', $product->qu_id_stock);
$productQuConversion = FindObjectInArrayByPropertyValue($productQuConversions, 'to_qu_id', $recipePosition->qu_id);
if ($productQuConversion)
{
$recipePosition->amount = $recipePosition->amount * $productQuConversion->factor;
}
@endphp
@if(!empty($recipePosition->variable_amount)) @if(!empty($recipePosition->variable_amount))
{{ $recipePosition->variable_amount }} {{ $recipePosition->variable_amount }}
@else @else

View File

@ -394,6 +394,7 @@
@endif @endif
<div class="tab-pane @if(count($recipePositionsFiltered) == 0) active @endif" <div class="tab-pane @if(count($recipePositionsFiltered) == 0) active @endif"
id="prep-{{ $index }}" id="prep-{{ $index }}"
data-ingredients="{{ json_encode(array('recipePositions' => $recipePositionsFiltered, 'products' => $products, 'quantityUnits' => $quantityUnits)) }}"
role="tabpanel"> role="tabpanel">
<div class="mb-2 d-none d-print-block"> <div class="mb-2 d-none d-print-block">
<h3 class="mb-0">{{ $__t('Preparation') }}</h3> <h3 class="mb-0">{{ $__t('Preparation') }}</h3>