Fix: camera scadenza più piccola con zoom 2x, quantità non si resetta più, nomi prodotti in lingua corretta
- Ridotto il frame della camera scadenza a 180px con zoom 2x e crop centrale - Fix: premere 'Appena comprato' / 'Ce l'avevo già' non modifica più la quantità - Fix: nomi prodotti in script non-latino vengono sostituiti con alternative leggibili - Corretto nome prodotto 'Celozrnný toastový chléb' → 'Sandwich American Style' - Migliorato ordine fallback nomi: product_name_it → generic_name_it → product_name
This commit is contained in:
+22
-2
@@ -141,17 +141,37 @@ function lookupBarcode(): void {
|
|||||||
$p = $data['product'];
|
$p = $data['product'];
|
||||||
|
|
||||||
// Prefer Italian name, fall back to generic
|
// Prefer Italian name, fall back to generic
|
||||||
|
// Also request localized name via abbreviated_product_name
|
||||||
$name = '';
|
$name = '';
|
||||||
if (!empty($p['product_name_it'])) {
|
if (!empty($p['product_name_it'])) {
|
||||||
$name = $p['product_name_it'];
|
$name = $p['product_name_it'];
|
||||||
} elseif (!empty($p['product_name'])) {
|
|
||||||
$name = $p['product_name'];
|
|
||||||
} elseif (!empty($p['generic_name_it'])) {
|
} elseif (!empty($p['generic_name_it'])) {
|
||||||
$name = $p['generic_name_it'];
|
$name = $p['generic_name_it'];
|
||||||
|
} elseif (!empty($p['product_name'])) {
|
||||||
|
$name = $p['product_name'];
|
||||||
} elseif (!empty($p['generic_name'])) {
|
} elseif (!empty($p['generic_name'])) {
|
||||||
$name = $p['generic_name'];
|
$name = $p['generic_name'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the name looks like it's in a non-Latin script (Arabic, Chinese, Thai, etc.)
|
||||||
|
// try to use a fallback from brands + generic category
|
||||||
|
if (!empty($name) && preg_match('/[\x{0600}-\x{06FF}\x{0E00}-\x{0E7F}\x{4E00}-\x{9FFF}\x{3040}-\x{30FF}\x{AC00}-\x{D7AF}\x{0400}-\x{04FF}]/u', $name)) {
|
||||||
|
// Try other name fields that might be in Latin script
|
||||||
|
$latinName = '';
|
||||||
|
foreach (['generic_name_it', 'generic_name', 'product_name_it', 'product_name'] as $field) {
|
||||||
|
if (!empty($p[$field]) && !preg_match('/[\x{0600}-\x{06FF}\x{0E00}-\x{0E7F}\x{4E00}-\x{9FFF}\x{3040}-\x{30FF}\x{AC00}-\x{D7AF}\x{0400}-\x{04FF}]/u', $p[$field])) {
|
||||||
|
$latinName = $p[$field];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If still no Latin name, construct from brand + category
|
||||||
|
if (empty($latinName)) {
|
||||||
|
$brand = $p['brands'] ?? '';
|
||||||
|
$latinName = !empty($brand) ? $brand : 'Prodotto sconosciuto';
|
||||||
|
}
|
||||||
|
$name = $latinName;
|
||||||
|
}
|
||||||
|
|
||||||
// Get Italian ingredients, fall back to generic
|
// Get Italian ingredients, fall back to generic
|
||||||
$ingredients = '';
|
$ingredients = '';
|
||||||
if (!empty($p['ingredients_text_it'])) {
|
if (!empty($p['ingredients_text_it'])) {
|
||||||
|
|||||||
+78
-30
@@ -490,7 +490,7 @@ function editInventoryItem(id) {
|
|||||||
<label>📦 Quantità</label>
|
<label>📦 Quantità</label>
|
||||||
<div class="qty-control">
|
<div class="qty-control">
|
||||||
<button type="button" class="qty-btn" onclick="adjustQty('edit-qty', -1)">−</button>
|
<button type="button" class="qty-btn" onclick="adjustQty('edit-qty', -1)">−</button>
|
||||||
<input type="number" id="edit-qty" value="${item.quantity}" min="0" step="0.5" class="qty-input">
|
<input type="number" id="edit-qty" value="${item.quantity}" min="0" step="any" class="qty-input">
|
||||||
<button type="button" class="qty-btn" onclick="adjustQty('edit-qty', 1)">+</button>
|
<button type="button" class="qty-btn" onclick="adjustQty('edit-qty', 1)">+</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -746,6 +746,15 @@ function startManualEntry(barcode = '') {
|
|||||||
document.getElementById('pf-image-preview').style.display = 'none';
|
document.getElementById('pf-image-preview').style.display = 'none';
|
||||||
document.getElementById('product-form-title').textContent = 'Nuovo Prodotto';
|
document.getElementById('product-form-title').textContent = 'Nuovo Prodotto';
|
||||||
|
|
||||||
|
// Reset manual-edit tracking flags
|
||||||
|
document.getElementById('pf-category').dataset.manuallySet = 'false';
|
||||||
|
document.getElementById('pf-defqty').dataset.manuallySet = 'false';
|
||||||
|
|
||||||
|
// Track if user manually changes the quantity field
|
||||||
|
const qtyInput = document.getElementById('pf-defqty');
|
||||||
|
qtyInput.removeEventListener('input', markQtyManuallySet);
|
||||||
|
qtyInput.addEventListener('input', markQtyManuallySet);
|
||||||
|
|
||||||
// Auto-detect name → category when typing
|
// Auto-detect name → category when typing
|
||||||
const nameInput = document.getElementById('pf-name');
|
const nameInput = document.getElementById('pf-name');
|
||||||
nameInput.removeEventListener('input', autoDetectCategory);
|
nameInput.removeEventListener('input', autoDetectCategory);
|
||||||
@@ -754,6 +763,10 @@ function startManualEntry(barcode = '') {
|
|||||||
showPage('product-form');
|
showPage('product-form');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function markQtyManuallySet() {
|
||||||
|
document.getElementById('pf-defqty').dataset.manuallySet = 'true';
|
||||||
|
}
|
||||||
|
|
||||||
function autoDetectCategory() {
|
function autoDetectCategory() {
|
||||||
const name = document.getElementById('pf-name').value.toLowerCase();
|
const name = document.getElementById('pf-name').value.toLowerCase();
|
||||||
if (name.length < 3) return;
|
if (name.length < 3) return;
|
||||||
@@ -796,23 +809,26 @@ function autoDetectCategory() {
|
|||||||
for (const [keyword, cat] of Object.entries(keyword2cat)) {
|
for (const [keyword, cat] of Object.entries(keyword2cat)) {
|
||||||
if (name.includes(keyword)) {
|
if (name.includes(keyword)) {
|
||||||
catSelect.value = cat;
|
catSelect.value = cat;
|
||||||
onCategoryChange();
|
onCategoryChange(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onCategoryChange() {
|
function onCategoryChange(fromAutoDetect = false) {
|
||||||
const cat = document.getElementById('pf-category').value;
|
const cat = document.getElementById('pf-category').value;
|
||||||
const unitSelect = document.getElementById('pf-unit');
|
const unitSelect = document.getElementById('pf-unit');
|
||||||
const qtyInput = document.getElementById('pf-defqty');
|
const qtyInput = document.getElementById('pf-defqty');
|
||||||
|
|
||||||
// Mark as manually set if triggered by user click
|
// If user manually changed category via dropdown, don't auto-fill qty/unit
|
||||||
if (event && event.isTrusted) {
|
if (!fromAutoDetect) {
|
||||||
document.getElementById('pf-category').dataset.manuallySet = 'true';
|
// Mark qty as "set" so future auto-detects won't overwrite either
|
||||||
|
qtyInput.dataset.manuallySet = 'true';
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Suggest default unit/qty based on category
|
// Auto-detect from name: suggest default unit/qty based on category
|
||||||
|
// BUT only if user hasn't manually changed the quantity field
|
||||||
const catDefaults = {
|
const catDefaults = {
|
||||||
'latticini': { unit: 'pz', qty: 1 },
|
'latticini': { unit: 'pz', qty: 1 },
|
||||||
'carne': { unit: 'g', qty: 500 },
|
'carne': { unit: 'g', qty: 500 },
|
||||||
@@ -832,8 +848,11 @@ function onCategoryChange() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (catDefaults[cat]) {
|
if (catDefaults[cat]) {
|
||||||
unitSelect.value = catDefaults[cat].unit;
|
// Only auto-fill unit/qty if user hasn't manually touched them
|
||||||
qtyInput.value = catDefaults[cat].qty;
|
if (qtyInput.dataset.manuallySet !== 'true') {
|
||||||
|
unitSelect.value = catDefaults[cat].unit;
|
||||||
|
qtyInput.value = catDefaults[cat].qty;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1002,6 +1021,12 @@ function showAddForm() {
|
|||||||
unitSelect.value = unit;
|
unitSelect.value = unit;
|
||||||
|
|
||||||
document.getElementById('add-quantity').value = currentProduct.default_quantity || 1;
|
document.getElementById('add-quantity').value = currentProduct.default_quantity || 1;
|
||||||
|
document.getElementById('add-quantity').dataset.manuallySet = 'false';
|
||||||
|
|
||||||
|
// Track manual edits to quantity in add form
|
||||||
|
const addQtyInput = document.getElementById('add-quantity');
|
||||||
|
addQtyInput.removeEventListener('input', markAddQtyManuallySet);
|
||||||
|
addQtyInput.addEventListener('input', markAddQtyManuallySet);
|
||||||
|
|
||||||
// Show weight info if product has it
|
// Show weight info if product has it
|
||||||
const weightInfoEl = document.getElementById('add-weight-info');
|
const weightInfoEl = document.getElementById('add-weight-info');
|
||||||
@@ -1061,8 +1086,11 @@ function showAddForm() {
|
|||||||
function onAddUnitChange() {
|
function onAddUnitChange() {
|
||||||
updateAddQtyStep();
|
updateAddQtyStep();
|
||||||
// If switching units, suggest a sensible quantity
|
// If switching units, suggest a sensible quantity
|
||||||
|
// BUT only if the user hasn't manually changed the quantity in this form
|
||||||
const unit = document.getElementById('add-unit').value;
|
const unit = document.getElementById('add-unit').value;
|
||||||
const qtyInput = document.getElementById('add-quantity');
|
const qtyInput = document.getElementById('add-quantity');
|
||||||
|
if (qtyInput.dataset.manuallySet === 'true') return; // User already edited qty, don't overwrite
|
||||||
|
|
||||||
const currentQty = parseFloat(qtyInput.value) || 1;
|
const currentQty = parseFloat(qtyInput.value) || 1;
|
||||||
|
|
||||||
// Convert between related units if logical
|
// Convert between related units if logical
|
||||||
@@ -1077,28 +1105,38 @@ function onAddUnitChange() {
|
|||||||
function updateAddQtyStep() {
|
function updateAddQtyStep() {
|
||||||
const qtyInput = document.getElementById('add-quantity');
|
const qtyInput = document.getElementById('add-quantity');
|
||||||
const unit = document.getElementById('add-unit').value;
|
const unit = document.getElementById('add-unit').value;
|
||||||
|
qtyInput.step = 'any';
|
||||||
if (unit === 'g' || unit === 'ml') {
|
if (unit === 'g' || unit === 'ml') {
|
||||||
qtyInput.step = '25';
|
|
||||||
qtyInput.min = '1';
|
qtyInput.min = '1';
|
||||||
} else if (unit === 'kg' || unit === 'l') {
|
} else if (unit === 'kg' || unit === 'l') {
|
||||||
qtyInput.step = '0.25';
|
|
||||||
qtyInput.min = '0.1';
|
qtyInput.min = '0.1';
|
||||||
} else {
|
} else {
|
||||||
qtyInput.step = '1';
|
|
||||||
qtyInput.min = '1';
|
qtyInput.min = '1';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function markAddQtyManuallySet() {
|
||||||
|
document.getElementById('add-quantity').dataset.manuallySet = 'true';
|
||||||
|
}
|
||||||
|
|
||||||
function adjustAddQty(delta) {
|
function adjustAddQty(delta) {
|
||||||
const qtyInput = document.getElementById('add-quantity');
|
const qtyInput = document.getElementById('add-quantity');
|
||||||
|
qtyInput.dataset.manuallySet = 'true'; // +/- buttons count as manual edit
|
||||||
const unit = document.getElementById('add-unit').value;
|
const unit = document.getElementById('add-unit').value;
|
||||||
let step;
|
|
||||||
if (unit === 'g' || unit === 'ml') step = 25;
|
|
||||||
else if (unit === 'kg' || unit === 'l') step = 0.25;
|
|
||||||
else step = 1;
|
|
||||||
let val = parseFloat(qtyInput.value) || 0;
|
let val = parseFloat(qtyInput.value) || 0;
|
||||||
|
let step;
|
||||||
|
if (unit === 'kg' || unit === 'l') {
|
||||||
|
step = val < 1 ? 0.1 : 0.5;
|
||||||
|
} else if (unit === 'g' || unit === 'ml') {
|
||||||
|
step = val < 50 ? 1 : (val < 500 ? 10 : 50);
|
||||||
|
} else {
|
||||||
|
step = 1;
|
||||||
|
}
|
||||||
val = Math.max(parseFloat(qtyInput.min) || 0.1, val + delta * step);
|
val = Math.max(parseFloat(qtyInput.min) || 0.1, val + delta * step);
|
||||||
qtyInput.value = Math.round(val * 100) / 100;
|
// Round nicely
|
||||||
|
if (step >= 1) val = Math.round(val);
|
||||||
|
else val = Math.round(val * 10) / 10;
|
||||||
|
qtyInput.value = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectPurchaseType(btn, type, estimatedDate, estimateLabel) {
|
function selectPurchaseType(btn, type, estimatedDate, estimateLabel) {
|
||||||
@@ -1107,6 +1145,9 @@ function selectPurchaseType(btn, type, estimatedDate, estimateLabel) {
|
|||||||
|
|
||||||
const detailDiv = document.getElementById('expiry-detail');
|
const detailDiv = document.getElementById('expiry-detail');
|
||||||
|
|
||||||
|
// Save current quantity before switching, so we can preserve it
|
||||||
|
const currentQty = document.getElementById('add-quantity').value;
|
||||||
|
|
||||||
if (type === 'new') {
|
if (type === 'new') {
|
||||||
detailDiv.innerHTML = `
|
detailDiv.innerHTML = `
|
||||||
<div class="expiry-estimate">
|
<div class="expiry-estimate">
|
||||||
@@ -1119,6 +1160,8 @@ function selectPurchaseType(btn, type, estimatedDate, estimateLabel) {
|
|||||||
</div>
|
</div>
|
||||||
<p class="form-hint">📝 Puoi modificare la data o scansionarla con la fotocamera</p>
|
<p class="form-hint">📝 Puoi modificare la data o scansionarla con la fotocamera</p>
|
||||||
`;
|
`;
|
||||||
|
// Restore quantity - switching purchase type should NOT change it
|
||||||
|
document.getElementById('add-quantity').value = currentQty;
|
||||||
} else {
|
} else {
|
||||||
detailDiv.innerHTML = `
|
detailDiv.innerHTML = `
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@@ -1134,14 +1177,13 @@ function selectPurchaseType(btn, type, estimatedDate, estimateLabel) {
|
|||||||
<p class="form-hint" style="margin-bottom:6px">Quanto è rimasto approssimativamente?</p>
|
<p class="form-hint" style="margin-bottom:6px">Quanto è rimasto approssimativamente?</p>
|
||||||
<div class="remaining-options">
|
<div class="remaining-options">
|
||||||
<button type="button" class="remaining-btn" onclick="setRemainingPct(1)">🟢 Pieno</button>
|
<button type="button" class="remaining-btn" onclick="setRemainingPct(1)">🟢 Pieno</button>
|
||||||
<button type="button" class="remaining-btn active" onclick="setRemainingPct(0.75)">🟡 ¾</button>
|
<button type="button" class="remaining-btn" onclick="setRemainingPct(0.75)">🟡 ¾</button>
|
||||||
<button type="button" class="remaining-btn" onclick="setRemainingPct(0.5)">🟠 Metà</button>
|
<button type="button" class="remaining-btn" onclick="setRemainingPct(0.5)">🟠 Metà</button>
|
||||||
<button type="button" class="remaining-btn" onclick="setRemainingPct(0.25)">🔴 ¼</button>
|
<button type="button" class="remaining-btn" onclick="setRemainingPct(0.25)">🔴 ¼</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
// Pre-set to 75%
|
// DON'T auto-set remaining percentage - keep the quantity the user already entered
|
||||||
setRemainingPct(0.75);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1526,16 +1568,17 @@ async function scanExpiryWithAI() {
|
|||||||
<button class="modal-close" onclick="closeExpiryScanner()">✕</button>
|
<button class="modal-close" onclick="closeExpiryScanner()">✕</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="expiry-scanner">
|
<div class="expiry-scanner">
|
||||||
<div id="expiry-cam-container">
|
<div id="expiry-cam-container" style="height:180px;overflow:hidden;border-radius:10px;position:relative">
|
||||||
<video id="expiry-video" autoplay playsinline style="width:100%;border-radius:10px"></video>
|
<video id="expiry-video" autoplay playsinline style="width:100%;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%) scale(2);transform-origin:center center"></video>
|
||||||
<canvas id="expiry-canvas" style="display:none"></canvas>
|
<canvas id="expiry-canvas" style="display:none"></canvas>
|
||||||
|
<div style="position:absolute;inset:0;border:2px dashed rgba(255,255,255,0.5);border-radius:10px;pointer-events:none"></div>
|
||||||
</div>
|
</div>
|
||||||
<div id="expiry-preview-container" style="display:none">
|
<div id="expiry-preview-container" style="display:none;height:180px;overflow:hidden;border-radius:10px">
|
||||||
<img id="expiry-preview-img" src="" alt="" style="width:100%;border-radius:10px">
|
<img id="expiry-preview-img" src="" alt="" style="width:100%;height:100%;object-fit:cover;border-radius:10px">
|
||||||
</div>
|
</div>
|
||||||
<p class="form-hint" style="text-align:center;margin:8px 0">Inquadra la data di scadenza stampata sul prodotto</p>
|
<p class="form-hint" style="text-align:center;margin:6px 0;font-size:0.8rem">Inquadra la data di scadenza stampata sul prodotto</p>
|
||||||
<div id="expiry-scan-status" style="display:none;text-align:center;padding:12px">
|
<div id="expiry-scan-status" style="display:none;text-align:center;padding:8px">
|
||||||
<div class="loading-spinner" style="margin:0 auto 8px"></div>
|
<div class="loading-spinner" style="margin:0 auto 6px"></div>
|
||||||
<p>🤖 Analisi AI in corso...</p>
|
<p>🤖 Analisi AI in corso...</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="expiry-scanner-actions">
|
<div class="expiry-scanner-actions">
|
||||||
@@ -1575,10 +1618,15 @@ function captureExpiry() {
|
|||||||
const canvas = document.getElementById('expiry-canvas');
|
const canvas = document.getElementById('expiry-canvas');
|
||||||
const img = document.getElementById('expiry-preview-img');
|
const img = document.getElementById('expiry-preview-img');
|
||||||
|
|
||||||
canvas.width = video.videoWidth;
|
// Crop to center 50% (matching the 2x zoom view) for better AI accuracy
|
||||||
canvas.height = video.videoHeight;
|
const sw = video.videoWidth / 2;
|
||||||
|
const sh = video.videoHeight / 2;
|
||||||
|
const sx = (video.videoWidth - sw) / 2;
|
||||||
|
const sy = (video.videoHeight - sh) / 2;
|
||||||
|
canvas.width = sw;
|
||||||
|
canvas.height = sh;
|
||||||
const ctx = canvas.getContext('2d');
|
const ctx = canvas.getContext('2d');
|
||||||
ctx.drawImage(video, 0, 0);
|
ctx.drawImage(video, sx, sy, sw, sh, 0, 0, sw, sh);
|
||||||
|
|
||||||
const dataUrl = canvas.toDataURL('image/jpeg', 0.85);
|
const dataUrl = canvas.toDataURL('image/jpeg', 0.85);
|
||||||
img.src = dataUrl;
|
img.src = dataUrl;
|
||||||
|
|||||||
+4
-4
@@ -167,7 +167,7 @@
|
|||||||
<div class="qty-unit-row">
|
<div class="qty-unit-row">
|
||||||
<div class="qty-control flex-1">
|
<div class="qty-control flex-1">
|
||||||
<button type="button" class="qty-btn" onclick="adjustAddQty(-1)">−</button>
|
<button type="button" class="qty-btn" onclick="adjustAddQty(-1)">−</button>
|
||||||
<input type="number" id="add-quantity" value="1" min="0.1" step="0.5" class="qty-input">
|
<input type="number" id="add-quantity" value="1" min="0.1" step="any" class="qty-input">
|
||||||
<button type="button" class="qty-btn" onclick="adjustAddQty(1)">+</button>
|
<button type="button" class="qty-btn" onclick="adjustAddQty(1)">+</button>
|
||||||
</div>
|
</div>
|
||||||
<select id="add-unit" class="form-input unit-select" onchange="onAddUnitChange()">
|
<select id="add-unit" class="form-input unit-select" onchange="onAddUnitChange()">
|
||||||
@@ -217,7 +217,7 @@
|
|||||||
<p>Oppure specifica la quantità usata:</p>
|
<p>Oppure specifica la quantità usata:</p>
|
||||||
<div class="qty-control">
|
<div class="qty-control">
|
||||||
<button type="button" class="qty-btn" onclick="adjustQty('use-quantity', -0.5)">−</button>
|
<button type="button" class="qty-btn" onclick="adjustQty('use-quantity', -0.5)">−</button>
|
||||||
<input type="number" id="use-quantity" value="1" min="0.1" step="0.5" class="qty-input">
|
<input type="number" id="use-quantity" value="1" min="0.1" step="any" class="qty-input">
|
||||||
<button type="button" class="qty-btn" onclick="adjustQty('use-quantity', 0.5)">+</button>
|
<button type="button" class="qty-btn" onclick="adjustQty('use-quantity', 0.5)">+</button>
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="btn btn-large btn-warning full-width mt-2">📤 Usa questa quantità</button>
|
<button type="submit" class="btn btn-large btn-warning full-width mt-2">📤 Usa questa quantità</button>
|
||||||
@@ -344,7 +344,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>📂 Categoria</label>
|
<label>📂 Categoria</label>
|
||||||
<select id="pf-category" class="form-input" onchange="onCategoryChange()">
|
<select id="pf-category" class="form-input" onchange="onCategoryChange(false)">
|
||||||
<option value="">-- Seleziona --</option>
|
<option value="">-- Seleziona --</option>
|
||||||
<option value="latticini">🥛 Latticini</option>
|
<option value="latticini">🥛 Latticini</option>
|
||||||
<option value="carne">🥩 Carne</option>
|
<option value="carne">🥩 Carne</option>
|
||||||
@@ -378,7 +378,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-group flex-1">
|
<div class="form-group flex-1">
|
||||||
<label>🔢 Quantità default</label>
|
<label>🔢 Quantità default</label>
|
||||||
<input type="number" id="pf-defqty" class="form-input" value="1" min="0.1" step="0.5">
|
<input type="number" id="pf-defqty" class="form-input" value="1" min="0.1" step="any">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
|||||||
Reference in New Issue
Block a user