taxonomy.go - hugo - [fork] hugo port for 9front
 (HTM) git clone https://git.drkhsh.at/hugo.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Submodules
 (DIR) README
 (DIR) LICENSE
       ---
       taxonomy.go (4887B)
       ---
            1 // Copyright 2024 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         "strings"
           20 
           21         "github.com/gohugoio/hugo/compare"
           22         "github.com/gohugoio/hugo/langs"
           23 )
           24 
           25 // The TaxonomyList is a list of all taxonomies and their values
           26 // e.g. List['tags'] => TagTaxonomy (from above)
           27 type TaxonomyList map[string]Taxonomy
           28 
           29 func (tl TaxonomyList) String() string {
           30         return fmt.Sprintf("TaxonomyList(%d)", len(tl))
           31 }
           32 
           33 // A Taxonomy is a map of keywords to a list of pages.
           34 // For example
           35 //
           36 //        TagTaxonomy['technology'] = WeightedPages
           37 //        TagTaxonomy['go']  =  WeightedPages
           38 type Taxonomy map[string]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 {
           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, WeightedPages: TaxonomyPages}
           55 type OrderedTaxonomyEntry struct {
           56         Name string
           57         WeightedPages
           58 }
           59 
           60 // Get the weighted pages for the given key.
           61 func (i Taxonomy) Get(key string) WeightedPages {
           62         return i[strings.ToLower(key)]
           63 }
           64 
           65 // Count the weighted pages for the given key.
           66 func (i Taxonomy) Count(key string) int { return len(i[strings.ToLower(key)]) }
           67 
           68 // TaxonomyArray returns an ordered taxonomy with a non defined order.
           69 func (i Taxonomy) TaxonomyArray() OrderedTaxonomy {
           70         ies := make([]OrderedTaxonomyEntry, len(i))
           71         count := 0
           72         for k, v := range i {
           73                 ies[count] = OrderedTaxonomyEntry{Name: k, WeightedPages: v}
           74                 count++
           75         }
           76         return ies
           77 }
           78 
           79 // Alphabetical returns an ordered taxonomy sorted by key name.
           80 func (i Taxonomy) Alphabetical() OrderedTaxonomy {
           81         ia := i.TaxonomyArray()
           82         p := ia.getOneOPage()
           83         if p == nil {
           84                 return ia
           85         }
           86         currentSite := p.Site().Current()
           87         coll := langs.GetCollator1(currentSite.Language())
           88         coll.Lock()
           89         defer coll.Unlock()
           90         name := func(i1, i2 *OrderedTaxonomyEntry) bool {
           91                 return coll.CompareStrings(i1.Name, i2.Name) < 0
           92         }
           93         oiBy(name).Sort(ia)
           94         return ia
           95 }
           96 
           97 // ByCount returns an ordered taxonomy sorted by # of pages per key.
           98 // If taxonomies have the same # of pages, sort them alphabetical
           99 func (i Taxonomy) ByCount() OrderedTaxonomy {
          100         count := func(i1, i2 *OrderedTaxonomyEntry) bool {
          101                 li1 := len(i1.WeightedPages)
          102                 li2 := len(i2.WeightedPages)
          103 
          104                 if li1 == li2 {
          105                         return compare.LessStrings(i1.Name, i2.Name)
          106                 }
          107                 return li1 > li2
          108         }
          109 
          110         ia := i.TaxonomyArray()
          111         oiBy(count).Sort(ia)
          112         return ia
          113 }
          114 
          115 // Page returns the taxonomy page or nil if the taxonomy has no terms.
          116 func (i Taxonomy) Page() Page {
          117         for _, v := range i {
          118                 return v.Page().Parent()
          119         }
          120         return nil
          121 }
          122 
          123 // Pages returns the Pages for this taxonomy.
          124 func (ie OrderedTaxonomyEntry) Pages() Pages {
          125         return ie.WeightedPages.Pages()
          126 }
          127 
          128 // Count returns the count the pages in this taxonomy.
          129 func (ie OrderedTaxonomyEntry) Count() int {
          130         return len(ie.WeightedPages)
          131 }
          132 
          133 // Term returns the name given to this taxonomy.
          134 func (ie OrderedTaxonomyEntry) Term() string {
          135         return ie.Name
          136 }
          137 
          138 // Reverse reverses the order of the entries in this taxonomy.
          139 func (t OrderedTaxonomy) Reverse() OrderedTaxonomy {
          140         for i, j := 0, len(t)-1; i < j; i, j = i+1, j-1 {
          141                 t[i], t[j] = t[j], t[i]
          142         }
          143 
          144         return t
          145 }
          146 
          147 // A type to implement the sort interface for TaxonomyEntries.
          148 type orderedTaxonomySorter struct {
          149         taxonomy OrderedTaxonomy
          150         by       oiBy
          151 }
          152 
          153 // Closure used in the Sort.Less method.
          154 type oiBy func(i1, i2 *OrderedTaxonomyEntry) bool
          155 
          156 func (by oiBy) Sort(taxonomy OrderedTaxonomy) {
          157         ps := &orderedTaxonomySorter{
          158                 taxonomy: taxonomy,
          159                 by:       by, // The Sort method's receiver is the function (closure) that defines the sort order.
          160         }
          161         sort.Stable(ps)
          162 }
          163 
          164 // Len is part of sort.Interface.
          165 func (s *orderedTaxonomySorter) Len() int {
          166         return len(s.taxonomy)
          167 }
          168 
          169 // Swap is part of sort.Interface.
          170 func (s *orderedTaxonomySorter) Swap(i, j int) {
          171         s.taxonomy[i], s.taxonomy[j] = s.taxonomy[j], s.taxonomy[i]
          172 }
          173 
          174 // Less is part of sort.Interface. It is implemented by calling the "by" closure in the sorter.
          175 func (s *orderedTaxonomySorter) Less(i, j int) bool {
          176         return s.by(&s.taxonomy[i], &s.taxonomy[j])
          177 }