mirror of
https://github.com/byteverse/colonnade.git
synced 2026-09-05 11:43:49 +02:00
add lucid-colonnade
This commit is contained in:
parent
a3d4c36bfa
commit
cb5be2ab25
30
lucid-colonnade/LICENSE
Normal file
30
lucid-colonnade/LICENSE
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
Copyright Andrew Martin (c) 2016
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following
|
||||||
|
disclaimer in the documentation and/or other materials provided
|
||||||
|
with the distribution.
|
||||||
|
|
||||||
|
* Neither the name of Andrew Martin nor the names of other
|
||||||
|
contributors may be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
2
lucid-colonnade/Setup.hs
Normal file
2
lucid-colonnade/Setup.hs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
import Distribution.Simple
|
||||||
|
main = defaultMain
|
||||||
28
lucid-colonnade/lucid-colonnade.cabal
Normal file
28
lucid-colonnade/lucid-colonnade.cabal
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
name: lucid-colonnade
|
||||||
|
version: 1.0
|
||||||
|
synopsis: Helper functions for using lucid with colonnade
|
||||||
|
description: Lucid and colonnade
|
||||||
|
homepage: https://github.com/andrewthad/colonnade#readme
|
||||||
|
license: BSD3
|
||||||
|
license-file: LICENSE
|
||||||
|
author: Andrew Martin
|
||||||
|
maintainer: andrew.thaddeus@gmail.com
|
||||||
|
copyright: 2017 Andrew Martin
|
||||||
|
category: web
|
||||||
|
build-type: Simple
|
||||||
|
cabal-version: >=1.10
|
||||||
|
|
||||||
|
library
|
||||||
|
hs-source-dirs: src
|
||||||
|
exposed-modules:
|
||||||
|
Lucid.Colonnade
|
||||||
|
build-depends:
|
||||||
|
base >= 4.7 && < 5
|
||||||
|
, colonnade >= 1.1 && < 1.3
|
||||||
|
, lucid >= 2.9 && < 3.0
|
||||||
|
, text >= 1.0 && < 1.3
|
||||||
|
default-language: Haskell2010
|
||||||
|
|
||||||
|
source-repository head
|
||||||
|
type: git
|
||||||
|
location: https://github.com/andrewthad/colonnade
|
||||||
193
lucid-colonnade/src/Lucid/Colonnade.hs
Normal file
193
lucid-colonnade/src/Lucid/Colonnade.hs
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
{-# LANGUAGE BangPatterns #-}
|
||||||
|
{-# LANGUAGE ScopedTypeVariables #-}
|
||||||
|
{-# LANGUAGE TypeFamilies #-}
|
||||||
|
|
||||||
|
-- | Build HTML tables using @lucid@ and @colonnade@. It is
|
||||||
|
-- recommended that users read the documentation for @colonnade@ first,
|
||||||
|
-- since this library builds on the abstractions introduced there.
|
||||||
|
-- Also, look at the docs for @blaze-colonnade@. These two
|
||||||
|
-- libraries are similar, but blaze offers an HTML pretty printer
|
||||||
|
-- which makes it possible to doctest examples. Since lucid
|
||||||
|
-- does not offer such facilities, examples are omitted here.
|
||||||
|
module Lucid.Colonnade
|
||||||
|
( -- * Apply
|
||||||
|
encodeHtmlTable
|
||||||
|
, encodeCellTable
|
||||||
|
, encodeTable
|
||||||
|
-- * Cell
|
||||||
|
-- $build
|
||||||
|
, Cell(..)
|
||||||
|
, htmlCell
|
||||||
|
, stringCell
|
||||||
|
, textCell
|
||||||
|
, lazyTextCell
|
||||||
|
, builderCell
|
||||||
|
, htmlFromCell
|
||||||
|
-- * Discussion
|
||||||
|
-- $discussion
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Colonnade (Colonnade,Headed,Headless,Fascia,Cornice)
|
||||||
|
import Data.Text (Text)
|
||||||
|
import Control.Monad
|
||||||
|
import Data.Monoid
|
||||||
|
import Data.Foldable
|
||||||
|
import Data.String (IsString(..))
|
||||||
|
import Data.Maybe (listToMaybe)
|
||||||
|
import Data.Char (isSpace)
|
||||||
|
import Control.Applicative (liftA2)
|
||||||
|
import Lucid
|
||||||
|
import qualified Data.List as List
|
||||||
|
import qualified Colonnade.Encode as E
|
||||||
|
import qualified Data.Text as Text
|
||||||
|
import qualified Data.Text.Lazy as LText
|
||||||
|
import qualified Data.Text.Lazy.Builder as TBuilder
|
||||||
|
|
||||||
|
-- $build
|
||||||
|
--
|
||||||
|
-- The 'Cell' type is used to build a 'Colonnade' that
|
||||||
|
-- has 'Html' content inside table cells and may optionally
|
||||||
|
-- have attributes added to the @\<td\>@ or @\<th\>@ elements
|
||||||
|
-- that wrap this HTML content.
|
||||||
|
|
||||||
|
-- | The attributes that will be applied to a @\<td\>@ and
|
||||||
|
-- the HTML content that will go inside it. When using
|
||||||
|
-- this type, remember that 'Attribute', defined in @blaze-markup@,
|
||||||
|
-- is actually a collection of attributes, not a single attribute.
|
||||||
|
data Cell d = Cell
|
||||||
|
{ cellAttribute :: ![Attribute]
|
||||||
|
, cellHtml :: !(Html d)
|
||||||
|
}
|
||||||
|
|
||||||
|
instance (d ~ ()) => IsString (Cell d) where
|
||||||
|
fromString = stringCell
|
||||||
|
|
||||||
|
instance Monoid d => Monoid (Cell d) where
|
||||||
|
mempty = Cell mempty (return mempty)
|
||||||
|
mappend (Cell a1 c1) (Cell a2 c2) = Cell (mappend a1 a2) (liftA2 mappend c1 c2)
|
||||||
|
|
||||||
|
-- | Create a 'Cell' from a 'Widget'
|
||||||
|
htmlCell :: Html d -> Cell d
|
||||||
|
htmlCell = Cell mempty
|
||||||
|
|
||||||
|
-- | Create a 'Cell' from a 'String'
|
||||||
|
stringCell :: String -> Cell ()
|
||||||
|
stringCell = htmlCell . fromString
|
||||||
|
|
||||||
|
-- | Create a 'Cell' from a 'Char'
|
||||||
|
charCell :: Char -> Cell ()
|
||||||
|
charCell = stringCell . pure
|
||||||
|
|
||||||
|
-- | Create a 'Cell' from a 'Text'
|
||||||
|
textCell :: Text -> Cell ()
|
||||||
|
textCell = htmlCell . toHtml
|
||||||
|
|
||||||
|
-- | Create a 'Cell' from a lazy text
|
||||||
|
lazyTextCell :: LText.Text -> Cell ()
|
||||||
|
lazyTextCell = textCell . LText.toStrict
|
||||||
|
|
||||||
|
-- | Create a 'Cell' from a text builder
|
||||||
|
builderCell :: TBuilder.Builder -> Cell ()
|
||||||
|
builderCell = lazyTextCell . TBuilder.toLazyText
|
||||||
|
|
||||||
|
-- | Encode a table. Table cell element do not have
|
||||||
|
-- any attributes applied to them.
|
||||||
|
encodeHtmlTable ::
|
||||||
|
(E.Headedness h, Foldable f, Monoid d)
|
||||||
|
=> [Attribute] -- ^ Attributes of @\<table\>@ element
|
||||||
|
-> Colonnade h a (Html d) -- ^ How to encode data as columns
|
||||||
|
-> f a -- ^ Collection of data
|
||||||
|
-> Html d
|
||||||
|
encodeHtmlTable = encodeTable
|
||||||
|
(E.headednessPure ([],[])) mempty (const mempty) (\el -> el [])
|
||||||
|
|
||||||
|
-- | Encode a table. Table cells may have attributes applied
|
||||||
|
-- to them
|
||||||
|
encodeCellTable ::
|
||||||
|
(E.Headedness h, Foldable f, Monoid d)
|
||||||
|
=> [Attribute] -- ^ Attributes of @\<table\>@ element
|
||||||
|
-> Colonnade h a (Cell d) -- ^ How to encode data as columns
|
||||||
|
-> f a -- ^ Collection of data
|
||||||
|
-> Html d
|
||||||
|
encodeCellTable = encodeTable
|
||||||
|
(E.headednessPure ([],[])) mempty (const mempty) htmlFromCell
|
||||||
|
|
||||||
|
-- | Encode a table. This handles a very general case and
|
||||||
|
-- is seldom needed by users. One of the arguments provided is
|
||||||
|
-- used to add attributes to the generated @\<tr\>@ elements.
|
||||||
|
-- The elements of type @d@ produced by generating html are
|
||||||
|
-- strictly combined with their monoidal append function.
|
||||||
|
-- However, this type is nearly always @()@.
|
||||||
|
encodeTable :: forall f h a d c.
|
||||||
|
(Foldable f, E.Headedness h, Monoid d)
|
||||||
|
=> h ([Attribute],[Attribute]) -- ^ Attributes of @\<thead\>@ and its @\<tr\>@
|
||||||
|
-> [Attribute] -- ^ Attributes of @\<tbody\>@ element
|
||||||
|
-> (a -> [Attribute]) -- ^ Attributes of each @\<tr\>@ element
|
||||||
|
-> (([Attribute] -> Html d -> Html d) -> c -> Html d) -- ^ Wrap content and convert to 'Html'
|
||||||
|
-> [Attribute] -- ^ Attributes of @\<table\>@ element
|
||||||
|
-> Colonnade h a c -- ^ How to encode data as a row
|
||||||
|
-> f a -- ^ Collection of data
|
||||||
|
-> Html d
|
||||||
|
encodeTable mtheadAttrs tbodyAttrs trAttrs wrapContent tableAttrs colonnade xs =
|
||||||
|
table_ tableAttrs $ do
|
||||||
|
d1 <- case E.headednessExtractForall of
|
||||||
|
Nothing -> return mempty
|
||||||
|
Just extractForall -> do
|
||||||
|
let (theadAttrs,theadTrAttrs) = extract mtheadAttrs
|
||||||
|
thead_ theadAttrs $ tr_ theadTrAttrs $ do
|
||||||
|
foldlMapM' (wrapContent th_ . extract . E.oneColonnadeHead) (E.getColonnade colonnade)
|
||||||
|
where
|
||||||
|
extract :: forall y. h y -> y
|
||||||
|
extract = E.runExtractForall extractForall
|
||||||
|
d2 <- encodeBody trAttrs wrapContent tbodyAttrs colonnade xs
|
||||||
|
return (mappend d1 d2)
|
||||||
|
|
||||||
|
encodeBody :: (Foldable f, Monoid d)
|
||||||
|
=> (a -> [Attribute]) -- ^ Attributes of each @\<tr\>@ element
|
||||||
|
-> (([Attribute] -> Html d -> Html d) -> c -> Html d) -- ^ Wrap content and convert to 'Html'
|
||||||
|
-> [Attribute] -- ^ Attributes of @\<tbody\>@ element
|
||||||
|
-> Colonnade h a c -- ^ How to encode data as a row
|
||||||
|
-> f a -- ^ Collection of data
|
||||||
|
-> Html d
|
||||||
|
encodeBody trAttrs wrapContent tbodyAttrs colonnade xs = do
|
||||||
|
tbody_ tbodyAttrs $ do
|
||||||
|
flip foldlMapM' xs $ \x -> do
|
||||||
|
tr_ (trAttrs x) $ E.rowMonadic colonnade (wrapContent td_) x
|
||||||
|
|
||||||
|
foldlMapM' :: forall g b a m. (Foldable g, Monoid b, Monad m) => (a -> m b) -> g a -> m b
|
||||||
|
foldlMapM' f xs = foldr f' pure xs mempty
|
||||||
|
where
|
||||||
|
f' :: a -> (b -> m b) -> b -> m b
|
||||||
|
f' x k bl = do
|
||||||
|
br <- f x
|
||||||
|
let !b = mappend bl br
|
||||||
|
k b
|
||||||
|
|
||||||
|
-- | Convert a 'Cell' to 'Html' by wrapping the content with a tag
|
||||||
|
-- and applying the 'Cell' attributes to that tag.
|
||||||
|
htmlFromCell :: ([Attribute] -> Html d -> Html d) -> Cell d -> Html d
|
||||||
|
htmlFromCell f (Cell attr content) = f attr content
|
||||||
|
|
||||||
|
-- $discussion
|
||||||
|
--
|
||||||
|
-- In this module, some of the functions for applying a 'Colonnade' to
|
||||||
|
-- some values to build a table have roughly this type signature:
|
||||||
|
--
|
||||||
|
-- > Foldable a => Colonnade Headedness a (Cell d) -> f a -> Html d
|
||||||
|
--
|
||||||
|
-- The 'Colonnade' content type is 'Cell', but the content
|
||||||
|
-- type of the result is 'Html'. It may not be immidiately clear why
|
||||||
|
-- this is done. Another strategy, which this library also
|
||||||
|
-- uses, is to write
|
||||||
|
-- these functions to take a 'Colonnade' whose content is 'Html':
|
||||||
|
--
|
||||||
|
-- > Foldable a => Colonnade Headedness a (Html d) -> f a -> Html d
|
||||||
|
--
|
||||||
|
-- When the 'Colonnade' content type is 'Html', then the header
|
||||||
|
-- content is rendered as the child of a @\<th\>@ and the row
|
||||||
|
-- content the child of a @\<td\>@. However, it is not possible
|
||||||
|
-- to add attributes to these parent elements. To accomodate this
|
||||||
|
-- situation, it is necessary to introduce 'Cell', which includes
|
||||||
|
-- the possibility of attributes on the parent node.
|
||||||
|
|
||||||
|
|
||||||
37
stack.yaml
37
stack.yaml
@ -1,44 +1,9 @@
|
|||||||
# This file was automatically generated by 'stack init'
|
|
||||||
#
|
|
||||||
# Some commonly used options have been documented as comments in this file.
|
|
||||||
# For advanced use and comprehensive documentation of the format, please see:
|
|
||||||
# http://docs.haskellstack.org/en/stable/yaml_configuration/
|
|
||||||
|
|
||||||
# Resolver to choose a 'specific' stackage snapshot or a compiler version.
|
|
||||||
# A snapshot resolver dictates the compiler version and the set of packages
|
|
||||||
# to be used for project dependencies. For example:
|
|
||||||
#
|
|
||||||
# resolver: lts-3.5
|
|
||||||
# resolver: nightly-2015-09-21
|
|
||||||
# resolver: ghc-7.10.2
|
|
||||||
# resolver: ghcjs-0.1.0_ghc-7.10.2
|
|
||||||
# resolver:
|
|
||||||
# name: custom-snapshot
|
|
||||||
# location: "./custom-snapshot.yaml"
|
|
||||||
resolver: lts-8.0
|
resolver: lts-8.0
|
||||||
|
|
||||||
# User packages to be built.
|
|
||||||
# Various formats can be used as shown in the example below.
|
|
||||||
#
|
|
||||||
# packages:
|
|
||||||
# - some-directory
|
|
||||||
# - https://example.com/foo/bar/baz-0.0.2.tar.gz
|
|
||||||
# - location:
|
|
||||||
# git: https://github.com/commercialhaskell/stack.git
|
|
||||||
# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a
|
|
||||||
# - location: https://github.com/commercialhaskell/stack/commit/e7b331f14bcffb8367cd58fbfc8b40ec7642100a
|
|
||||||
# extra-dep: true
|
|
||||||
# subdirs:
|
|
||||||
# - auto-update
|
|
||||||
# - wai
|
|
||||||
#
|
|
||||||
# A package marked 'extra-dep: true' will only be built if demanded by a
|
|
||||||
# non-dependency (i.e. a user package), and its test suites and benchmarks
|
|
||||||
# will not be run. This is useful for tweaking upstream packages.
|
|
||||||
packages:
|
packages:
|
||||||
- 'colonnade'
|
- 'colonnade'
|
||||||
- 'yesod-colonnade'
|
- 'yesod-colonnade'
|
||||||
- 'blaze-colonnade'
|
- 'blaze-colonnade'
|
||||||
|
- 'lucid-colonnade'
|
||||||
- 'siphon'
|
- 'siphon'
|
||||||
# - 'geolite-csv'
|
# - 'geolite-csv'
|
||||||
# Dependency packages to be pulled from upstream that are not in the resolver
|
# Dependency packages to be pulled from upstream that are not in the resolver
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user