Fixes and improvements
This commit is contained in:
parent
73c4648978
commit
374d067cf4
61
iframe.html
61
iframe.html
@ -2202,7 +2202,8 @@ const CALCULATOR_CONFIG = {
|
||||
energyUnit: 'kcal100g',
|
||||
percentage: 0,
|
||||
isLocked: false,
|
||||
chartType: null
|
||||
chartType: null,
|
||||
splitByMeals: false
|
||||
};
|
||||
this.foodSources.push(treats);
|
||||
this.renderFoodSource(treats);
|
||||
@ -2654,6 +2655,11 @@ const CALCULATOR_CONFIG = {
|
||||
const container = document.getElementById('foodSources');
|
||||
if (!container) return;
|
||||
|
||||
const isChart = foodSource.chartType === 'gc' || foodSource.chartType === 'kibble';
|
||||
const energyReadonlyAttr = isChart ? 'readonly' : '';
|
||||
const energyTitle = isChart ? 'Chart-based food: kcal locked' : 'Enter energy content';
|
||||
const unitDisabledAttr = isChart ? 'disabled' : '';
|
||||
|
||||
const cardHTML = `
|
||||
<div class="dog-calculator-food-source-card" id="foodSource-${foodSource.id}">
|
||||
<div class="dog-calculator-food-source-header">
|
||||
@ -2664,11 +2670,11 @@ const CALCULATOR_CONFIG = {
|
||||
<div class="dog-calculator-input-group">
|
||||
<div class="dog-calculator-form-group">
|
||||
<label for="energy-${foodSource.id}">Energy Content:</label>
|
||||
<input type="number" id="energy-${foodSource.id}" min="1" step="1" placeholder="Enter energy content" value="${foodSource.energy}">
|
||||
<input type="number" id="energy-${foodSource.id}" ${energyReadonlyAttr} title="${energyTitle}" min="1" step="1" placeholder="Enter energy content" value="${foodSource.energy}">
|
||||
</div>
|
||||
<div class="dog-calculator-form-group">
|
||||
<label for="energy-unit-${foodSource.id}">Unit:</label>
|
||||
<select id="energy-unit-${foodSource.id}" class="dog-calculator-unit-select">
|
||||
<select id="energy-unit-${foodSource.id}" class="dog-calculator-unit-select" ${unitDisabledAttr} title="${isChart ? 'Chart-based food: unit locked' : 'Select energy unit'}">
|
||||
<option value="kcal100g" ${foodSource.energyUnit === 'kcal100g' ? 'selected' : ''}>kcal/100g</option>
|
||||
<option value="kcalkg" ${foodSource.energyUnit === 'kcalkg' ? 'selected' : ''}>kcal/kg</option>
|
||||
<option value="kcalcup" ${foodSource.energyUnit === 'kcalcup' ? 'selected' : ''}>kcal/cup</option>
|
||||
@ -2729,7 +2735,7 @@ const CALCULATOR_CONFIG = {
|
||||
});
|
||||
}
|
||||
|
||||
if (energyInput) {
|
||||
if (energyInput && !energyInput.hasAttribute('readonly')) {
|
||||
energyInput.addEventListener('input', () => {
|
||||
this.updateFoodSourceData(id, 'energy', energyInput.value);
|
||||
// If kibble reference changed, recompute daily target
|
||||
@ -2753,7 +2759,7 @@ const CALCULATOR_CONFIG = {
|
||||
energyInput.addEventListener('blur', () => this.validateFoodSourceEnergy(id));
|
||||
}
|
||||
|
||||
if (energyUnitSelect) {
|
||||
if (energyUnitSelect && !energyUnitSelect.hasAttribute('disabled')) {
|
||||
energyUnitSelect.addEventListener('change', () => {
|
||||
this.updateFoodSourceData(id, 'energyUnit', energyUnitSelect.value);
|
||||
if (id === this.kibbleRefId) {
|
||||
@ -3365,7 +3371,7 @@ const CALCULATOR_CONFIG = {
|
||||
// Debug: log what unit is being used
|
||||
console.log('UpdateFoodCalculations - unit:', unit, 'unitLabel:', unitLabel);
|
||||
|
||||
// Determine frequency suffix for display
|
||||
// Determine frequency suffix for display (will adjust per-item below)
|
||||
const frequencySuffix = this.showPerMeal ? '/meal' : '/day';
|
||||
|
||||
// Clear all food source errors first
|
||||
@ -3429,6 +3435,8 @@ const CALCULATOR_CONFIG = {
|
||||
const kcalPerPercent = chartedPercent > 0 ? (chartedKcal / chartedPercent) : null;
|
||||
|
||||
// Second pass: finalize amounts
|
||||
let splitDailyTotal = 0;
|
||||
let dailyOnlyTotal = 0;
|
||||
firstPass.forEach(({ fs, energyPer100g, gramsPortion }) => {
|
||||
let dailyGramsForThisFood = 0;
|
||||
let hasEnergyContent = !!(energyPer100g && energyPer100g > 0);
|
||||
@ -3447,12 +3455,14 @@ const CALCULATOR_CONFIG = {
|
||||
}
|
||||
}
|
||||
|
||||
const displayGrams = this.showPerMeal ? dailyGramsForThisFood / this.mealsPerDay : dailyGramsForThisFood;
|
||||
const isDailyOnly = fs.splitByMeals === false;
|
||||
const displayGrams = (this.showPerMeal && !isDailyOnly) ? (dailyGramsForThisFood / this.mealsPerDay) : dailyGramsForThisFood;
|
||||
|
||||
foodBreakdowns.push({
|
||||
name: fs.name,
|
||||
percentage: fs.percentage,
|
||||
dailyGrams: dailyGramsForThisFood,
|
||||
isDailyOnly: isDailyOnly,
|
||||
displayGrams: displayGrams,
|
||||
dailyCups: null,
|
||||
displayCups: null,
|
||||
@ -3463,6 +3473,7 @@ const CALCULATOR_CONFIG = {
|
||||
foodSource: fs
|
||||
});
|
||||
totalDailyGrams += dailyGramsForThisFood;
|
||||
if (isDailyOnly) dailyOnlyTotal += dailyGramsForThisFood; else splitDailyTotal += dailyGramsForThisFood;
|
||||
if (dailyGramsForThisFood > 0) hasValidFoods = true;
|
||||
});
|
||||
|
||||
@ -3483,12 +3494,13 @@ const CALCULATOR_CONFIG = {
|
||||
const unitButtons = document.getElementById('unitButtons');
|
||||
if (unitButtons) unitButtons.style.display = 'none';
|
||||
|
||||
// If we have any food sources without energy content, still show the breakdown section
|
||||
if (foodBreakdowns.length > 0) {
|
||||
// If we have any foods with >0% but missing energy, show warnings only for those
|
||||
const visibleBreakdownsMissing = foodBreakdowns.filter(b => b.percentage > 0);
|
||||
if (visibleBreakdownsMissing.length > 0) {
|
||||
// Show food amounts section with warnings for missing energy content
|
||||
const unitLabel = unit === 'g' ? 'g' : unit === 'kg' ? 'kg' : unit === 'oz' ? 'oz' : 'lb';
|
||||
|
||||
const foodAmountsHTML = foodBreakdowns.map(breakdown => {
|
||||
const foodAmountsHTML = visibleBreakdownsMissing.map(breakdown => {
|
||||
const lockIndicator = breakdown.isLocked ? '<span class="dog-calculator-lock-indicator">🔒</span>' : '';
|
||||
|
||||
return `
|
||||
@ -3539,31 +3551,24 @@ const CALCULATOR_CONFIG = {
|
||||
const unitButtons = document.getElementById('unitButtons');
|
||||
if (unitButtons) unitButtons.style.display = 'flex';
|
||||
|
||||
// Update per-food breakdown
|
||||
if (foodBreakdownList && foodBreakdowns.length > 1) {
|
||||
const breakdownHTML = foodBreakdowns.map(breakdown => {
|
||||
// Update per-food breakdown (show only items with >0%)
|
||||
const visibleBreakdowns = foodBreakdowns.filter(b => b.percentage > 0);
|
||||
if (foodBreakdownList && visibleBreakdowns.length > 0) {
|
||||
const breakdownHTML = visibleBreakdowns.map(breakdown => {
|
||||
let valueContent;
|
||||
// Choose per-item frequency suffix: daily-only items stay /day even in per-meal view
|
||||
const itemSuffix = (this.showPerMeal && !breakdown.isDailyOnly) ? '/meal' : '/day';
|
||||
if (breakdown.hasEnergyContent) {
|
||||
if (unit === 'cups') {
|
||||
// For cups, use the pre-calculated cups value if available
|
||||
if (breakdown.displayCups !== null) {
|
||||
if (breakdown.hasRange && breakdown.displayCupsMin !== breakdown.displayCupsMax) {
|
||||
valueContent = `${this.formatNumber(breakdown.displayCupsMin, decimals)}-${this.formatNumber(breakdown.displayCupsMax, decimals)} ${unitLabel}${frequencySuffix}`;
|
||||
} else {
|
||||
valueContent = `${this.formatNumber(breakdown.displayCups, decimals)} ${unitLabel}${frequencySuffix}`;
|
||||
}
|
||||
valueContent = `${this.formatNumber(breakdown.displayCups, decimals)} ${unitLabel}${itemSuffix}`;
|
||||
} else {
|
||||
valueContent = `<span class="dog-calculator-warning" title="Cups only available for foods with kcal/cup measurement">N/A</span>`;
|
||||
}
|
||||
} else {
|
||||
// For other units (g, kg, oz, lb)
|
||||
if (breakdown.hasRange && breakdown.displayGramsMin !== breakdown.displayGramsMax) {
|
||||
const minConverted = this.convertUnits(breakdown.displayGramsMin, unit);
|
||||
const maxConverted = this.convertUnits(breakdown.displayGramsMax, unit);
|
||||
valueContent = `${this.formatNumber(minConverted, decimals)}-${this.formatNumber(maxConverted, decimals)} ${unitLabel}${frequencySuffix}`;
|
||||
} else {
|
||||
valueContent = `${this.formatNumber(this.convertUnits(breakdown.displayGrams, unit), decimals)} ${unitLabel}${frequencySuffix}`;
|
||||
}
|
||||
valueContent = `${this.formatNumber(this.convertUnits(breakdown.displayGrams, unit), decimals)} ${unitLabel}${itemSuffix}`;
|
||||
}
|
||||
} else {
|
||||
valueContent = `<span class="dog-calculator-warning" title="Enter energy content to calculate amount">⚠️</span>`;
|
||||
@ -3586,7 +3591,8 @@ const CALCULATOR_CONFIG = {
|
||||
// Generate individual food amount breakdown
|
||||
|
||||
// Update daily food value with correct units
|
||||
const displayTotal = this.showPerMeal ? totalDailyGrams / this.mealsPerDay : totalDailyGrams;
|
||||
// When per-meal view is enabled, split-only items divide by meals/day; daily-only items remain as daily totals
|
||||
const displayTotal = this.showPerMeal ? (splitDailyTotal / this.mealsPerDay + dailyOnlyTotal) : (splitDailyTotal + dailyOnlyTotal);
|
||||
let convertedTotal;
|
||||
let totalDisplayText;
|
||||
|
||||
@ -3653,7 +3659,8 @@ const CALCULATOR_CONFIG = {
|
||||
dailyFoodValue.textContent = totalDisplayText;
|
||||
|
||||
// Build HTML for individual food amounts
|
||||
const foodAmountsHTML = foodBreakdowns.map(breakdown => {
|
||||
const foodAmountsVisible = foodBreakdowns.filter(b => b.percentage > 0);
|
||||
const foodAmountsHTML = foodAmountsVisible.map(breakdown => {
|
||||
const lockIndicator = breakdown.isLocked ? '<span class="dog-calculator-lock-indicator">🔒</span>' : '';
|
||||
|
||||
if (!breakdown.hasEnergyContent) {
|
||||
|
||||
@ -106,7 +106,8 @@
|
||||
energyUnit: 'kcal100g',
|
||||
percentage: 0,
|
||||
isLocked: false,
|
||||
chartType: null
|
||||
chartType: null,
|
||||
splitByMeals: false
|
||||
};
|
||||
this.foodSources.push(treats);
|
||||
this.renderFoodSource(treats);
|
||||
@ -558,6 +559,11 @@
|
||||
const container = document.getElementById('foodSources');
|
||||
if (!container) return;
|
||||
|
||||
const isChart = foodSource.chartType === 'gc' || foodSource.chartType === 'kibble';
|
||||
const energyReadonlyAttr = isChart ? 'readonly' : '';
|
||||
const energyTitle = isChart ? 'Chart-based food: kcal locked' : 'Enter energy content';
|
||||
const unitDisabledAttr = isChart ? 'disabled' : '';
|
||||
|
||||
const cardHTML = `
|
||||
<div class="dog-calculator-food-source-card" id="foodSource-${foodSource.id}">
|
||||
<div class="dog-calculator-food-source-header">
|
||||
@ -568,11 +574,11 @@
|
||||
<div class="dog-calculator-input-group">
|
||||
<div class="dog-calculator-form-group">
|
||||
<label for="energy-${foodSource.id}">Energy Content:</label>
|
||||
<input type="number" id="energy-${foodSource.id}" min="1" step="1" placeholder="Enter energy content" value="${foodSource.energy}">
|
||||
<input type="number" id="energy-${foodSource.id}" ${energyReadonlyAttr} title="${energyTitle}" min="1" step="1" placeholder="Enter energy content" value="${foodSource.energy}">
|
||||
</div>
|
||||
<div class="dog-calculator-form-group">
|
||||
<label for="energy-unit-${foodSource.id}">Unit:</label>
|
||||
<select id="energy-unit-${foodSource.id}" class="dog-calculator-unit-select">
|
||||
<select id="energy-unit-${foodSource.id}" class="dog-calculator-unit-select" ${unitDisabledAttr} title="${isChart ? 'Chart-based food: unit locked' : 'Select energy unit'}">
|
||||
<option value="kcal100g" ${foodSource.energyUnit === 'kcal100g' ? 'selected' : ''}>kcal/100g</option>
|
||||
<option value="kcalkg" ${foodSource.energyUnit === 'kcalkg' ? 'selected' : ''}>kcal/kg</option>
|
||||
<option value="kcalcup" ${foodSource.energyUnit === 'kcalcup' ? 'selected' : ''}>kcal/cup</option>
|
||||
@ -633,7 +639,7 @@
|
||||
});
|
||||
}
|
||||
|
||||
if (energyInput) {
|
||||
if (energyInput && !energyInput.hasAttribute('readonly')) {
|
||||
energyInput.addEventListener('input', () => {
|
||||
this.updateFoodSourceData(id, 'energy', energyInput.value);
|
||||
// If kibble reference changed, recompute daily target
|
||||
@ -657,7 +663,7 @@
|
||||
energyInput.addEventListener('blur', () => this.validateFoodSourceEnergy(id));
|
||||
}
|
||||
|
||||
if (energyUnitSelect) {
|
||||
if (energyUnitSelect && !energyUnitSelect.hasAttribute('disabled')) {
|
||||
energyUnitSelect.addEventListener('change', () => {
|
||||
this.updateFoodSourceData(id, 'energyUnit', energyUnitSelect.value);
|
||||
if (id === this.kibbleRefId) {
|
||||
@ -1269,7 +1275,7 @@
|
||||
// Debug: log what unit is being used
|
||||
console.log('UpdateFoodCalculations - unit:', unit, 'unitLabel:', unitLabel);
|
||||
|
||||
// Determine frequency suffix for display
|
||||
// Determine frequency suffix for display (will adjust per-item below)
|
||||
const frequencySuffix = this.showPerMeal ? '/meal' : '/day';
|
||||
|
||||
// Clear all food source errors first
|
||||
@ -1333,6 +1339,8 @@
|
||||
const kcalPerPercent = chartedPercent > 0 ? (chartedKcal / chartedPercent) : null;
|
||||
|
||||
// Second pass: finalize amounts
|
||||
let splitDailyTotal = 0;
|
||||
let dailyOnlyTotal = 0;
|
||||
firstPass.forEach(({ fs, energyPer100g, gramsPortion }) => {
|
||||
let dailyGramsForThisFood = 0;
|
||||
let hasEnergyContent = !!(energyPer100g && energyPer100g > 0);
|
||||
@ -1351,12 +1359,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
const displayGrams = this.showPerMeal ? dailyGramsForThisFood / this.mealsPerDay : dailyGramsForThisFood;
|
||||
const isDailyOnly = fs.splitByMeals === false;
|
||||
const displayGrams = (this.showPerMeal && !isDailyOnly) ? (dailyGramsForThisFood / this.mealsPerDay) : dailyGramsForThisFood;
|
||||
|
||||
foodBreakdowns.push({
|
||||
name: fs.name,
|
||||
percentage: fs.percentage,
|
||||
dailyGrams: dailyGramsForThisFood,
|
||||
isDailyOnly: isDailyOnly,
|
||||
displayGrams: displayGrams,
|
||||
dailyCups: null,
|
||||
displayCups: null,
|
||||
@ -1367,6 +1377,7 @@
|
||||
foodSource: fs
|
||||
});
|
||||
totalDailyGrams += dailyGramsForThisFood;
|
||||
if (isDailyOnly) dailyOnlyTotal += dailyGramsForThisFood; else splitDailyTotal += dailyGramsForThisFood;
|
||||
if (dailyGramsForThisFood > 0) hasValidFoods = true;
|
||||
});
|
||||
|
||||
@ -1387,12 +1398,13 @@
|
||||
const unitButtons = document.getElementById('unitButtons');
|
||||
if (unitButtons) unitButtons.style.display = 'none';
|
||||
|
||||
// If we have any food sources without energy content, still show the breakdown section
|
||||
if (foodBreakdowns.length > 0) {
|
||||
// If we have any foods with >0% but missing energy, show warnings only for those
|
||||
const visibleBreakdownsMissing = foodBreakdowns.filter(b => b.percentage > 0);
|
||||
if (visibleBreakdownsMissing.length > 0) {
|
||||
// Show food amounts section with warnings for missing energy content
|
||||
const unitLabel = unit === 'g' ? 'g' : unit === 'kg' ? 'kg' : unit === 'oz' ? 'oz' : 'lb';
|
||||
|
||||
const foodAmountsHTML = foodBreakdowns.map(breakdown => {
|
||||
const foodAmountsHTML = visibleBreakdownsMissing.map(breakdown => {
|
||||
const lockIndicator = breakdown.isLocked ? '<span class="dog-calculator-lock-indicator">🔒</span>' : '';
|
||||
|
||||
return `
|
||||
@ -1443,31 +1455,24 @@
|
||||
const unitButtons = document.getElementById('unitButtons');
|
||||
if (unitButtons) unitButtons.style.display = 'flex';
|
||||
|
||||
// Update per-food breakdown
|
||||
if (foodBreakdownList && foodBreakdowns.length > 1) {
|
||||
const breakdownHTML = foodBreakdowns.map(breakdown => {
|
||||
// Update per-food breakdown (show only items with >0%)
|
||||
const visibleBreakdowns = foodBreakdowns.filter(b => b.percentage > 0);
|
||||
if (foodBreakdownList && visibleBreakdowns.length > 0) {
|
||||
const breakdownHTML = visibleBreakdowns.map(breakdown => {
|
||||
let valueContent;
|
||||
// Choose per-item frequency suffix: daily-only items stay /day even in per-meal view
|
||||
const itemSuffix = (this.showPerMeal && !breakdown.isDailyOnly) ? '/meal' : '/day';
|
||||
if (breakdown.hasEnergyContent) {
|
||||
if (unit === 'cups') {
|
||||
// For cups, use the pre-calculated cups value if available
|
||||
if (breakdown.displayCups !== null) {
|
||||
if (breakdown.hasRange && breakdown.displayCupsMin !== breakdown.displayCupsMax) {
|
||||
valueContent = `${this.formatNumber(breakdown.displayCupsMin, decimals)}-${this.formatNumber(breakdown.displayCupsMax, decimals)} ${unitLabel}${frequencySuffix}`;
|
||||
} else {
|
||||
valueContent = `${this.formatNumber(breakdown.displayCups, decimals)} ${unitLabel}${frequencySuffix}`;
|
||||
}
|
||||
valueContent = `${this.formatNumber(breakdown.displayCups, decimals)} ${unitLabel}${itemSuffix}`;
|
||||
} else {
|
||||
valueContent = `<span class="dog-calculator-warning" title="Cups only available for foods with kcal/cup measurement">N/A</span>`;
|
||||
}
|
||||
} else {
|
||||
// For other units (g, kg, oz, lb)
|
||||
if (breakdown.hasRange && breakdown.displayGramsMin !== breakdown.displayGramsMax) {
|
||||
const minConverted = this.convertUnits(breakdown.displayGramsMin, unit);
|
||||
const maxConverted = this.convertUnits(breakdown.displayGramsMax, unit);
|
||||
valueContent = `${this.formatNumber(minConverted, decimals)}-${this.formatNumber(maxConverted, decimals)} ${unitLabel}${frequencySuffix}`;
|
||||
} else {
|
||||
valueContent = `${this.formatNumber(this.convertUnits(breakdown.displayGrams, unit), decimals)} ${unitLabel}${frequencySuffix}`;
|
||||
}
|
||||
valueContent = `${this.formatNumber(this.convertUnits(breakdown.displayGrams, unit), decimals)} ${unitLabel}${itemSuffix}`;
|
||||
}
|
||||
} else {
|
||||
valueContent = `<span class="dog-calculator-warning" title="Enter energy content to calculate amount">⚠️</span>`;
|
||||
@ -1490,7 +1495,8 @@
|
||||
// Generate individual food amount breakdown
|
||||
|
||||
// Update daily food value with correct units
|
||||
const displayTotal = this.showPerMeal ? totalDailyGrams / this.mealsPerDay : totalDailyGrams;
|
||||
// When per-meal view is enabled, split-only items divide by meals/day; daily-only items remain as daily totals
|
||||
const displayTotal = this.showPerMeal ? (splitDailyTotal / this.mealsPerDay + dailyOnlyTotal) : (splitDailyTotal + dailyOnlyTotal);
|
||||
let convertedTotal;
|
||||
let totalDisplayText;
|
||||
|
||||
@ -1557,7 +1563,8 @@
|
||||
dailyFoodValue.textContent = totalDisplayText;
|
||||
|
||||
// Build HTML for individual food amounts
|
||||
const foodAmountsHTML = foodBreakdowns.map(breakdown => {
|
||||
const foodAmountsVisible = foodBreakdowns.filter(b => b.percentage > 0);
|
||||
const foodAmountsHTML = foodAmountsVisible.map(breakdown => {
|
||||
const lockIndicator = breakdown.isLocked ? '<span class="dog-calculator-lock-indicator">🔒</span>' : '';
|
||||
|
||||
if (!breakdown.hasEnergyContent) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user