github.com/linchen2chris/hugo@v0.0.0-20230307053224-cec209389705/resources/page/weighted.go (about)

     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  }