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 }