Get more flexible API working
This commit is contained in:
parent
5de13f7561
commit
a0ac286ac3
|
@ -25,7 +25,7 @@ type alias Model =
|
||||||
|
|
||||||
init : List Person -> ( Model, Cmd Msg )
|
init : List Person -> ( Model, Cmd Msg )
|
||||||
init people =
|
init people =
|
||||||
( Model people (Table.ascending "Year")
|
( Model people (Table.initialSort "Year")
|
||||||
, Cmd.none
|
, Cmd.none
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
145
src/Table.elm
145
src/Table.elm
|
@ -1,10 +1,12 @@
|
||||||
module Table exposing
|
module Table exposing
|
||||||
( view
|
( view
|
||||||
|
, config, stringColumn, intColumn, floatColumn
|
||||||
, State, initialSort
|
, State, initialSort
|
||||||
, Config, config
|
, Column, customColumn, veryCustomColumn
|
||||||
, Column, stringColumn, intColumn, floatColumn, column
|
|
||||||
, Sorter, unsortable, increasingBy, decreasingBy
|
, Sorter, unsortable, increasingBy, decreasingBy
|
||||||
, increasingOrDecreasingBy, decreasingOrIncreasingBy
|
, increasingOrDecreasingBy, decreasingOrIncreasingBy
|
||||||
|
, Config, customConfig
|
||||||
|
, Customizations, HtmlDetails, Status(..)
|
||||||
)
|
)
|
||||||
|
|
||||||
{-|
|
{-|
|
||||||
|
@ -20,12 +22,15 @@ I recommend checking out the [examples][] to get a feel for how it works.
|
||||||
[examples]: https://github.com/evancz/elm-tables/tree/master/examples
|
[examples]: https://github.com/evancz/elm-tables/tree/master/examples
|
||||||
|
|
||||||
# View
|
# View
|
||||||
|
|
||||||
@docs view
|
@docs view
|
||||||
|
|
||||||
# Configuration
|
# Configuration
|
||||||
|
|
||||||
@docs config, stringColumn, intColumn, floatColumn
|
@docs config, stringColumn, intColumn, floatColumn
|
||||||
|
|
||||||
# State
|
# State
|
||||||
|
|
||||||
@docs State, initialSort
|
@docs State, initialSort
|
||||||
|
|
||||||
|
|
||||||
|
@ -44,8 +49,7 @@ is not that crazy.
|
||||||
|
|
||||||
## Custom Tables
|
## Custom Tables
|
||||||
|
|
||||||
@docs Config, customConfig,
|
@docs Config, customConfig, Customizations, HtmlDetails, Status
|
||||||
Customizations, HtmlDetails, Status, defaultCustomizations
|
|
||||||
-}
|
-}
|
||||||
|
|
||||||
import Html exposing (Html, Attribute)
|
import Html exposing (Html, Attribute)
|
||||||
|
@ -53,6 +57,7 @@ import Html.Attributes as Attr
|
||||||
import Html.Events as E
|
import Html.Events as E
|
||||||
import Html.Keyed as Keyed
|
import Html.Keyed as Keyed
|
||||||
import Html.Lazy exposing (lazy2, lazy3)
|
import Html.Lazy exposing (lazy2, lazy3)
|
||||||
|
import Json.Decode as Json
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -91,7 +96,7 @@ type Config data msg =
|
||||||
Config
|
Config
|
||||||
{ toId : data -> String
|
{ toId : data -> String
|
||||||
, toMsg : State -> msg
|
, toMsg : State -> msg
|
||||||
, columns : List (Column data msg)
|
, columns : List (ColumnData data msg)
|
||||||
, customizations : Customizations data msg
|
, customizations : Customizations data msg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,6 +149,8 @@ config { toId, toMsg, columns } =
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{-| Just like `config` but you can specify a bunch of table customizations.
|
||||||
|
-}
|
||||||
customConfig
|
customConfig
|
||||||
: { toId : data -> String
|
: { toId : data -> String
|
||||||
, toMsg : State -> msg
|
, toMsg : State -> msg
|
||||||
|
@ -171,7 +178,7 @@ high that I could not see how to provide the full functionality *and* make it
|
||||||
impossible to do bad stuff. So just be aware of that, and share any stories
|
impossible to do bad stuff. So just be aware of that, and share any stories
|
||||||
you have. Stories make it possible to design better!
|
you have. Stories make it possible to design better!
|
||||||
-}
|
-}
|
||||||
type alias Cusomizations data msg =
|
type alias Customizations data msg =
|
||||||
{ tableAttrs : List (Attribute msg)
|
{ tableAttrs : List (Attribute msg)
|
||||||
, caption : Maybe (HtmlDetails msg)
|
, caption : Maybe (HtmlDetails msg)
|
||||||
, thead : List (String, Status, Attribute msg) -> HtmlDetails msg
|
, thead : List (String, Status, Attribute msg) -> HtmlDetails msg
|
||||||
|
@ -213,20 +220,20 @@ simpleTheadHelp (name, status, onClick) =
|
||||||
content =
|
content =
|
||||||
case status of
|
case status of
|
||||||
Unsortable ->
|
Unsortable ->
|
||||||
[ text name ]
|
[ Html.text name ]
|
||||||
|
|
||||||
Sortable selected ->
|
Sortable selected ->
|
||||||
[ text name
|
[ Html.text name
|
||||||
, if selected then darkGrey "↓" else lightGrey "↓"
|
, if selected then darkGrey "↓" else lightGrey "↓"
|
||||||
]
|
]
|
||||||
|
|
||||||
Reversable Nothing ->
|
Reversible Nothing ->
|
||||||
[ text name
|
[ Html.text name
|
||||||
, lightGrey "↕"
|
, lightGrey "↕"
|
||||||
]
|
]
|
||||||
|
|
||||||
Reversable (Just isReversed) ->
|
Reversible (Just isReversed) ->
|
||||||
[ text name
|
[ Html.text name
|
||||||
, darkGrey (if isReversed then "↑" else "↓")
|
, darkGrey (if isReversed then "↑" else "↓")
|
||||||
]
|
]
|
||||||
in
|
in
|
||||||
|
@ -235,23 +242,38 @@ simpleTheadHelp (name, status, onClick) =
|
||||||
|
|
||||||
darkGrey : String -> Html msg
|
darkGrey : String -> Html msg
|
||||||
darkGrey symbol =
|
darkGrey symbol =
|
||||||
Html.span [ Attr.style [("color", "#ccc")] ] [ Html.text (" " ++ symbol) ]
|
Html.span [ Attr.style [("color", "#555")] ] [ Html.text (" " ++ symbol) ]
|
||||||
|
|
||||||
|
|
||||||
lightGrey : String -> Html msg
|
lightGrey : String -> Html msg
|
||||||
lightGrey symbol =
|
lightGrey symbol =
|
||||||
Html.span [ Attr.style [("color", "#999")] ] [ Html.text (" " ++ symbol) ]
|
Html.span [ Attr.style [("color", "#ccc")] ] [ Html.text (" " ++ symbol) ]
|
||||||
|
|
||||||
|
|
||||||
simpleRowAttrs : data -> Attribute msg
|
simpleRowAttrs : data -> List (Attribute msg)
|
||||||
simpleRowAttrs _ =
|
simpleRowAttrs _ =
|
||||||
[]
|
[]
|
||||||
|
|
||||||
|
|
||||||
|
{-| The status of a particular column, for use in the `thead` field of your
|
||||||
|
`Customizations`.
|
||||||
|
|
||||||
|
- If the column is unsortable, the status will always be `Unsortable`.
|
||||||
|
- If the column can be sorted in one direction, the status will be `Sortable`.
|
||||||
|
The associated boolean represents whether this column is selected. So it is
|
||||||
|
`True` if the table is currently sorted by this column, and `False` otherwise.
|
||||||
|
- If the column can be sorted in either direction, the status will be `Reversible`.
|
||||||
|
The associated maybe tells you whether this column is selected. It is
|
||||||
|
`Just isReversed` if the table is currently sorted by this column, and
|
||||||
|
`Nothing` otherwise. The `isReversed` boolean lets you know which way it
|
||||||
|
is sorted.
|
||||||
|
|
||||||
|
This information lets you do custom header decorations for each scenario.
|
||||||
|
-}
|
||||||
type Status
|
type Status
|
||||||
= Unsortable
|
= Unsortable
|
||||||
| Sortable Bool
|
| Sortable Bool
|
||||||
| Reversable (Maybe Bool)
|
| Reversible (Maybe Bool)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -397,21 +419,22 @@ view (Config { toId, toMsg, columns, customizations }) state data =
|
||||||
sort state columns data
|
sort state columns data
|
||||||
|
|
||||||
theadDetails =
|
theadDetails =
|
||||||
customizations.thead (List.map Debug.crash columns)
|
customizations.thead (List.map (toHeaderInfo state toMsg) columns)
|
||||||
|
|
||||||
thead =
|
thead =
|
||||||
Html.thead theadDetails.attributes theadDetails.children
|
Html.thead theadDetails.attributes theadDetails.children
|
||||||
|
|
||||||
tbody =
|
tbody =
|
||||||
List.map (viewRow toId columns) sortedData
|
Keyed.node "tbody" customizations.tbodyAttrs <|
|
||||||
|
List.map (viewRow toId columns customizations.rowAttrs) sortedData
|
||||||
|
|
||||||
withFoot =
|
withFoot =
|
||||||
case customizations.tfoot of
|
case customizations.tfoot of
|
||||||
Nothing ->
|
Nothing ->
|
||||||
tbody
|
tbody :: []
|
||||||
|
|
||||||
Just { attributes, children } ->
|
Just { attributes, children } ->
|
||||||
Html.tfoot attributes children :: tbody
|
Html.tfoot attributes children :: tbody :: []
|
||||||
in
|
in
|
||||||
Html.table customizations.tableAttrs <|
|
Html.table customizations.tableAttrs <|
|
||||||
case customizations.caption of
|
case customizations.caption of
|
||||||
|
@ -422,52 +445,60 @@ view (Config { toId, toMsg, columns, customizations }) state data =
|
||||||
Html.caption attributes children :: thead :: withFoot
|
Html.caption attributes children :: thead :: withFoot
|
||||||
|
|
||||||
|
|
||||||
viewHeader : List (ColumnData a msg) -> (State -> msg) -> State -> Html msg
|
toHeaderInfo : State -> (State -> msg) -> ColumnData data msg -> ( String, Status, Attribute msg )
|
||||||
viewHeader columnData toMsg state =
|
toHeaderInfo (State sortName isReversed) toMsg { name, sorter } =
|
||||||
Html.tr [] (List.map (lazy3 viewHeaderHelp toMsg state) columnData)
|
|
||||||
|
|
||||||
|
|
||||||
viewHeaderHelp : (State -> msg) -> State -> ColumnData a msg -> Html msg
|
|
||||||
viewHeaderHelp toMsg state ({name} as column) =
|
|
||||||
let
|
let
|
||||||
|
(status, newIsReversed) =
|
||||||
|
case sorter of
|
||||||
|
None ->
|
||||||
|
( Unsortable, False )
|
||||||
|
|
||||||
Html.th
|
Increasing _ ->
|
||||||
[ class (String.join " " classes)
|
( Sortable (name == sortName), False )
|
||||||
, onClick name state toMsg
|
|
||||||
]
|
Decreasing _ ->
|
||||||
[ html
|
( Sortable (name == sortName), False )
|
||||||
]
|
|
||||||
|
IncOrDec _ ->
|
||||||
|
if name == sortName then
|
||||||
|
( Reversible (Just isReversed), not isReversed )
|
||||||
|
else
|
||||||
|
( Reversible Nothing, False )
|
||||||
|
|
||||||
|
DecOrInc _ ->
|
||||||
|
if name == sortName then
|
||||||
|
( Reversible (Just isReversed), not isReversed )
|
||||||
|
else
|
||||||
|
( Reversible Nothing, False )
|
||||||
|
in
|
||||||
|
( name, status, onClick name newIsReversed toMsg )
|
||||||
|
|
||||||
|
|
||||||
onClick : String -> State -> (State -> msg) -> Attribute msg
|
onClick : String -> Bool -> (State -> msg) -> Attribute msg
|
||||||
onClick name (State selectedColumn isReversed) toMsg =
|
onClick name isReversed toMsg =
|
||||||
E.on "click" <| Json.map toMsg <|
|
E.on "click" <| Json.map toMsg <|
|
||||||
Json.object2
|
Json.object2 State (Json.succeed name) (Json.succeed isReversed)
|
||||||
State
|
|
||||||
(Json.succed name)
|
|
||||||
(Json.succed (name == selectedColumn && not isReversed)
|
|
||||||
|
|
||||||
|
|
||||||
descendingClass : Attribute msg
|
viewRow : (data -> String) -> List (ColumnData data msg) -> (data -> List (Attribute msg)) -> data -> ( String, Html msg )
|
||||||
descendingClass =
|
viewRow toId columns toRowAttrs data =
|
||||||
class "elm-table-selected elm-table-descending"
|
( toId data
|
||||||
|
, lazy3 viewRowHelp columns toRowAttrs data
|
||||||
|
|
||||||
ascendingClass : Attribute msg
|
|
||||||
ascendingClass =
|
|
||||||
class "elm-table-selected elm-table-ascending"
|
|
||||||
|
|
||||||
|
|
||||||
viewRow : (a -> String) -> List (ColumnData a msg) -> a -> ( String, Html msg )
|
|
||||||
viewRow toId columnData entry =
|
|
||||||
( toId entry
|
|
||||||
, lazy2 viewRowHelp columnData entry
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
viewRowHelp : List (ColumnData a msg) -> a -> Html msg
|
viewRowHelp : List (ColumnData data msg) -> (data -> List (Attribute msg)) -> data -> Html msg
|
||||||
viewRowHelp columnData entry =
|
viewRowHelp columns toRowAttrs data =
|
||||||
Html.tr [] (List.map (\{toCell} -> Html.td [] [ toCell entry ]) columnData)
|
Html.tr (toRowAttrs data) (List.map (viewCell data) columns)
|
||||||
|
|
||||||
|
|
||||||
|
viewCell : data -> ColumnData data msg -> Html msg
|
||||||
|
viewCell data {viewData} =
|
||||||
|
let
|
||||||
|
details =
|
||||||
|
viewData data
|
||||||
|
in
|
||||||
|
Html.td details.attributes details.children
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -511,7 +542,7 @@ findSorter selectedColumn columnData =
|
||||||
|
|
||||||
{name, sorter} :: remainingColumnData ->
|
{name, sorter} :: remainingColumnData ->
|
||||||
if name == selectedColumn then
|
if name == selectedColumn then
|
||||||
sorter
|
Just sorter
|
||||||
else
|
else
|
||||||
findSorter selectedColumn remainingColumnData
|
findSorter selectedColumn remainingColumnData
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue