github.com/neohugo/neohugo@v0.123.8/hugolib/page__tree.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 hugolib 15 16 import ( 17 "context" 18 "fmt" 19 "strings" 20 21 "github.com/neohugo/neohugo/common/paths" 22 "github.com/neohugo/neohugo/common/types" 23 "github.com/neohugo/neohugo/hugolib/doctree" 24 "github.com/neohugo/neohugo/resources/kinds" 25 "github.com/neohugo/neohugo/resources/page" 26 ) 27 28 // pageTree holds the treen navigational method for a Page. 29 type pageTree struct { 30 p *pageState 31 } 32 33 func (pt pageTree) IsAncestor(other any) bool { 34 n, ok := other.(contentNodeI) 35 if !ok { 36 return false 37 } 38 39 if n.Path() == pt.p.Path() { 40 return false 41 } 42 43 return strings.HasPrefix(n.Path(), paths.AddTrailingSlash(pt.p.Path())) 44 } 45 46 func (pt pageTree) IsDescendant(other any) bool { 47 n, ok := other.(contentNodeI) 48 if !ok { 49 return false 50 } 51 52 if n.Path() == pt.p.Path() { 53 return false 54 } 55 56 return strings.HasPrefix(pt.p.Path(), paths.AddTrailingSlash(n.Path())) 57 } 58 59 func (pt pageTree) CurrentSection() page.Page { 60 if kinds.IsBranch(pt.p.Kind()) { 61 return pt.p 62 } 63 64 dir := pt.p.m.pathInfo.Dir() 65 if dir == "/" { 66 return pt.p.s.home 67 } 68 69 _, n := pt.p.s.pageMap.treePages.LongestPrefix(dir, true, func(n contentNodeI) bool { return n.isContentNodeBranch() }) 70 if n != nil { 71 return n.(page.Page) 72 } 73 74 panic(fmt.Sprintf("CurrentSection not found for %q in lang %s", pt.p.Path(), pt.p.Lang())) 75 } 76 77 func (pt pageTree) FirstSection() page.Page { 78 s := pt.p.m.pathInfo.Dir() 79 if s == "/" { 80 return pt.p.s.home 81 } 82 83 for { 84 k, n := pt.p.s.pageMap.treePages.LongestPrefix(s, true, func(n contentNodeI) bool { return n.isContentNodeBranch() }) 85 if n == nil { 86 return nil 87 } 88 89 // /blog 90 if strings.Count(k, "/") < 2 { 91 return n.(page.Page) 92 } 93 94 if s == "" { 95 return nil 96 } 97 98 s = paths.Dir(s) 99 100 } 101 } 102 103 func (pt pageTree) InSection(other any) bool { 104 if pt.p == nil || types.IsNil(other) { 105 return false 106 } 107 108 p, ok := other.(page.Page) 109 if !ok { 110 return false 111 } 112 113 return pt.CurrentSection() == p.CurrentSection() 114 } 115 116 func (pt pageTree) Parent() page.Page { 117 if pt.p.IsHome() { 118 return nil 119 } 120 121 dir := pt.p.m.pathInfo.ContainerDir() 122 123 if dir == "" { 124 return pt.p.s.home 125 } 126 127 _, n := pt.p.s.pageMap.treePages.LongestPrefix(dir, true, nil) 128 if n != nil { 129 return n.(page.Page) 130 } 131 return nil 132 } 133 134 func (pt pageTree) Ancestors() page.Pages { 135 var ancestors page.Pages 136 parent := pt.Parent() 137 for parent != nil { 138 ancestors = append(ancestors, parent) 139 parent = parent.Parent() 140 } 141 return ancestors 142 } 143 144 func (pt pageTree) Sections() page.Pages { 145 var ( 146 pages page.Pages 147 currentBranchPrefix string 148 s = pt.p.Path() 149 prefix = paths.AddTrailingSlash(s) 150 tree = pt.p.s.pageMap.treePages 151 ) 152 153 w := &doctree.NodeShiftTreeWalker[contentNodeI]{ 154 Tree: tree, 155 Prefix: prefix, 156 } 157 w.Handle = func(ss string, n contentNodeI, match doctree.DimensionFlag) (bool, error) { 158 if !n.isContentNodeBranch() { 159 return false, nil 160 } 161 if currentBranchPrefix == "" || !strings.HasPrefix(ss, currentBranchPrefix) { 162 if p, ok := n.(*pageState); ok && p.IsSection() && p.m.shouldList(false) && p.Parent() == pt.p { 163 pages = append(pages, p) 164 } else { 165 w.SkipPrefix(ss + "/") 166 } 167 } 168 currentBranchPrefix = ss + "/" 169 return false, nil 170 } 171 172 if err := w.Walk(context.Background()); err != nil { 173 panic(err) 174 } 175 176 page.SortByDefault(pages) 177 return pages 178 } 179 180 func (pt pageTree) Page() page.Page { 181 return pt.p 182 } 183 184 func (p pageTree) SectionsEntries() []string { 185 sp := p.SectionsPath() 186 if sp == "/" { 187 return nil 188 } 189 entries := strings.Split(sp[1:], "/") 190 if len(entries) == 0 { 191 return nil 192 } 193 return entries 194 } 195 196 func (p pageTree) SectionsPath() string { 197 return p.CurrentSection().Path() 198 }