hugo

Fork of github.com/gohugoio/hugo with reverse pagination support

git clone git://git.shimmy1996.com/hugo.git

taxonomy.go (4848B)

    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 hugolib
   15 
   16 import (
   17 	"fmt"
   18 	"sort"
   19 
   20 	"github.com/gohugoio/hugo/compare"
   21 	"github.com/gohugoio/hugo/langs"
   22 
   23 	"github.com/gohugoio/hugo/resources/page"
   24 )
   25 
   26 // The TaxonomyList is a list of all taxonomies and their values
   27 // e.g. List['tags'] => TagTaxonomy (from above)
   28 type TaxonomyList map[string]Taxonomy
   29 
   30 func (tl TaxonomyList) String() string {
   31 	return fmt.Sprintf("TaxonomyList(%d)", len(tl))
   32 }
   33 
   34 // A Taxonomy is a map of keywords to a list of pages.
   35 // For example
   36 //    TagTaxonomy['technology'] = page.WeightedPages
   37 //    TagTaxonomy['go']  =  page.WeightedPages
   38 type Taxonomy map[string]page.WeightedPages
   39 
   40 // OrderedTaxonomy is another representation of an Taxonomy using an array rather than a map.
   41 // Important because you can't order a map.
   42 type OrderedTaxonomy []OrderedTaxonomyEntry
   43 
   44 // getOneOPage returns one page in the taxonomy,
   45 // nil if there is none.
   46 func (t OrderedTaxonomy) getOneOPage() page.Page {
   47 	if len(t) == 0 {
   48 		return nil
   49 	}
   50 	return t[0].Pages()[0]
   51 }
   52 
   53 // OrderedTaxonomyEntry is similar to an element of a Taxonomy, but with the key embedded (as name)
   54 // e.g:  {Name: Technology, page.WeightedPages: TaxonomyPages}
   55 type OrderedTaxonomyEntry struct {
   56 	Name string
   57 	page.WeightedPages
   58 }
   59 
   60 // Get the weighted pages for the given key.
   61 func (i Taxonomy) Get(key string) page.WeightedPages {
   62 	return i[key]
   63 }
   64 
   65 // Count the weighted pages for the given key.
   66 func (i Taxonomy) Count(key string) int { return len(i[key]) }
   67 
   68 func (i Taxonomy) add(key string, w page.WeightedPage) {
   69 	i[key] = append(i[key], w)
   70 }
   71 
   72 // TaxonomyArray returns an ordered taxonomy with a non defined order.
   73 func (i Taxonomy) TaxonomyArray() OrderedTaxonomy {
   74 	ies := make([]OrderedTaxonomyEntry, len(i))
   75 	count := 0
   76 	for k, v := range i {
   77 		ies[count] = OrderedTaxonomyEntry{Name: k, WeightedPages: v}
   78 		count++
   79 	}
   80 	return ies
   81 }
   82 
   83 // Alphabetical returns an ordered taxonomy sorted by key name.
   84 func (i Taxonomy) Alphabetical() OrderedTaxonomy {
   85 	ia := i.TaxonomyArray()
   86 	p := ia.getOneOPage()
   87 	if p == nil {
   88 		return ia
   89 	}
   90 	currentSite := p.Site().Current()
   91 	coll := langs.GetCollator(currentSite.Language())
   92 	coll.Lock()
   93 	defer coll.Unlock()
   94 	name := func(i1, i2 *OrderedTaxonomyEntry) bool {
   95 		return coll.CompareStrings(i1.Name, i2.Name) < 0
   96 	}
   97 	oiBy(name).Sort(ia)
   98 	return ia
   99 }
  100 
  101 // ByCount returns an ordered taxonomy sorted by # of pages per key.
  102 // If taxonomies have the same # of pages, sort them alphabetical
  103 func (i Taxonomy) ByCount() OrderedTaxonomy {
  104 	count := func(i1, i2 *OrderedTaxonomyEntry) bool {
  105 		li1 := len(i1.WeightedPages)
  106 		li2 := len(i2.WeightedPages)
  107 
  108 		if li1 == li2 {
  109 			return compare.LessStrings(i1.Name, i2.Name)
  110 		}
  111 		return li1 > li2
  112 	}
  113 
  114 	ia := i.TaxonomyArray()
  115 	oiBy(count).Sort(ia)
  116 	return ia
  117 }
  118 
  119 // Pages returns the Pages for this taxonomy.
  120 func (ie OrderedTaxonomyEntry) Pages() page.Pages {
  121 	return ie.WeightedPages.Pages()
  122 }
  123 
  124 // Count returns the count the pages in this taxonomy.
  125 func (ie OrderedTaxonomyEntry) Count() int {
  126 	return len(ie.WeightedPages)
  127 }
  128 
  129 // Term returns the name given to this taxonomy.
  130 func (ie OrderedTaxonomyEntry) Term() string {
  131 	return ie.Name
  132 }
  133 
  134 // Reverse reverses the order of the entries in this taxonomy.
  135 func (t OrderedTaxonomy) Reverse() OrderedTaxonomy {
  136 	for i, j := 0, len(t)-1; i < j; i, j = i+1, j-1 {
  137 		t[i], t[j] = t[j], t[i]
  138 	}
  139 
  140 	return t
  141 }
  142 
  143 // A type to implement the sort interface for TaxonomyEntries.
  144 type orderedTaxonomySorter struct {
  145 	taxonomy OrderedTaxonomy
  146 	by       oiBy
  147 }
  148 
  149 // Closure used in the Sort.Less method.
  150 type oiBy func(i1, i2 *OrderedTaxonomyEntry) bool
  151 
  152 func (by oiBy) Sort(taxonomy OrderedTaxonomy) {
  153 	ps := &orderedTaxonomySorter{
  154 		taxonomy: taxonomy,
  155 		by:       by, // The Sort method's receiver is the function (closure) that defines the sort order.
  156 	}
  157 	sort.Stable(ps)
  158 }
  159 
  160 // Len is part of sort.Interface.
  161 func (s *orderedTaxonomySorter) Len() int {
  162 	return len(s.taxonomy)
  163 }
  164 
  165 // Swap is part of sort.Interface.
  166 func (s *orderedTaxonomySorter) Swap(i, j int) {
  167 	s.taxonomy[i], s.taxonomy[j] = s.taxonomy[j], s.taxonomy[i]
  168 }
  169 
  170 // Less is part of sort.Interface. It is implemented by calling the "by" closure in the sorter.
  171 func (s *orderedTaxonomySorter) Less(i, j int) bool {
  172 	return s.by(&s.taxonomy[i], &s.taxonomy[j])
  173 }