weighted.go (3626B)
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 "sort"
19
20 "github.com/gohugoio/hugo/common/collections"
21 )
22
23 var _ collections.Slicer = WeightedPage{}
24
25 // WeightedPages is a list of Pages with their corresponding (and relative) weight
26 // [{Weight: 30, Page: *1}, {Weight: 40, Page: *2}]
27 type WeightedPages []WeightedPage
28
29 // Page will return the Page (of Kind taxonomyList) that represents this set
30 // of pages. This method will panic if p is empty, as that should never happen.
31 func (p WeightedPages) Page() Page {
32 if len(p) == 0 {
33 panic("WeightedPages is empty")
34 }
35
36 first := p[0]
37
38 // TODO(bep) fix tests
39 if first.owner == nil {
40 return nil
41 }
42
43 return first.owner
44 }
45
46 // A WeightedPage is a Page with a weight.
47 type WeightedPage struct {
48 Weight int
49 Page
50
51 // Reference to the owning Page. This avoids having to do
52 // manual .Site.GetPage lookups. It is implemented in this roundabout way
53 // because we cannot add additional state to the WeightedPages slice
54 // without breaking lots of templates in the wild.
55 owner Page
56 }
57
58 func NewWeightedPage(weight int, p Page, owner Page) WeightedPage {
59 return WeightedPage{Weight: weight, Page: p, owner: owner}
60 }
61
62 func (w WeightedPage) String() string {
63 return fmt.Sprintf("WeightedPage(%d,%q)", w.Weight, w.Page.Title())
64 }
65
66 // Slice is for internal use.
67 // for the template functions. See collections.Slice.
68 func (p WeightedPage) Slice(in any) (any, error) {
69 switch items := in.(type) {
70 case WeightedPages:
71 return items, nil
72 case []any:
73 weighted := make(WeightedPages, len(items))
74 for i, v := range items {
75 g, ok := v.(WeightedPage)
76 if !ok {
77 return nil, fmt.Errorf("type %T is not a WeightedPage", v)
78 }
79 weighted[i] = g
80 }
81 return weighted, nil
82 default:
83 return nil, fmt.Errorf("invalid slice type %T", items)
84 }
85 }
86
87 // Pages returns the Pages in this weighted page set.
88 func (wp WeightedPages) Pages() Pages {
89 pages := make(Pages, len(wp))
90 for i := range wp {
91 pages[i] = wp[i].Page
92 }
93 return pages
94 }
95
96 // Next returns the next Page relative to the given Page in
97 // this weighted page set.
98 func (wp WeightedPages) Next(cur Page) Page {
99 for x, c := range wp {
100 if c.Page.Eq(cur) {
101 if x == 0 {
102 return nil
103 }
104 return wp[x-1].Page
105 }
106 }
107 return nil
108 }
109
110 // Prev returns the previous Page relative to the given Page in
111 // this weighted page set.
112 func (wp WeightedPages) Prev(cur Page) Page {
113 for x, c := range wp {
114 if c.Page.Eq(cur) {
115 if x < len(wp)-1 {
116 return wp[x+1].Page
117 }
118 return nil
119 }
120 }
121 return nil
122 }
123
124 func (wp WeightedPages) Len() int { return len(wp) }
125 func (wp WeightedPages) Swap(i, j int) { wp[i], wp[j] = wp[j], wp[i] }
126
127 // Sort stable sorts this weighted page set.
128 func (wp WeightedPages) Sort() { sort.Stable(wp) }
129
130 // Count returns the number of pages in this weighted page set.
131 func (wp WeightedPages) Count() int { return len(wp) }
132
133 func (wp WeightedPages) Less(i, j int) bool {
134 if wp[i].Weight == wp[j].Weight {
135 return DefaultPageSort(wp[i].Page, wp[j].Page)
136 }
137 return wp[i].Weight < wp[j].Weight
138 }