one pagination error has been fixed
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user