refactor: Unify PDF pagination system and rename templates

BREAKING CHANGE: Template names changed from page1_stats.html to page_1.html

## Phase 1: Unified Pagination Function
- Implemented PaginateMultiList() to replace PaginateSkills(), PaginateSpells(), and PaginatePage2PlayLists()
- Single metadata-driven function handles all list types (skills, weapons, spells, equipment)
- Properly handles filters (learned/unlearned/language) via template metadata
- Shares list trackers by ListType+Filter combination to avoid duplication
- Added comprehensive tests for all edge cases

## Phase 2: Template Naming Convention
- Renamed templates to be data-agnostic:
  - page1_stats.html -> page_1.html
  - page1.2_stats.html -> page_1.2.html
  - page2_play.html -> page_2.html
  - page2.2_play.html -> page_2.2.html
  - page3_spell.html -> page_3.html
  - page3.2_spell.html -> page_3.2.html
  - page4_equip.html -> page_4.html
- Updated GenerateContinuationTemplateName() for new naming (page_1.html -> page_1.2.html)
- Updated ExtractBaseTemplateName() to handle new format
- Updated all test files and source files with new template names

## Phase 3: Simplified RenderPageWithContinuations
- Removed hardcoded switch statements based on template names
- Replaced with generic dataMap and unified pagination call
- Extracted populatePageDataFromDistribution() to handle data mapping
- Template type detection now driven by metadata, not hardcoded names

## Benefits
-  Extensibility: Add new templates without code changes
-  Maintainability: One pagination algorithm instead of three
-  Clarity: Template names reflect page numbers, not content types
-  Flexibility: Templates can mix any data types
-  All 40+ tests passing

## Technical Details
- Added SkillsColumn3 and SkillsColumn4 fields to PageData for continuation pages
- Template metadata loaded from HTML comments drives pagination behavior
- Backward compatibility maintained for old template references in comments
This commit is contained in:
2025-12-21 22:07:46 +01:00
parent 61ebcea3b3
commit 59fe69d35d
28 changed files with 784 additions and 397 deletions
+20 -20
View File
@@ -22,7 +22,7 @@ func TestContinuationPages_WhenSkillsExceedCapacity(t *testing.T) {
}
// Act - Paginate skills for page1_stats
pages, err := paginator.PaginateSkills(skills, "page1_stats.html", "")
pages, err := paginator.PaginateSkills(skills, "page_1.html", "")
// Assert
if err != nil {
@@ -34,13 +34,13 @@ func TestContinuationPages_WhenSkillsExceedCapacity(t *testing.T) {
t.Errorf("Expected at least 2 pages for 100 skills, got %d", len(pages))
}
// First page should be "page1_stats.html"
if pages[0].TemplateName != "page1_stats.html" {
t.Errorf("Expected first page template 'page1_stats.html', got '%s'", pages[0].TemplateName)
// First page should be "page_1.html"
if pages[0].TemplateName != "page_1.html" {
t.Errorf("Expected first page template 'page_1.html', got '%s'", pages[0].TemplateName)
}
// Second page should be continuation page with name pattern "page1.2_stats.html"
expectedContinuation := "page1.2_stats.html"
// Second page should be continuation page with name pattern "page_1.2.html"
expectedContinuation := "page_1.2.html"
if pages[1].TemplateName != expectedContinuation {
t.Errorf("Expected continuation page template '%s', got '%s'",
expectedContinuation, pages[1].TemplateName)
@@ -79,7 +79,7 @@ func TestContinuationPages_WhenWeaponsExceedCapacity(t *testing.T) {
// Get capacity for page2_play weapons (should be 12)
var weaponsCapacity int
for _, tmpl := range templateSet.Templates {
if tmpl.Metadata.Name == "page2_play.html" {
if tmpl.Metadata.Name == "page_2.html" {
for _, block := range tmpl.Metadata.Blocks {
if block.ListType == "weapons" {
weaponsCapacity = block.MaxItems
@@ -106,7 +106,7 @@ func TestContinuationPages_WhenWeaponsExceedCapacity(t *testing.T) {
t.Logf("Created %d weapons (capacity %d)", numWeapons, weaponsCapacity)
// Act
pages, err := paginator.PaginateWeapons(weapons, "page2_play.html")
pages, err := paginator.PaginateWeapons(weapons, "page_2.html")
// Assert
if err != nil {
@@ -119,13 +119,13 @@ func TestContinuationPages_WhenWeaponsExceedCapacity(t *testing.T) {
}
// First page should be original template
if pages[0].TemplateName != "page2_play.html" {
t.Errorf("Expected first page 'page2_play.html', got '%s'", pages[0].TemplateName)
if pages[0].TemplateName != "page_2.html" {
t.Errorf("Expected first page 'page_2.html', got '%s'", pages[0].TemplateName)
}
// Second page should be continuation
if pages[1].TemplateName != "page2.2_play.html" {
t.Errorf("Expected continuation 'page2.2_play.html', got '%s'", pages[1].TemplateName)
if pages[1].TemplateName != "page_2.2.html" {
t.Errorf("Expected continuation 'page_2.2.html', got '%s'", pages[1].TemplateName)
}
}
@@ -138,7 +138,7 @@ func TestContinuationPages_MultipleOverflows(t *testing.T) {
// Get actual capacity from template
var skillsCapacity int
for _, tmpl := range templateSet.Templates {
if tmpl.Metadata.Name == "page1_stats.html" {
if tmpl.Metadata.Name == "page_1.html" {
for _, block := range tmpl.Metadata.Blocks {
if block.ListType == "skills" {
skillsCapacity += block.MaxItems
@@ -163,7 +163,7 @@ func TestContinuationPages_MultipleOverflows(t *testing.T) {
expectedPages := (200 + skillsCapacity - 1) / skillsCapacity
// Act
pages, err := paginator.PaginateSkills(skills, "page1_stats.html", "")
pages, err := paginator.PaginateSkills(skills, "page_1.html", "")
// Assert
if err != nil {
@@ -177,14 +177,14 @@ func TestContinuationPages_MultipleOverflows(t *testing.T) {
t.Logf("Created %d pages for 200 skills", len(pages))
// Verify template names follow pattern: page1_stats.html, then all use page1.2_stats.html
// Verify template names follow pattern: page_1.html, then all use page_1.2.html
for i, page := range pages {
var expectedTemplate string
if i == 0 {
expectedTemplate = "page1_stats.html"
expectedTemplate = "page_1.html"
} else {
// All continuation pages use the same .2 template
expectedTemplate = "page1.2_stats.html"
expectedTemplate = "page_1.2.html"
}
if page.TemplateName != expectedTemplate {
@@ -211,7 +211,7 @@ func TestContinuationPages_NoOverflow(t *testing.T) {
}
// Act
pages, err := paginator.PaginateSkills(skills, "page1_stats.html", "")
pages, err := paginator.PaginateSkills(skills, "page_1.html", "")
// Assert
if err != nil {
@@ -224,7 +224,7 @@ func TestContinuationPages_NoOverflow(t *testing.T) {
}
// Should use original template, not continuation
if pages[0].TemplateName != "page1_stats.html" {
t.Errorf("Expected original template 'page1_stats.html', got '%s'", pages[0].TemplateName)
if pages[0].TemplateName != "page_1.html" {
t.Errorf("Expected original template 'page_1.html', got '%s'", pages[0].TemplateName)
}
}