Files
bamort/backend/pdfrender/pagination_helper.go
T

202 lines
6.6 KiB
Go
Raw Normal View History

2025-12-19 08:24:32 +01:00
package pdfrender
// GetBlockCapacity gets the MAX capacity for a block from template metadata
// Returns 0 if block not found
func GetBlockCapacity(templateSet *TemplateSet, templateName, blockName string) int {
for _, tmpl := range templateSet.Templates {
if tmpl.Metadata.Name == templateName {
block := GetBlockByName(tmpl.Metadata.Blocks, blockName)
if block != nil {
return block.MaxItems
}
}
}
return 0
}
2025-12-19 08:24:32 +01:00
// PreparePaginatedPageData prepares data for rendering a template page with proper pagination
// It takes the full view model and returns PageData with lists split according to template capacity
func PreparePaginatedPageData(viewModel *CharacterSheetViewModel, templateName string, pageNumber int, date string) (*PageData, error) {
// Get template metadata to determine capacities
templateSet := DefaultA4QuerTemplateSet()
pageData := &PageData{
Character: viewModel.Character,
Attributes: viewModel.Attributes,
DerivedValues: viewModel.DerivedValues,
GameResults: viewModel.GameResults,
Meta: PageMeta{
Date: date,
PageNumber: pageNumber,
},
}
// For page1_stats.html - paginate skills across two columns
if templateName == "page_1.html" {
2025-12-19 08:24:32 +01:00
// Get the template metadata
var template *TemplateMetadata
for _, tmpl := range templateSet.Templates {
if tmpl.Metadata.Name == templateName {
template = &tmpl.Metadata
break
}
}
if template != nil {
// Get skill blocks (should be skills_column1 and skills_column2)
var skillBlocks []BlockMetadata
for _, block := range template.Blocks {
if block.ListType == "skills" {
skillBlocks = append(skillBlocks, block)
}
}
if len(skillBlocks) >= 2 {
// Calculate how to split skills across columns
col1Capacity := skillBlocks[0].MaxItems
col2Capacity := skillBlocks[1].MaxItems
// Debug logging
// fmt.Printf("DEBUG: col1Capacity=%d, col2Capacity=%d\n", col1Capacity, col2Capacity)
col1Skills, col2Skills := SplitSkillsForColumns(viewModel.Skills, col1Capacity, col2Capacity)
// Fill to capacity to ensure empty rows render in template
pageData.SkillsColumn1 = FillToCapacity(col1Skills, col1Capacity)
pageData.SkillsColumn2 = FillToCapacity(col2Skills, col2Capacity)
2025-12-19 08:24:32 +01:00
pageData.Skills = viewModel.Skills // Keep for backward compatibility
} else {
pageData.Skills = viewModel.Skills
}
} else {
pageData.Skills = viewModel.Skills
}
} else if templateName == "page_2.html" {
// Get capacities from template
weaponsCapacity := GetBlockCapacity(&templateSet, templateName, "weapons_main")
learnedCapacity := GetBlockCapacity(&templateSet, templateName, "skills_learned")
languageCapacity := GetBlockCapacity(&templateSet, templateName, "skills_languages")
// Limit and fill weapons to capacity
weapons := viewModel.Weapons
if weaponsCapacity > 0 && len(weapons) > weaponsCapacity {
weapons = weapons[:weaponsCapacity]
}
if weaponsCapacity > 0 {
pageData.Weapons = FillToCapacity(weapons, weaponsCapacity)
} else {
pageData.Weapons = weapons
2025-12-19 08:24:32 +01:00
}
2025-12-19 08:30:45 +01:00
// Filter skills by category for page2 blocks
var learnedSkills, languageSkills []SkillViewModel
for _, skill := range viewModel.Skills {
if skill.Category == "Sprache" {
languageSkills = append(languageSkills, skill)
} else if skill.IsLearned || skill.Category == "Waffenfertigkeit" {
2025-12-19 08:30:45 +01:00
learnedSkills = append(learnedSkills, skill)
}
}
// Apply capacity limits
if learnedCapacity > 0 && len(learnedSkills) > learnedCapacity {
learnedSkills = learnedSkills[:learnedCapacity]
2025-12-19 08:30:45 +01:00
}
if languageCapacity > 0 && len(languageSkills) > languageCapacity {
languageSkills = languageSkills[:languageCapacity]
2025-12-19 08:24:32 +01:00
}
2025-12-19 08:30:45 +01:00
// Fill to capacity to ensure empty rows render
if learnedCapacity > 0 {
pageData.SkillsLearned = FillToCapacity(learnedSkills, learnedCapacity)
} else {
pageData.SkillsLearned = learnedSkills
}
if languageCapacity > 0 {
pageData.SkillsLanguage = FillToCapacity(languageSkills, languageCapacity)
} else {
pageData.SkillsLanguage = languageSkills
}
2025-12-19 08:30:45 +01:00
pageData.Skills = viewModel.Skills // Keep for backward compatibility
} else if templateName == "page_3.html" {
// Get capacities from template
2025-12-22 23:20:49 +01:00
spellsLeftCapacity := GetBlockCapacity(&templateSet, templateName, "spells_column1")
spellsRightCapacity := GetBlockCapacity(&templateSet, templateName, "spells_column2")
magicItemsCapacity := GetBlockCapacity(&templateSet, templateName, "magic_items")
// Split spells into left and right columns
leftSpells, rightSpells := SplitSkillsIntoColumns(viewModel.Spells, spellsLeftCapacity, spellsRightCapacity)
// Fill to capacity to ensure empty rows render
if spellsLeftCapacity > 0 {
pageData.SpellsLeft = FillToCapacity(leftSpells, spellsLeftCapacity)
} else {
pageData.SpellsLeft = leftSpells
}
if spellsRightCapacity > 0 {
pageData.SpellsRight = FillToCapacity(rightSpells, spellsRightCapacity)
} else {
pageData.SpellsRight = rightSpells
}
2025-12-19 08:30:45 +01:00
pageData.Spells = viewModel.Spells // Keep for backward compatibility
// Limit and fill magic items
magicItems := viewModel.MagicItems
if magicItemsCapacity > 0 && len(magicItems) > magicItemsCapacity {
magicItems = magicItems[:magicItemsCapacity]
}
if magicItemsCapacity > 0 {
pageData.MagicItems = FillToCapacity(magicItems, magicItemsCapacity)
} else {
pageData.MagicItems = magicItems
2025-12-19 08:24:32 +01:00
}
} else if templateName == "page_4.html" {
// Page 4 needs ALL equipment to properly render containers
// The template has complex logic showing containers on left, worn items and container sections on right
// Don't truncate based on capacity - let the template handle all items
pageData.Equipment = viewModel.Equipment
2025-12-19 08:24:32 +01:00
}
return pageData, nil
}
// SplitSkillsForColumns splits skills into two separate lists for two-column layout
// Returns (column1Skills, column2Skills)
func SplitSkillsForColumns(skills []SkillViewModel, col1Max, col2Max int) ([]SkillViewModel, []SkillViewModel) {
col1 := skills
if len(col1) > col1Max {
col1 = col1[:col1Max]
}
col2 := []SkillViewModel{}
if len(skills) > col1Max {
remaining := skills[col1Max:]
if len(remaining) > col2Max {
col2 = remaining[:col2Max]
} else {
col2 = remaining
}
}
return col1, col2
}
2025-12-19 08:30:45 +01:00
// SplitSkillsIntoColumns splits spells/items into two columns (generic for any slice type)
// Returns (column1, column2)
func SplitSkillsIntoColumns[T any](items []T, col1Max, col2Max int) ([]T, []T) {
col1 := items
if len(col1) > col1Max {
col1 = col1[:col1Max]
}
col2 := []T{}
if len(items) > col1Max {
remaining := items[col1Max:]
if len(remaining) > col2Max {
col2 = remaining[:col2Max]
} else {
col2 = remaining
}
}
return col1, col2
}