one pagination error has been fixed

This commit is contained in:
2025-12-19 08:30:45 +01:00
parent da91eb5f56
commit 9d1398b397
9 changed files with 120 additions and 81 deletions
+12 -19
View File
@@ -152,7 +152,7 @@ func TestIntegration_TemplateMetadata(t *testing.T) {
}{
{"page1_stats.html", "skills_column1", 29},
{"page2_play.html", "skills_learned", 24},
{"page3_spell.html", "spells_left", 12},
{"page3_spell.html", "spells_left", 20},
{"page3_spell.html", "spells_right", 10},
{"page4_equip.html", "equipment_worn", 10},
}
@@ -296,31 +296,24 @@ func TestIntegration_MultiPageSpellList(t *testing.T) {
t.Fatalf("Failed to paginate spells: %v", err)
}
// Should create 2 pages
if len(pages) != 2 {
t.Fatalf("Expected 2 pages for 30 spells, got %d", len(pages))
}
// With 30 capacity (20+10), should create 1 page for 30 spells
// Verify distribution
// Page 1: 12 + 12 = 24 spells
col1Page1 := pages[0].Data["spells_column1"].([]SpellViewModel)
col2Page1 := pages[0].Data["spells_column2"].([]SpellViewModel)
totalPage1 := len(col1Page1) + len(col2Page1)
if totalPage1 != 24 {
t.Errorf("Expected 24 spells on page 1, got %d", totalPage1)
// With 20+10 capacity, 30 spells should fit on 1 page
if len(pages) != 1 {
t.Fatalf("Expected 1 page for 30 spells, got %d", len(pages))
}
// Page 2: 6 + 0 = 6 spells
col1Page2 := pages[1].Data["spells_column1"].([]SpellViewModel)
col2Page2 := pages[1].Data["spells_column2"].([]SpellViewModel)
totalPage2 := len(col1Page2) + len(col2Page2)
// Page 1: 20 (left) + 10 (right) = 30 spells
leftPage1 := pages[0].Data["spells_left"].([]SpellViewModel)
rightPage1 := pages[0].Data["spells_right"].([]SpellViewModel)
totalPage1 := len(leftPage1) + len(rightPage1)
if totalPage2 != 6 {
t.Errorf("Expected 6 spells on page 2, got %d", totalPage2)
if totalPage1 != 30 {
t.Errorf("Expected 30 spells on page 1 (20+10), got %d", totalPage1)
}
t.Logf("Successfully distributed 30 spells: Page 1 has %d, Page 2 has %d", totalPage1, totalPage2)
t.Logf("Successfully distributed 30 spells: Page 1 has %d (left %d, right %d)", totalPage1, len(leftPage1), len(rightPage1))
}
// TestIntegration_CompleteWorkflow demonstrates the full workflow from character to multi-page PDF
+50 -6
View File
@@ -61,13 +61,36 @@ func PreparePaginatedPageData(viewModel *CharacterSheetViewModel, templateName s
if len(pageData.Weapons) > 30 {
pageData.Weapons = pageData.Weapons[:30]
}
pageData.Skills = viewModel.Skills
} else if templateName == "page3_spell.html" {
// Limit spells according to capacity (24 total: 12+12)
pageData.Spells = viewModel.Spells
if len(pageData.Spells) > 24 {
pageData.Spells = pageData.Spells[:24]
// 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 {
learnedSkills = append(learnedSkills, skill)
}
}
// Apply capacity limits
if len(learnedSkills) > 24 {
learnedSkills = learnedSkills[:24]
}
if len(languageSkills) > 11 {
languageSkills = languageSkills[:11]
}
pageData.SkillsLearned = learnedSkills
pageData.SkillsLanguage = languageSkills
pageData.Skills = viewModel.Skills // Keep for backward compatibility
} else if templateName == "page3_spell.html" {
// Split spells into left (20) and right (10) columns
leftSpells, rightSpells := SplitSkillsIntoColumns(viewModel.Spells, 20, 10)
pageData.SpellsLeft = leftSpells
pageData.SpellsRight = rightSpells
pageData.Spells = viewModel.Spells // Keep for backward compatibility
// Limit magic items to 5
pageData.MagicItems = viewModel.MagicItems
if len(pageData.MagicItems) > 5 {
pageData.MagicItems = pageData.MagicItems[:5]
@@ -102,3 +125,24 @@ func SplitSkillsForColumns(skills []SkillViewModel, col1Max, col2Max int) ([]Ski
return col1, col2
}
// 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
}
+14 -4
View File
@@ -173,9 +173,18 @@ func TestPreparePaginatedPageData_Page3Spell(t *testing.T) {
t.Fatalf("PreparePaginatedPageData failed: %v", err)
}
// Page 3 should have spells limited to 24 (12+12)
if len(pageData.Spells) > 24 {
t.Errorf("Spells exceed capacity: got %d, max 24", len(pageData.Spells))
// Page 3 should have spells split: left (max 20) and right (max 10)
if len(pageData.SpellsLeft) > 20 {
t.Errorf("SpellsLeft exceed capacity: got %d, max 20", len(pageData.SpellsLeft))
}
if len(pageData.SpellsRight) > 10 {
t.Errorf("SpellsRight exceed capacity: got %d, max 10", len(pageData.SpellsRight))
}
totalSpells := len(pageData.SpellsLeft) + len(pageData.SpellsRight)
if totalSpells > 30 {
t.Errorf("Total spells exceed capacity: got %d, max 30 (20+10)", totalSpells)
}
// Magic items limited to 5
@@ -183,7 +192,8 @@ func TestPreparePaginatedPageData_Page3Spell(t *testing.T) {
t.Errorf("MagicItems exceed capacity: got %d, max 5", len(pageData.MagicItems))
}
t.Logf("Page3: %d spells, %d magic items", len(pageData.Spells), len(pageData.MagicItems))
t.Logf("Page3: left=%d, right=%d (total=%d spells), %d magic items",
len(pageData.SpellsLeft), len(pageData.SpellsRight), totalSpells, len(pageData.MagicItems))
}
func TestPreparePaginatedPageData_Page4Equipment(t *testing.T) {
+21 -31
View File
@@ -211,16 +211,16 @@ func TestPaginateSpells_TwoColumns(t *testing.T) {
page := pages[0]
// Column 1 should have 12 spells
col1Data := page.Data["spells_column1"].([]SpellViewModel)
if len(col1Data) != 12 {
t.Errorf("Expected 12 spells in column 1, got %d", len(col1Data))
// Left column should have 15 spells (all fit in 20 capacity)
leftData := page.Data["spells_left"].([]SpellViewModel)
if len(leftData) != 15 {
t.Errorf("Expected 15 spells in left column, got %d", len(leftData))
}
// Column 2 should have 3 spells
col2Data := page.Data["spells_column2"].([]SpellViewModel)
if len(col2Data) != 3 {
t.Errorf("Expected 3 spells in column 2, got %d", len(col2Data))
// Right column should be empty (15 spells all fit in left)
rightData := page.Data["spells_right"].([]SpellViewModel)
if len(rightData) != 0 {
t.Errorf("Expected 0 spells in right column, got %d", len(rightData))
}
}
@@ -229,7 +229,7 @@ func TestPaginateSpells_MultiPage(t *testing.T) {
templateSet := DefaultA4QuerTemplateSet()
paginator := NewPaginator(templateSet)
// Create 30 spells - should span 2 pages (24 capacity per page = 12+12)
// Create 30 spells - should fit on 1 page (30 capacity = 20 left + 10 right)
spells := make([]SpellViewModel, 30)
for i := 0; i < 30; i++ {
spells[i] = SpellViewModel{Name: "Spell" + string(rune(i))}
@@ -243,30 +243,20 @@ func TestPaginateSpells_MultiPage(t *testing.T) {
t.Fatalf("Expected no error, got %v", err)
}
if len(pages) != 2 {
t.Fatalf("Expected 2 pages, got %d", len(pages))
// With capacity of 20+10=30, all 30 spells fit on 1 page
if len(pages) != 1 {
t.Fatalf("Expected 1 page, got %d", len(pages))
}
// Page 1 should have 24 spells (12 + 12)
// Page 1 should have all 30 spells (20 left + 10 right)
page1 := pages[0]
col1Page1 := page1.Data["spells_column1"].([]SpellViewModel)
col2Page1 := page1.Data["spells_column2"].([]SpellViewModel)
if len(col1Page1) != 12 {
t.Errorf("Page 1 col1: expected 12 spells, got %d", len(col1Page1))
leftPage1 := page1.Data["spells_left"].([]SpellViewModel)
rightPage1 := page1.Data["spells_right"].([]SpellViewModel)
if len(leftPage1) != 20 {
t.Errorf("Page 1 left: expected 20 spells, got %d", len(leftPage1))
}
if len(col2Page1) != 12 {
t.Errorf("Page 1 col2: expected 12 spells, got %d", len(col2Page1))
}
// Page 2 should have 6 spells (6 + 0)
page2 := pages[1]
col1Page2 := page2.Data["spells_column1"].([]SpellViewModel)
col2Page2 := page2.Data["spells_column2"].([]SpellViewModel)
if len(col1Page2) != 6 {
t.Errorf("Page 2 col1: expected 6 spells, got %d", len(col1Page2))
}
if len(col2Page2) != 0 {
t.Errorf("Page 2 col2: expected 0 spells, got %d", len(col2Page2))
if len(rightPage1) != 10 {
t.Errorf("Page 1 right: expected 10 spells, got %d", len(rightPage1))
}
}
@@ -355,8 +345,8 @@ func TestCalculatePagesNeeded(t *testing.T) {
{"30 weapons on page2", "page2_play.html", "weapons", 30, 1},
{"31 weapons on page2", "page2_play.html", "weapons", 31, 2},
{"10 spells on page3", "page3_spell.html", "spells", 10, 1},
{"24 spells on page3", "page3_spell.html", "spells", 24, 1},
{"25 spells on page3", "page3_spell.html", "spells", 25, 2},
{"30 spells on page3", "page3_spell.html", "spells", 30, 1}, // 20+10 = 30 fits on 1 page
{"31 spells on page3", "page3_spell.html", "spells", 31, 2}, // 31 requires 2 pages
}
for _, tc := range testCases {
+4 -4
View File
@@ -98,15 +98,15 @@ func DefaultA4QuerTemplateSet() TemplateSet {
Description: "Zauberseite mit Zauberliste",
Blocks: []BlockMetadata{
{
Name: "spells_column1",
Name: "spells_left",
ListType: "spells",
MaxItems: 12,
MaxItems: 20,
Column: 1,
},
{
Name: "spells_column2",
Name: "spells_right",
ListType: "spells",
MaxItems: 12,
MaxItems: 10,
Column: 2,
},
{
+2 -2
View File
@@ -87,8 +87,8 @@ func TestGetTemplateMetadata(t *testing.T) {
if leftBlock == nil {
t.Error("Expected to find 'spells_left' block")
} else {
if leftBlock.MaxItems != 12 {
t.Errorf("Expected spells_left max 12, got %d", leftBlock.MaxItems)
if leftBlock.MaxItems != 20 {
t.Errorf("Expected spells_left max 20, got %d", leftBlock.MaxItems)
}
}
+12 -8
View File
@@ -173,14 +173,18 @@ type PageData struct {
DerivedValues DerivedValueSet
// Lists sliced according to template block metadata
Skills []SkillViewModel
SkillsColumn1 []SkillViewModel // For two-column skill layout
SkillsColumn2 []SkillViewModel // For two-column skill layout
Weapons []WeaponViewModel
Spells []SpellViewModel
MagicItems []MagicItemViewModel
Equipment []EquipmentViewModel
GameResults []GameResultViewModel
Skills []SkillViewModel
SkillsColumn1 []SkillViewModel // For two-column skill layout (page1)
SkillsColumn2 []SkillViewModel // For two-column skill layout (page1)
SkillsLearned []SkillViewModel // Filtered learned skills (page2)
SkillsLanguage []SkillViewModel // Filtered language skills (page2)
Weapons []WeaponViewModel
Spells []SpellViewModel
SpellsLeft []SpellViewModel // Left column spells (page3)
SpellsRight []SpellViewModel // Right column spells (page3)
MagicItems []MagicItemViewModel
Equipment []EquipmentViewModel
GameResults []GameResultViewModel
Meta PageMeta
}
@@ -59,7 +59,7 @@
<th>EW</th>
<th>PP</th>
</tr>
{{range .Skills}}
{{range .SkillsLearned}}
<tr><td>{{.Name}}</td><td>+ {{.Value}}</td><td>{{if .PracticePoints}}{{.PracticePoints}}{{end}}</td></tr>
{{end}}
</table>
@@ -92,11 +92,9 @@
<th>EW</th>
<th>PP</th>
</tr>
{{range .Skills}}
{{if eq .Category "Sprache"}}
{{range .SkillsLanguage}}
<tr><td>{{.Name}}</td><td>+ {{.Value}}</td><td>{{if .PracticePoints}}{{.PracticePoints}}{{end}}</td></tr>
{{end}}
{{end}}
</table>
</div>
</div>
@@ -26,7 +26,7 @@
<div class="flex main-content">
<!-- Left spell table -->
<div class="left-section">
<!-- BLOCK: spells_left, TYPE: spells, MAX: 12 -->
<!-- BLOCK: spells_left, TYPE: spells, MAX: 20 -->
<table class="spells-table">
<tr>
<th>AP<hr>Prozess *</th>
@@ -36,7 +36,7 @@
<th>Wirkung</th>
<th>Wirk.ziel<hr>Art</th>
</tr>
{{range .Spells}}
{{range .SpellsLeft}}
<tr>
<td>{{.AP}}<hr>{{.Notes}}</td>
<td>{{.Name}}</td>
@@ -61,7 +61,7 @@
<th>Wirkung</th>
<th>Wirk.ziel<br>Art</th>
</tr>
{{range .Spells}}
{{range .SpellsRight}}
<tr>
<td>{{.AP}}<hr>{{.Notes}}</td>
<td>{{.Name}}</td>