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  }