pages.go (3247B)
1 // Copyright 2019 The Hugo Authors. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13
14 package page
15
16 import (
17 "fmt"
18 "math/rand"
19
20 "github.com/gohugoio/hugo/compare"
21
22 "github.com/gohugoio/hugo/resources/resource"
23 )
24
25 // Pages is a slice of Page objects. This is the most common list type in Hugo.
26 type Pages []Page
27
28 // String returns a string representation of the list.
29 // For internal use.
30 func (ps Pages) String() string {
31 return fmt.Sprintf("Pages(%d)", len(ps))
32 }
33
34 // Used in tests.
35 func (ps Pages) shuffle() {
36 for i := range ps {
37 j := rand.Intn(i + 1)
38 ps[i], ps[j] = ps[j], ps[i]
39 }
40 }
41
42 // ToResources wraps resource.ResourcesConverter.
43 // For internal use.
44 func (pages Pages) ToResources() resource.Resources {
45 r := make(resource.Resources, len(pages))
46 for i, p := range pages {
47 r[i] = p
48 }
49 return r
50 }
51
52 // ToPages tries to convert seq into Pages.
53 func ToPages(seq any) (Pages, error) {
54 if seq == nil {
55 return Pages{}, nil
56 }
57
58 switch v := seq.(type) {
59 case Pages:
60 return v, nil
61 case *Pages:
62 return *(v), nil
63 case WeightedPages:
64 return v.Pages(), nil
65 case PageGroup:
66 return v.Pages, nil
67 case []Page:
68 pages := make(Pages, len(v))
69 for i, vv := range v {
70 pages[i] = vv
71 }
72 return pages, nil
73 case []any:
74 pages := make(Pages, len(v))
75 success := true
76 for i, vv := range v {
77 p, ok := vv.(Page)
78 if !ok {
79 success = false
80 break
81 }
82 pages[i] = p
83 }
84 if success {
85 return pages, nil
86 }
87 }
88
89 return nil, fmt.Errorf("cannot convert type %T to Pages", seq)
90 }
91
92 // Group groups the pages in in by key.
93 // This implements collections.Grouper.
94 func (p Pages) Group(key any, in any) (any, error) {
95 pages, err := ToPages(in)
96 if err != nil {
97 return PageGroup{}, err
98 }
99 return PageGroup{Key: key, Pages: pages}, nil
100 }
101
102 // Len returns the number of pages in the list.
103 func (p Pages) Len() int {
104 return len(p)
105 }
106
107 // ProbablyEq wraps compare.ProbablyEqer
108 // For internal use.
109 func (pages Pages) ProbablyEq(other any) bool {
110 otherPages, ok := other.(Pages)
111 if !ok {
112 return false
113 }
114
115 if len(pages) != len(otherPages) {
116 return false
117 }
118
119 step := 1
120
121 for i := 0; i < len(pages); i += step {
122 if !pages[i].Eq(otherPages[i]) {
123 return false
124 }
125
126 if i > 50 {
127 // This is most likely the same.
128 step = 50
129 }
130 }
131
132 return true
133 }
134
135 func (ps Pages) removeFirstIfFound(p Page) Pages {
136 ii := -1
137 for i, pp := range ps {
138 if p.Eq(pp) {
139 ii = i
140 break
141 }
142 }
143
144 if ii != -1 {
145 ps = append(ps[:ii], ps[ii+1:]...)
146 }
147 return ps
148 }
149
150 // PagesFactory somehow creates some Pages.
151 // We do a lot of lazy Pages initialization in Hugo, so we need a type.
152 type PagesFactory func() Pages
153
154 var (
155 _ resource.ResourcesConverter = Pages{}
156 _ compare.ProbablyEqer = Pages{}
157 )