Squashed commit

Make it possible to actively not-check a mandatory checkbox Userfield (closes #2601)
Pluralize the "opened" localization string (closes #2280)
Added a trendline to the price history chart (closes #2237)
Various minor style/code refinements
This commit is contained in:
Bernd Bestel
2025-01-14 17:54:06 +01:00
parent c99dd46007
commit 11d28622e8
32 changed files with 134 additions and 86 deletions

View File

@@ -37,30 +37,29 @@ Grocy.Components.CameraBarcodeScanner.CheckCapabilities = async function()
var hasTorch = typeof capabilities.torch === 'boolean' && capabilities.torch;
// Remove the torch button if the select camera doesn't have a torch
var button = document.querySelector('.torch');
if (!hasTorch)
{
button.classList.add('disabled');
document.querySelector('.camerabarcodescanner-modal .modal-footer').setAttribute('style', 'display:none !important;');
}
else
{
button.classList.remove('disabled');
document.querySelector('.camerabarcodescanner-modal .modal-footer').setAttribute('style', 'flex;');
}
// Reduce the height of the video, if it's higher than then the viewport
if (!Grocy.Components.CameraBarcodeScanner.LiveVideoSizeAdjusted)
{
var bc = document.getElementById('barcodescanner-container');
var bc = document.getElementById('camerabarcodescanner-container');
if (bc)
{
var bcAspectRatio = bc.offsetWidth / bc.offsetHeight;
var settings = track.getSettings();
if (bcAspectRatio > settings.aspectRatio)
{
var v = document.querySelector('#barcodescanner-livestream video');
var v = document.querySelector('#camerabarcodescanner-livestream video');
if (v)
{
var c = document.querySelector('#barcodescanner-livestream canvas')
var c = document.querySelector('#camerabarcodescanner-livestream canvas')
var newWidth = v.clientWidth / bcAspectRatio * settings.aspectRatio + 'px';
v.style.width = newWidth;
c.style.width = newWidth;
@@ -81,7 +80,7 @@ Grocy.Components.CameraBarcodeScanner.StartScanning = function()
inputStream: {
name: "Live",
type: "LiveStream",
target: document.querySelector("#barcodescanner-livestream"),
target: document.querySelector("#camerabarcodescanner-livestream"),
constraints: {
facingMode: "environment",
...(window.localStorage.getItem('cameraId') && { deviceId: window.localStorage.getItem('cameraId') }), // If preferred cameraId is set, request to use that specific camera
@@ -234,7 +233,7 @@ Quagga.onProcessed(function(result)
}
});
$(document).on("click", "#barcodescanner-start-button", async function(e)
$(document).on("click", "#camerabarcodescanner-start-button", async function(e)
{
e.preventDefault();
var inputElement = $(e.currentTarget).prev();
@@ -248,12 +247,12 @@ $(document).on("click", "#barcodescanner-start-button", async function(e)
Grocy.Components.CameraBarcodeScanner.CurrentTarget = inputElement.attr("data-target");
var dialog = bootbox.dialog({
message: '<div id="barcodescanner-container" class="col"><div id="barcodescanner-livestream"></div></div>',
message: '<div id="camerabarcodescanner-container" class="col"><div id="camerabarcodescanner-livestream"></div></div>',
title: __t('Scan a barcode'),
size: 'large',
backdrop: true,
closeButton: true,
className: "form",
className: "form camerabarcodescanner-modal",
buttons: {
torch: {
label: '<i class="fa-solid fa-lightbulb"></i>',
@@ -296,11 +295,11 @@ Grocy.Components.CameraBarcodeScanner.Init = function()
{
if ($(this).hasAttr("disabled"))
{
$(this).after('<a id="barcodescanner-start-button" class="btn btn-sm btn-primary text-white disabled" data-target="' + $(this).attr("data-target") + '"><i class="fa-solid fa-camera"></i></a>');
$(this).after('<a id="camerabarcodescanner-start-button" class="btn btn-sm btn-primary text-white disabled" data-target="' + $(this).attr("data-target") + '"><i class="fa-solid fa-camera"></i></a>');
}
else
{
$(this).after('<a id="barcodescanner-start-button" class="btn btn-sm btn-primary text-white" data-target="' + $(this).attr("data-target") + '"><i class="fa-solid fa-camera"></i></a>');
$(this).after('<a id="camerabarcodescanner-start-button" class="btn btn-sm btn-primary text-white" data-target="' + $(this).attr("data-target") + '"><i class="fa-solid fa-camera"></i></a>');
}
Grocy.Components.CameraBarcodeScanner.InitDone = true;

View File

@@ -136,7 +136,10 @@ Grocy.Components.ProductCard.Refresh = function(productId)
$("#productcard-no-price-data-hint").addClass("d-none");
Grocy.Components.ProductCard.ReInitPriceHistoryChart();
var datasets = {};
datasets["_TrendlineDataset"] = []
var chart = Grocy.Components.ProductCard.PriceHistoryChart.data;
priceHistoryDataPoints.forEach((dataPoint) =>
{
@@ -150,18 +153,41 @@ Grocy.Components.ProductCard.Refresh = function(productId)
{
datasets[key] = []
}
chart.labels.push(moment(dataPoint.date).toDate());
datasets[key].push({ x: moment(dataPoint.date).toDate(), y: dataPoint.price * productDetails.qu_conversion_factor_price_to_stock });
datasets["_TrendlineDataset"].push({ x: moment(dataPoint.date).toDate(), y: dataPoint.price * productDetails.qu_conversion_factor_price_to_stock });
});
Object.keys(datasets).forEach((key) =>
{
chart.datasets.push({
data: datasets[key],
fill: false,
borderColor: "HSL(" + (129 * chart.datasets.length) + ",100%,50%)",
label: key,
});
if (key != "_TrendlineDataset")
{
chart.datasets.push({
data: datasets[key],
fill: false,
borderColor: "HSL(" + (129 * chart.datasets.length) + ",100%,50%)",
label: key
});
}
else
{
chart.datasets.push({
data: datasets[key],
fill: false,
borderColor: "HSL(" + (129 * chart.datasets.length) + ",100%,50%)",
label: key,
hidden: true,
alwaysShowTrendline: true,
trendlineLinear: {
colorMin: "rgba(0, 0, 0, 0.3)",
colorMax: "rgba(0, 0, 0, 0.3)",
lineStyle: "dotted",
width: 3
}
});
}
});
Grocy.Components.ProductCard.PriceHistoryChart.update();
@@ -234,7 +260,13 @@ Grocy.Components.ProductCard.ReInitPriceHistoryChart = function()
}]
},
legend: {
display: true
display: true,
labels: {
filter: function(item, chart)
{
return item.text != "_TrendlineDataset";
}
}
},
tooltips: {
callbacks: {

View File

@@ -76,15 +76,15 @@ Grocy.Components.ProductPicker.HideCustomError = function()
Grocy.Components.ProductPicker.Disable = function()
{
Grocy.Components.ProductPicker.GetInputElement().attr("disabled", "");
$("#barcodescanner-start-button").attr("disabled", "");
$("#barcodescanner-start-button").addClass("disabled");
$("#camerabarcodescanner-start-button").attr("disabled", "");
$("#camerabarcodescanner-start-button").addClass("disabled");
}
Grocy.Components.ProductPicker.Enable = function()
{
Grocy.Components.ProductPicker.GetInputElement().removeAttr("disabled");
$("#barcodescanner-start-button").removeAttr("disabled");
$("#barcodescanner-start-button").removeClass("disabled");
$("#camerabarcodescanner-start-button").removeAttr("disabled");
$("#camerabarcodescanner-start-button").removeClass("disabled");
}
$('.product-combobox').combobox({
@@ -295,7 +295,7 @@ $('#product_id_text_input').on('blur', function(e)
{
Grocy.Components.ProductPicker.PopupOpen = false;
Grocy.Components.ProductPicker.SetValue('');
$("#barcodescanner-start-button").click();
$("#camerabarcodescanner-start-button").click();
}
};
}

View File

@@ -182,11 +182,19 @@ Grocy.Components.UserfieldsForm.Load = function()
if (userfield.type == "datetime" && userfield.default_value == "now")
{
input.val(moment().format("YYYY-MM-DD HH:mm:ss"))
input.val(moment().format("YYYY-MM-DD HH:mm:ss"));
}
else if (userfield.type == "date" && userfield.default_value == "now")
{
input.val(moment().format("YYYY-MM-DD"))
input.val(moment().format("YYYY-MM-DD"));
}
else if (userfield.type == "checkbox" && userfield.input_required == 1)
{
input.prop("indeterminate", true);
input.on("change", function()
{
input.removeAttr("required");
});
}
});
@@ -212,6 +220,12 @@ Grocy.Components.UserfieldsForm.Load = function()
{
var input = $(".userfield-input[data-userfield-name='" + key + "']");
if (input.attr("type") == "checkbox")
{
// The required attribute for checkboxes is only relevant when creating objects
input.removeAttr("required");
}
if (input.attr("type") == "checkbox" && value == 1)
{
input.prop("checked", true);