Use binding mechanism for the Pagination component
- Rename PaginationEvent to PaginateEvent - Add PaginationBinder interface
This commit is contained in:
parent
37d42e9a94
commit
c149bbfc06
@ -2,22 +2,22 @@ package navigation
|
|||||||
|
|
||||||
import "github.com/vugu/vugu"
|
import "github.com/vugu/vugu"
|
||||||
|
|
||||||
type PaginationEvent struct {
|
type PaginateEvent struct {
|
||||||
vugu.DOMEvent
|
vugu.DOMEvent
|
||||||
|
|
||||||
Page int
|
PaginationInfo // The current state of the pagination component.
|
||||||
}
|
}
|
||||||
|
|
||||||
// PaginationHandler is the interface for things that can handle PaginationEvent.
|
// PaginationHandler is the interface for things that can handle PaginationEvent.
|
||||||
type PaginationHandler interface {
|
type PaginateHandler interface {
|
||||||
PaginationHandle(event PaginationEvent)
|
PaginateHandle(event PaginateEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PaginationFunc implements PaginationHandler as a function.
|
// PaginateFunc implements PaginateHandler as a function.
|
||||||
type PaginationFunc func(event PaginationEvent)
|
type PaginateFunc func(event PaginateEvent)
|
||||||
|
|
||||||
// PaginationHandle implements the PaginationHandler interface.
|
// PaginateHandle implements the PaginateHandler interface.
|
||||||
func (f PaginationFunc) PaginationHandle(event PaginationEvent) { f(event) }
|
func (f PaginateFunc) PaginateHandle(event PaginateEvent) { f(event) }
|
||||||
|
|
||||||
// assert PaginationFunc implements PaginationHandler.
|
// assert PaginateFunc implements PaginateHandler.
|
||||||
var _ PaginationHandler = PaginationFunc(nil)
|
var _ PaginateHandler = PaginateFunc(nil)
|
||||||
|
26
components/navigation/pagination-binder.go
Normal file
26
components/navigation/pagination-binder.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package navigation
|
||||||
|
|
||||||
|
// PaginationBinder is an interface that everything that every type that wants to bind to an pagination component must implement.
|
||||||
|
type PaginationBinder interface {
|
||||||
|
Page() int // Page returns the current page, as a 1-based index. A value of 0 means there is no active page.
|
||||||
|
Pages() int // Pages returns the total number of pages.
|
||||||
|
SetPage(page int) // SetPage changes the current page as a 1-based index. A value of 0 means there is no active page.
|
||||||
|
}
|
||||||
|
|
||||||
|
// PaginationInfo implements the PaginationBinder interface and represents the current state of a pagination component.
|
||||||
|
type PaginationInfo struct {
|
||||||
|
CurrentPage int // The current page as a 1-based index. A value of 0 means there is no current page.
|
||||||
|
TotalPages int // The number of total pages.
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PaginationInfo) Page() int {
|
||||||
|
return p.CurrentPage
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PaginationInfo) Pages() int {
|
||||||
|
return p.TotalPages
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PaginationInfo) SetPage(page int) {
|
||||||
|
p.CurrentPage = page
|
||||||
|
}
|
@ -10,10 +10,9 @@ type Pagination struct {
|
|||||||
|
|
||||||
buttons []paginationButtonInfo
|
buttons []paginationButtonInfo
|
||||||
|
|
||||||
Page int `vugu:"data"`
|
Bind PaginationBinder
|
||||||
Pages int `vugu:"data"`
|
|
||||||
|
|
||||||
Pagination PaginationHandler // External handler that is called upon an event.
|
Paginate PaginateHandler // External handler that is called upon an event.
|
||||||
}
|
}
|
||||||
|
|
||||||
type paginationButtonInfo struct {
|
type paginationButtonInfo struct {
|
||||||
@ -21,32 +20,55 @@ type paginationButtonInfo struct {
|
|||||||
Class string
|
Class string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Pagination) Page() int {
|
||||||
|
if c.Bind == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Bind.Page()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Pagination) Pages() int {
|
||||||
|
if c.Bind == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Bind.Pages()
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Pagination) handleClickPrev(event input.ClickEvent) {
|
func (c *Pagination) handleClickPrev(event input.ClickEvent) {
|
||||||
c.handleClickPage(event, c.Page-1)
|
c.handleClickPage(event, c.Page()-1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Pagination) handleClickNext(event input.ClickEvent) {
|
func (c *Pagination) handleClickNext(event input.ClickEvent) {
|
||||||
c.handleClickPage(event, c.Page+1)
|
c.handleClickPage(event, c.Page()+1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Pagination) handleClickPage(event input.ClickEvent, page int) {
|
func (c *Pagination) handleClickPage(event input.ClickEvent, page int) {
|
||||||
if page <= 0 || page > c.Pages {
|
pages := c.Pages()
|
||||||
|
|
||||||
|
if page <= 0 || page > pages {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.Pagination != nil {
|
if c.Bind != nil {
|
||||||
c.Pagination.PaginationHandle(PaginationEvent{
|
c.Bind.SetPage(page)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Paginate != nil {
|
||||||
|
c.Paginate.PaginateHandle(PaginateEvent{
|
||||||
DOMEvent: event,
|
DOMEvent: event,
|
||||||
Page: page,
|
PaginationInfo: PaginationInfo{
|
||||||
|
CurrentPage: page,
|
||||||
|
TotalPages: pages,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Pagination) Init(ctx vugu.InitCtx) {
|
|
||||||
c.Pages = 10
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Pagination) Compute(ctx vugu.ComputeCtx) {
|
func (c *Pagination) Compute(ctx vugu.ComputeCtx) {
|
||||||
|
page, pages := c.Page(), c.Pages()
|
||||||
|
|
||||||
// Number of buttons around the current page.
|
// Number of buttons around the current page.
|
||||||
// Excluding first and last page.
|
// Excluding first and last page.
|
||||||
const AroundButtons = 2
|
const AroundButtons = 2
|
||||||
@ -60,15 +82,15 @@ func (c *Pagination) Compute(ctx vugu.ComputeCtx) {
|
|||||||
// Prepare buttons.
|
// Prepare buttons.
|
||||||
buttons := [TotalButtons]paginationButtonInfo{
|
buttons := [TotalButtons]paginationButtonInfo{
|
||||||
0: {Page: 1},
|
0: {Page: 1},
|
||||||
TotalButtons - 1: {Page: c.Pages},
|
TotalButtons - 1: {Page: pages},
|
||||||
}
|
}
|
||||||
|
|
||||||
startPage := 2
|
startPage := 2
|
||||||
if startPage < c.Page-AroundButtons {
|
if startPage < page-AroundButtons {
|
||||||
startPage = c.Page - AroundButtons
|
startPage = page - AroundButtons
|
||||||
}
|
}
|
||||||
if startPage > c.Pages-DynamicButtons {
|
if startPage > pages-DynamicButtons {
|
||||||
startPage = c.Pages - DynamicButtons
|
startPage = pages - DynamicButtons
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < DynamicButtons; i++ {
|
for i := 0; i < DynamicButtons; i++ {
|
||||||
@ -79,13 +101,13 @@ func (c *Pagination) Compute(ctx vugu.ComputeCtx) {
|
|||||||
// pageCounter is used to check if pages are strictly monotonically increasing.
|
// pageCounter is used to check if pages are strictly monotonically increasing.
|
||||||
buttonsFiltered := make([]paginationButtonInfo, 0, len(buttons))
|
buttonsFiltered := make([]paginationButtonInfo, 0, len(buttons))
|
||||||
pageCounter := 0
|
pageCounter := 0
|
||||||
for _, page := range buttons {
|
for _, pageInfo := range buttons {
|
||||||
if pageCounter < page.Page && page.Page <= c.Pages {
|
if pageCounter < pageInfo.Page && pageInfo.Page <= pages {
|
||||||
pageCounter = page.Page
|
pageCounter = pageInfo.Page
|
||||||
if page.Page == c.Page {
|
if pageInfo.Page == page {
|
||||||
page.Class = "d3c-button-highlight"
|
pageInfo.Class = "d3c-button-highlight"
|
||||||
}
|
}
|
||||||
buttonsFiltered = append(buttonsFiltered, page)
|
buttonsFiltered = append(buttonsFiltered, pageInfo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,15 +8,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type PageLayout struct {
|
type PageLayout struct {
|
||||||
Page int `vugu:"data"`
|
Pagination navigation.PaginationInfo `vugu:"data"`
|
||||||
Pages int `vugu:"data"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *PageLayout) Init(ctx vugu.InitCtx) {
|
func (c *PageLayout) Init(ctx vugu.InitCtx) {
|
||||||
c.Pages = 10
|
c.Pagination.CurrentPage = 2
|
||||||
|
c.Pagination.TotalPages = 10
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *PageLayout) handlePagination(event navigation.PaginationEvent) {
|
func (c *PageLayout) handlePagination(event navigation.PaginateEvent) {
|
||||||
log.Printf("Some page %v", event.Page)
|
log.Printf("Current pagination info: %v", event.PaginationInfo)
|
||||||
c.Page = event.Page
|
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<h1>Layout</h1>
|
<h1>Layout</h1>
|
||||||
<p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.</p>
|
<p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.</p>
|
||||||
<h2>Items</h2>
|
<h2>Items</h2>
|
||||||
<navigation:Pagination :Page="c.Page" :Pages="c.Pages" @Pagination="c.handlePagination(event)"></navigation:Pagination>
|
<navigation:Pagination :Bind="&c.Pagination" @Paginate="c.handlePagination(event)"></navigation:Pagination>
|
||||||
<main:ComponentAddress Name="Max Mustermann" Street="Musterstraße 45" PostalCode="12345" City="Musterstadt" Country="Germany"></main:ComponentAddress>
|
<main:ComponentAddress Name="Max Mustermann" Street="Musterstraße 45" PostalCode="12345" City="Musterstadt" Country="Germany"></main:ComponentAddress>
|
||||||
</layout:Container>
|
</layout:Container>
|
||||||
</div>
|
</div>
|
||||||
|
@ -28,7 +28,7 @@ func (c *PageLayout) Build(vgin *vugu.BuildIn) (vgout *vugu.BuildOut) {
|
|||||||
vgn = &vugu.VGNode{Type: vugu.VGNodeType(1), Data: "\n\t"}
|
vgn = &vugu.VGNode{Type: vugu.VGNodeType(1), Data: "\n\t"}
|
||||||
vgparent.AppendChild(vgn)
|
vgparent.AppendChild(vgn)
|
||||||
{
|
{
|
||||||
vgcompKey := vugu.MakeCompKey(0x3467920B61750485^vgin.CurrentPositionHash(), vgiterkey)
|
vgcompKey := vugu.MakeCompKey(0x60B66E06F722C68^vgin.CurrentPositionHash(), vgiterkey)
|
||||||
// ask BuildEnv for prior instance of this specific component
|
// ask BuildEnv for prior instance of this specific component
|
||||||
vgcomp, _ := vgin.BuildEnv.CachedComponent(vgcompKey).(*layout.Container)
|
vgcomp, _ := vgin.BuildEnv.CachedComponent(vgcompKey).(*layout.Container)
|
||||||
if vgcomp == nil {
|
if vgcomp == nil {
|
||||||
@ -62,7 +62,7 @@ func (c *PageLayout) Build(vgin *vugu.BuildIn) (vgout *vugu.BuildOut) {
|
|||||||
vgn = &vugu.VGNode{Type: vugu.VGNodeType(1), Data: "\n\t\t"}
|
vgn = &vugu.VGNode{Type: vugu.VGNodeType(1), Data: "\n\t\t"}
|
||||||
vgparent.AppendChild(vgn)
|
vgparent.AppendChild(vgn)
|
||||||
{
|
{
|
||||||
vgcompKey := vugu.MakeCompKey(0x6A61FD21D9782C05^vgin.CurrentPositionHash(), vgiterkey)
|
vgcompKey := vugu.MakeCompKey(0xD22F5BB58705C5DF^vgin.CurrentPositionHash(), vgiterkey)
|
||||||
// ask BuildEnv for prior instance of this specific component
|
// ask BuildEnv for prior instance of this specific component
|
||||||
vgcomp, _ := vgin.BuildEnv.CachedComponent(vgcompKey).(*navigation.Pagination)
|
vgcomp, _ := vgin.BuildEnv.CachedComponent(vgcompKey).(*navigation.Pagination)
|
||||||
if vgcomp == nil {
|
if vgcomp == nil {
|
||||||
@ -71,9 +71,8 @@ func (c *PageLayout) Build(vgin *vugu.BuildIn) (vgout *vugu.BuildOut) {
|
|||||||
vgin.BuildEnv.WireComponent(vgcomp)
|
vgin.BuildEnv.WireComponent(vgcomp)
|
||||||
}
|
}
|
||||||
vgin.BuildEnv.UseComponent(vgcompKey, vgcomp) // ensure we can use this in the cache next time around
|
vgin.BuildEnv.UseComponent(vgcompKey, vgcomp) // ensure we can use this in the cache next time around
|
||||||
vgcomp.Page = c.Page
|
vgcomp.Bind = &c.Pagination
|
||||||
vgcomp.Pages = c.Pages
|
vgcomp.Paginate = navigation.PaginateFunc(func(event navigation.PaginateEvent) { c.handlePagination(event) })
|
||||||
vgcomp.Pagination = navigation.PaginationFunc(func(event navigation.PaginationEvent) { c.handlePagination(event) })
|
|
||||||
vgout.Components = append(vgout.Components, vgcomp)
|
vgout.Components = append(vgout.Components, vgcomp)
|
||||||
vgn = &vugu.VGNode{Component: vgcomp}
|
vgn = &vugu.VGNode{Component: vgcomp}
|
||||||
vgparent.AppendChild(vgn)
|
vgparent.AppendChild(vgn)
|
||||||
@ -81,7 +80,7 @@ func (c *PageLayout) Build(vgin *vugu.BuildIn) (vgout *vugu.BuildOut) {
|
|||||||
vgn = &vugu.VGNode{Type: vugu.VGNodeType(1), Data: "\n\t\t"}
|
vgn = &vugu.VGNode{Type: vugu.VGNodeType(1), Data: "\n\t\t"}
|
||||||
vgparent.AppendChild(vgn)
|
vgparent.AppendChild(vgn)
|
||||||
{
|
{
|
||||||
vgcompKey := vugu.MakeCompKey(0xD67C1752436E9AB1^vgin.CurrentPositionHash(), vgiterkey)
|
vgcompKey := vugu.MakeCompKey(0xE6379FC706A49E07^vgin.CurrentPositionHash(), vgiterkey)
|
||||||
// ask BuildEnv for prior instance of this specific component
|
// ask BuildEnv for prior instance of this specific component
|
||||||
vgcomp, _ := vgin.BuildEnv.CachedComponent(vgcompKey).(*ComponentAddress)
|
vgcomp, _ := vgin.BuildEnv.CachedComponent(vgcompKey).(*ComponentAddress)
|
||||||
if vgcomp == nil {
|
if vgcomp == nil {
|
||||||
|
Loading…
Reference in New Issue
Block a user