mirror of
https://code.naskya.net/repos/ndqEd
synced 2025-03-20 15:14:54 +09:00
161 lines
4.5 KiB
Haskell
161 lines
4.5 KiB
Haskell
{- This file is part of Vervis.
|
|
-
|
|
- Written in 2016 by fr33domlover <fr33domlover@riseup.net>.
|
|
-
|
|
- ♡ Copying is an act of love. Please copy, reuse and share.
|
|
-
|
|
- The author(s) have dedicated all copyright and related and neighboring
|
|
- rights to this software to the public domain worldwide. This software is
|
|
- distributed without any warranty.
|
|
-
|
|
- You should have received a copy of the CC0 Public Domain Dedication along
|
|
- with this software. If not, see
|
|
- <http://creativecommons.org/publicdomain/zero/1.0/>.
|
|
-}
|
|
|
|
module Data.Paginate.Local
|
|
( -- * Settings
|
|
-- ** Jump settings
|
|
JumpSettings ()
|
|
, jumpMin
|
|
, jumpFactor
|
|
, jumpRound
|
|
-- ** Navigation settings
|
|
, NavSettings ()
|
|
, navEdges
|
|
, navJump
|
|
, navNext
|
|
-- ** Pagination settings
|
|
, PaginateSettings ()
|
|
, psSelect
|
|
, psCurrent
|
|
, psPer
|
|
-- * Results
|
|
-- ** Navigation controls
|
|
, NavModel ()
|
|
, nmFirst
|
|
, nmPrevJumps
|
|
, nmPrev
|
|
, nmCurrent
|
|
, nmTotal
|
|
, nmNext
|
|
, nmNextJumps
|
|
, nmLast
|
|
-- ** Paginate
|
|
, paginate
|
|
)
|
|
where
|
|
|
|
import Prelude
|
|
|
|
import Data.Default.Class
|
|
import Data.Ratio
|
|
|
|
data JumpSettings = JumpSettings
|
|
{ -- | Minimal jump size to display. Smaller jumps will be discarded.
|
|
jumpMin :: Int
|
|
-- | Ratio of size of consecutive jumps.
|
|
, jumpFactor :: Ratio Int
|
|
-- | Round jump page numbers to be multiples of this number. 1 means no
|
|
-- rounding. 10 means all jumps will be to page numbers that are
|
|
-- multiples of 10. And so on.
|
|
, jumpRound :: Int
|
|
}
|
|
|
|
instance Default JumpSettings where
|
|
def = JumpSettings
|
|
{ jumpMin = 10
|
|
, jumpFactor = 2 % 3
|
|
, jumpRound = 10
|
|
}
|
|
|
|
data NavSettings = NavSettings
|
|
{ -- | Whether to always show links to first and last pages
|
|
navEdges :: Bool
|
|
-- | Whether and how to show jump links
|
|
, navJump :: Maybe JumpSettings
|
|
-- | Number of next\/prev page links to show on each side of the current
|
|
-- page.
|
|
, navNext :: Int
|
|
}
|
|
|
|
instance Default NavSettings where
|
|
def = NavSettings
|
|
{ navEdges = True
|
|
, navJump = Just def
|
|
, navNext = 3
|
|
}
|
|
|
|
data PaginateSettings m f i = PaginateSettings
|
|
{ -- | Get the total number of items being paginated, and given an offset
|
|
-- and a limit, get the specified subset of the items. The offset tells
|
|
-- you how many items to skip from the beginning of the list, and then
|
|
-- the limit says how many items you should take after skipping.
|
|
psSelect :: Int -> Int -> m (Int, f i)
|
|
-- | Get the current page
|
|
, psCurrent :: m Int
|
|
-- | How many items to list in one page
|
|
, psPer :: Int
|
|
}
|
|
|
|
instance Default (PaginateSettings m f i) where
|
|
def = PaginateSettings
|
|
{ psSelect = error "You didn't implement psSelect"
|
|
, psCurrent = error "You didn't implement psCurrent"
|
|
, psPer = 30
|
|
}
|
|
|
|
data NavModel = NavModel
|
|
{
|
|
nmFirst :: Bool
|
|
, nmPrevJumps :: [Int]
|
|
, nmPrev :: [Int]
|
|
, nmCurrent :: Int
|
|
, nmTotal :: Int
|
|
, nmNext :: [Int]
|
|
, nmNextJumps :: [Int]
|
|
, nmLast :: Bool
|
|
}
|
|
|
|
-- | Given the number of items per page and the current page number, determine
|
|
-- the offset and limit.
|
|
subseq :: Int -> Int -> (Int, Int)
|
|
subseq per curr =
|
|
let offset = (curr - 1) * per
|
|
limit = per
|
|
in (offset, limit)
|
|
|
|
navModel :: NavSettings -> Int -> Int -> NavModel
|
|
navModel ns curr total = NavModel
|
|
{ nmFirst = navEdges ns
|
|
, nmPrevJumps = [] --TODO
|
|
, nmPrev =
|
|
if curr == 1 || navNext ns < 1
|
|
then []
|
|
else [max 1 (curr - navNext ns) .. curr - 1]
|
|
, nmCurrent = curr
|
|
, nmTotal = total
|
|
, nmNext =
|
|
if curr >= total || navNext ns < 1
|
|
then []
|
|
else [curr + 1 .. min total (curr + navNext ns)]
|
|
, nmNextJumps = [] --TODO
|
|
, nmLast = navEdges ns
|
|
}
|
|
|
|
-- | Get a page's contents and its navigation controls.
|
|
paginate
|
|
:: Monad m
|
|
=> PaginateSettings m f i
|
|
-- ^ How to get the page contents and split them into pages
|
|
-> NavSettings
|
|
-- ^ How to build page navigation controls for the user interface
|
|
-> m (f i, NavModel)
|
|
-- ^ The items in the current page, and the navigation controls
|
|
paginate ps ns = do
|
|
curr <- psCurrent ps
|
|
let (offset, limit) = subseq (psPer ps) curr
|
|
(total, items) <- psSelect ps offset limit
|
|
let (d, m) = total `divMod` psPer ps
|
|
pages = if m == 0 then d else d + 1
|
|
return (items, navModel ns curr pages)
|