flamingo.me/flamingo-commerce/v3@v3.11.0/search/utils/pagination.go (about) 1 package utils 2 3 import ( 4 "fmt" 5 "net/url" 6 "sort" 7 "strconv" 8 ) 9 10 type ( 11 //PaginationConfig - represents configuration Options used by the PaginationInfo Build method 12 PaginationConfig struct { 13 ShowFirstPage bool `inject:"config:commerce.pagination.showFirstPage"` 14 ShowLastPage bool `inject:"config:commerce.pagination.showLastPage"` 15 //ShowAroundActivePageAmount - amount of pages to show before and after the current page (so a value of2 would show 2 pages before and 2 pages after) 16 ShowAroundActivePageAmount float64 `inject:"config:commerce.pagination.showAroundActivePageAmount"` 17 NameSpace string 18 } 19 20 // CurrentResultInfos page information 21 CurrentResultInfos struct { 22 ActivePage int 23 TotalHits int 24 PageSize int 25 LastPage int 26 } 27 28 // PaginationInfo meta information 29 PaginationInfo struct { 30 NextPage *Page 31 PreviousPage *Page 32 TotalHits int 33 PageNavigation []Page 34 } 35 36 // Page page data 37 Page struct { 38 Page int 39 URL string 40 IsActive bool 41 IsSpacer bool 42 } 43 44 // PaginationInfoFactory - used to build a configuration based on configured defaults 45 PaginationInfoFactory struct { 46 DefaultConfig *PaginationConfig `inject:""` 47 } 48 ) 49 50 // BuildWith builds a paginationInfo based on the given infos and config 51 func BuildWith(currentResult CurrentResultInfos, paginationConfig PaginationConfig, urlBase *url.URL) PaginationInfo { 52 if currentResult.PageSize < 1 { 53 currentResult.PageSize = 1 54 } 55 if currentResult.ActivePage < 1 { 56 currentResult.ActivePage = 1 57 } 58 paginationInfo := PaginationInfo{ 59 TotalHits: currentResult.TotalHits, 60 } 61 var pagesToAdd []int 62 if paginationConfig.ShowFirstPage { 63 pagesToAdd = append(pagesToAdd, 1) 64 } 65 if paginationConfig.ShowLastPage { 66 pagesToAdd = append(pagesToAdd, currentResult.LastPage) 67 } 68 if currentResult.ActivePage > 1 { 69 paginationInfo.PreviousPage = &Page{ 70 Page: currentResult.ActivePage - 1, 71 URL: makeURL(urlBase, currentResult.ActivePage-1, paginationConfig.NameSpace), 72 } 73 } 74 if currentResult.ActivePage < currentResult.LastPage { 75 paginationInfo.NextPage = &Page{ 76 Page: currentResult.ActivePage + 1, 77 URL: makeURL(urlBase, currentResult.ActivePage+1, paginationConfig.NameSpace), 78 } 79 } 80 81 pagesToAdd = append(pagesToAdd, currentResult.ActivePage) 82 showAroundActivePageAmount := int(paginationConfig.ShowAroundActivePageAmount) 83 for i := currentResult.ActivePage - showAroundActivePageAmount; i <= currentResult.ActivePage+showAroundActivePageAmount; i++ { 84 if i > 0 && i < currentResult.LastPage { 85 pagesToAdd = append(pagesToAdd, i) 86 } 87 } 88 89 if currentResult.ActivePage == 1 && currentResult.LastPage > currentResult.ActivePage+2 { 90 pagesToAdd = append(pagesToAdd, currentResult.ActivePage+2) 91 } 92 93 if currentResult.ActivePage == currentResult.LastPage && currentResult.LastPage > 2 { 94 pagesToAdd = append(pagesToAdd, currentResult.ActivePage-2) 95 } 96 97 sort.Ints(pagesToAdd) 98 99 previousPageNr := 0 100 for _, pageNr := range pagesToAdd { 101 //guard same pages / deduplication 102 if previousPageNr == pageNr { 103 continue 104 } 105 // add spacer if not subsequent pages 106 if pageNr > previousPageNr+1 { 107 paginationInfo.PageNavigation = append(paginationInfo.PageNavigation, Page{ 108 IsSpacer: true, 109 }) 110 } 111 page := Page{ 112 Page: pageNr, 113 IsActive: pageNr == currentResult.ActivePage, 114 IsSpacer: false, 115 URL: makeURL(urlBase, pageNr, paginationConfig.NameSpace), 116 } 117 paginationInfo.PageNavigation = append(paginationInfo.PageNavigation, page) 118 previousPageNr = pageNr 119 } 120 return paginationInfo 121 } 122 123 // Build Pagination with the default configuration 124 func (f *PaginationInfoFactory) Build(activePage int, totalHits int, pageSize int, lastPage int, urlBase *url.URL) PaginationInfo { 125 return BuildWith(CurrentResultInfos{ 126 ActivePage: activePage, 127 TotalHits: totalHits, 128 PageSize: pageSize, 129 LastPage: lastPage, 130 }, *f.DefaultConfig, urlBase) 131 } 132 133 func makeURL(base *url.URL, page int, namespace string) string { 134 q := base.Query() 135 parameterName := "page" 136 if namespace != "" { 137 parameterName = fmt.Sprintf("%v.%v", namespace, "page") 138 } 139 q.Set(parameterName, strconv.Itoa(page)) 140 return (&url.URL{RawQuery: q.Encode()}).String() 141 }