Compare commits
17 Commits
Author | SHA1 | Date |
---|---|---|
setop | b40d76e4bf | |
Tereza Sokol | 2d1117eac2 | |
Evan Czaplicki | bf632ced14 | |
Matthias Winkelmann | 1078c7f5fa | |
Evan Czaplicki | 6d9acec654 | |
derekdreery | 4dbfc3f806 | |
Evan Czaplicki | 2903fe9620 | |
Tim Bezhashvyly | 535c39d7d3 | |
Evan Czaplicki | 2fdac906c3 | |
Carlos De la Guardia | 18dc1c23ae | |
Evan Czaplicki | 2191b37127 | |
Evan Czaplicki | 8206138b89 | |
Evan Czaplicki | 86377edfcc | |
Jan Hrček | 9f8866525e | |
Evan Czaplicki | d988bd91bc | |
Evan Czaplicki | 701149ab61 | |
Evan Czaplicki | 7f3ab5f2f7 |
|
@ -0,0 +1 @@
|
||||||
|
elm 0.19.1
|
|
@ -7,8 +7,8 @@ This library also lets you customize `<caption>`, `<tbody>`, `<tr>`, etc. for yo
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
1. [U.S. Presidents by Birth Place](http://evancz.github.io/elm-sortable-tables/presidents.html) / [Code](https://github.com/evancz/elm-sortable-table/blob/master/examples/1-presidents.elm)
|
1. [U.S. Presidents by Birth Place](https://evancz.github.io/elm-sortable-table/presidents.html) / [Code](https://github.com/evancz/elm-sortable-table/blob/master/examples/1-presidents.elm)
|
||||||
2. [Travel Planner for the Mission District in San Francisco](http://evancz.github.io/elm-sortable-tables/travel.html) / [Code](https://github.com/evancz/elm-sortable-table/blob/master/examples/2-travel.elm)
|
2. [Travel Planner for the Mission District in San Francisco](https://evancz.github.io/elm-sortable-table/travel.html) / [Code](https://github.com/evancz/elm-sortable-table/blob/master/examples/2-travel.elm)
|
||||||
|
|
||||||
|
|
||||||
## Usage Rules
|
## Usage Rules
|
||||||
|
@ -43,7 +43,7 @@ I took some minor liberties with `update` to make the API a bit simpler. It woul
|
||||||
|
|
||||||
### Single Source of Truth
|
### Single Source of Truth
|
||||||
|
|
||||||
The data displayed by in the table is given as an argument to `view`. To put that another way, the `Table.State` value only tracks the details specific to *displaying* a sorted table, not the actual data to appear in the table. **This is the most important decision in this whole library.** This choice means you can change your data without any risk of the table getting out of sync. You may be adding things, changing entries, or whatever else; the table will never “get stuck” and display out of date information.
|
The data displayed in the table is given as an argument to `view`. To put that another way, the `Table.State` value only tracks the details specific to *displaying* a sorted table, not the actual data to appear in the table. **This is the most important decision in this whole library.** This choice means you can change your data without any risk of the table getting out of sync. You may be adding things, changing entries, or whatever else; the table will never “get stuck” and display out of date information.
|
||||||
|
|
||||||
To make this more clear, let’s imagine the alternate choice: instead of giving `List data` to `view`, we have it live in `Table.State`. Now say we want to update the dataset. We grab a copy of the data, make the changes we want, and put it back. But what if we forget to put it back? What if we hold on to that second copy in our `Model`? Which one is the *real* data now?
|
To make this more clear, let’s imagine the alternate choice: instead of giving `List data` to `view`, we have it live in `Table.State`. Now say we want to update the dataset. We grab a copy of the data, make the changes we want, and put it back. But what if we forget to put it back? What if we hold on to that second copy in our `Model`? Which one is the *real* data now?
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"version": "1.0.0",
|
"version": "1.0.1",
|
||||||
"summary": "Sortable tables for data of any shape.",
|
"summary": "Sortable tables for data of any shape.",
|
||||||
"repository": "https://github.com/evancz/elm-table.git",
|
"repository": "https://github.com/evancz/elm-sortable-table.git",
|
||||||
"license": "BSD3",
|
"license": "BSD3",
|
||||||
"source-directories": [
|
"source-directories": [
|
||||||
"src"
|
"src"
|
||||||
|
@ -10,8 +10,8 @@
|
||||||
"Table"
|
"Table"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"elm-lang/core": "4.0.0 <= v < 5.0.0",
|
"elm-lang/core": "5.0.0 <= v < 6.0.0",
|
||||||
"elm-lang/html": "1.1.0 <= v < 2.0.0"
|
"elm-lang/html": "2.0.0 <= v < 3.0.0"
|
||||||
},
|
},
|
||||||
"elm-version": "0.17.0 <= v < 0.18.0"
|
"elm-version": "0.18.0 <= v < 0.19.0"
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
"type": "package",
|
||||||
|
"name": "NoRedInk/elm-sortable-table",
|
||||||
|
"summary": "Sortable tables for whatever data you want to display.",
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"version": "1.0.1",
|
||||||
|
"exposed-modules": [
|
||||||
|
"Table"
|
||||||
|
],
|
||||||
|
"elm-version": "0.19.0 <= v < 0.20.0",
|
||||||
|
"dependencies": {
|
||||||
|
"elm/core": "1.0.0 <= v < 2.0.0",
|
||||||
|
"elm/html": "1.0.0 <= v < 2.0.0",
|
||||||
|
"elm/json": "1.0.0 <= v < 2.0.0"
|
||||||
|
},
|
||||||
|
"test-dependencies": {}
|
||||||
|
}
|
|
@ -1,14 +1,12 @@
|
||||||
import Html exposing (Html, div, h1, input, text)
|
import Html exposing (Html, div, h1, input, text)
|
||||||
import Html.App as App
|
|
||||||
import Html.Attributes exposing (placeholder)
|
import Html.Attributes exposing (placeholder)
|
||||||
import Html.Events exposing (onInput)
|
import Html.Events exposing (onInput)
|
||||||
import String
|
|
||||||
import Table
|
import Table
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
main =
|
main =
|
||||||
App.program
|
Html.program
|
||||||
{ init = init presidents
|
{ init = init presidents
|
||||||
, update = update
|
, update = update
|
||||||
, view = view
|
, view = view
|
||||||
|
@ -153,4 +151,5 @@ presidents =
|
||||||
, Person "George W. Bush" 1946 "New Haven" "Connecticut"
|
, Person "George W. Bush" 1946 "New Haven" "Connecticut"
|
||||||
, Person "Bill Clinton" 1946 "Hope" "Arkansas"
|
, Person "Bill Clinton" 1946 "Hope" "Arkansas"
|
||||||
, Person "Barack Obama" 1961 "Honolulu" "Hawaii"
|
, Person "Barack Obama" 1961 "Honolulu" "Hawaii"
|
||||||
|
, Person "Donald Trump" 1946 "New York City" "New York"
|
||||||
]
|
]
|
|
@ -1,16 +1,14 @@
|
||||||
import Html exposing (Html, Attribute, div, h1, input, p, text)
|
import Html exposing (Html, Attribute, div, h1, input, p, text)
|
||||||
import Html.App as App
|
import Html.Attributes exposing (checked, style, type_)
|
||||||
import Html.Attributes exposing (checked, style, type')
|
|
||||||
import Html.Events exposing (onClick)
|
import Html.Events exposing (onClick)
|
||||||
import Html.Lazy exposing (lazy)
|
import Html.Lazy exposing (lazy)
|
||||||
import String
|
|
||||||
import Table exposing (defaultCustomizations)
|
import Table exposing (defaultCustomizations)
|
||||||
import Time exposing (Time)
|
import Time exposing (Time)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
main =
|
main =
|
||||||
App.program
|
Html.program
|
||||||
{ init = init missionSights
|
{ init = init missionSights
|
||||||
, update = update
|
, update = update
|
||||||
, view = view
|
, view = view
|
||||||
|
@ -171,7 +169,7 @@ checkboxColumn =
|
||||||
viewCheckbox : Sight -> Table.HtmlDetails Msg
|
viewCheckbox : Sight -> Table.HtmlDetails Msg
|
||||||
viewCheckbox {selected} =
|
viewCheckbox {selected} =
|
||||||
Table.HtmlDetails []
|
Table.HtmlDetails []
|
||||||
[ input [ type' "checkbox", checked selected ] []
|
[ input [ type_ "checkbox", checked selected ] []
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# Examples
|
# Examples
|
||||||
|
|
||||||
1. [U.S. Presidents by Birth Place](http://evancz.github.io/elm-sortable-tables/presidents.html)
|
1. [U.S. Presidents by Birth Place](https://evancz.github.io/elm-sortable-table/presidents.html)
|
||||||
2. [Travel Planner for the Mission District in San Francisco](http://evancz.github.io/elm-sortable-tables/travel.html)
|
2. [Travel Planner for the Mission District in San Francisco](https://evancz.github.io/elm-sortable-table/travel.html)
|
||||||
|
|
||||||
|
|
||||||
## Build Instructions
|
## Build Instructions
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"version": "1.0.0",
|
"version": "1.0.1",
|
||||||
"summary": "helpful summary of your project, less than 80 characters",
|
"summary": "helpful summary of your project, less than 80 characters",
|
||||||
"repository": "https://github.com/user/project.git",
|
"repository": "https://github.com/user/project.git",
|
||||||
"license": "BSD3",
|
"license": "BSD3",
|
||||||
|
@ -8,9 +8,9 @@
|
||||||
],
|
],
|
||||||
"exposed-modules": [],
|
"exposed-modules": [],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"elm-lang/core": "4.0.3 <= v < 5.0.0",
|
"elm-lang/core": "5.0.0 <= v < 6.0.0",
|
||||||
"elm-lang/html": "1.1.0 <= v < 2.0.0",
|
"elm-lang/html": "2.0.0 <= v < 3.0.0",
|
||||||
"evancz/elm-sortable-table": "1.0.0 <= v < 2.0.0"
|
"evancz/elm-sortable-table": "1.0.1 <= v < 2.0.0"
|
||||||
},
|
},
|
||||||
"elm-version": "0.17.0 <= v < 0.18.0"
|
"elm-version": "0.18.0 <= v < 0.19.0"
|
||||||
}
|
}
|
||||||
|
|
170
src/Table.elm
170
src/Table.elm
|
@ -1,34 +1,35 @@
|
||||||
module Table exposing
|
module Table exposing
|
||||||
( view
|
( view
|
||||||
, config, stringColumn, intColumn, floatColumn
|
, config, stringColumn, intColumn, floatColumn
|
||||||
, State, initialSort
|
, State, initialSort, initialRevSort
|
||||||
, Column, customColumn, veryCustomColumn
|
, Column, customColumn, veryCustomColumn
|
||||||
, Sorter, unsortable, increasingBy, decreasingBy
|
, Sorter, unsortable, increasingBy, decreasingBy
|
||||||
, increasingOrDecreasingBy, decreasingOrIncreasingBy
|
, increasingOrDecreasingBy, decreasingOrIncreasingBy
|
||||||
, Config, customConfig
|
, Config, customConfig, Customizations, HtmlDetails, Status(..)
|
||||||
, Customizations, HtmlDetails, Status(..), defaultCustomizations
|
, defaultCustomizations
|
||||||
)
|
)
|
||||||
|
|
||||||
{-|
|
{-| This library helps you create sortable tables. The crucial feature is that it
|
||||||
|
|
||||||
This library helps you create sortable tables. The crucial feature is that it
|
|
||||||
lets you own your data separately and keep it in whatever format is best for
|
lets you own your data separately and keep it in whatever format is best for
|
||||||
you. This way you are free to change your data without worrying about the table
|
you. This way you are free to change your data without worrying about the table
|
||||||
“getting out of sync” with the data. Having a single source of
|
“getting out of sync” with the data. Having a single source of
|
||||||
truth is pretty great!
|
truth is pretty great!
|
||||||
|
|
||||||
I recommend checking out the [examples][] to get a feel for how it works.
|
I recommend checking out the [examples] to get a feel for how it works.
|
||||||
|
|
||||||
|
[examples]: https://github.com/evancz/elm-sortable-table/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
|
||||||
|
@ -41,19 +42,22 @@ point are a bunch of ways to customize your table further. If it does not
|
||||||
provide what you need, you may just want to write a custom table yourself. It
|
provide what you need, you may just want to write a custom table yourself. It
|
||||||
is not that crazy.
|
is not that crazy.
|
||||||
|
|
||||||
|
|
||||||
## Custom Columns
|
## Custom Columns
|
||||||
|
|
||||||
@docs Column, customColumn, veryCustomColumn,
|
@docs Column, customColumn, veryCustomColumn
|
||||||
Sorter, unsortable, increasingBy, decreasingBy,
|
@docs Sorter, unsortable, increasingBy, decreasingBy
|
||||||
increasingOrDecreasingBy, decreasingOrIncreasingBy
|
@docs increasingOrDecreasingBy, decreasingOrIncreasingBy
|
||||||
|
|
||||||
|
|
||||||
## Custom Tables
|
## Custom Tables
|
||||||
|
|
||||||
@docs Config, customConfig, Customizations, HtmlDetails, Status,
|
@docs Config, customConfig, Customizations, HtmlDetails, Status
|
||||||
defaultCustomizations
|
@docs defaultCustomizations
|
||||||
|
|
||||||
-}
|
-}
|
||||||
|
|
||||||
import Html exposing (Html, Attribute)
|
import Html exposing (Attribute, Html)
|
||||||
import Html.Attributes as Attr
|
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
|
||||||
|
@ -67,8 +71,8 @@ import Json.Decode as Json
|
||||||
|
|
||||||
{-| Tracks which column to sort by.
|
{-| Tracks which column to sort by.
|
||||||
-}
|
-}
|
||||||
type State =
|
type State
|
||||||
State String Bool
|
= State String Bool
|
||||||
|
|
||||||
|
|
||||||
{-| Create a table state. By providing a column name, you determine which
|
{-| Create a table state. By providing a column name, you determine which
|
||||||
|
@ -78,11 +82,16 @@ yachts to be sorted by length by default, you might say:
|
||||||
import Table
|
import Table
|
||||||
|
|
||||||
Table.initialSort "Length"
|
Table.initialSort "Length"
|
||||||
|
|
||||||
-}
|
-}
|
||||||
initialSort : String -> State
|
initialSort : String -> State
|
||||||
initialSort header =
|
initialSort header =
|
||||||
State header False
|
State header False
|
||||||
|
|
||||||
|
initialRevSort : String -> State
|
||||||
|
initialRevSort header =
|
||||||
|
State header True
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- CONFIG
|
-- CONFIG
|
||||||
|
@ -90,11 +99,12 @@ initialSort header =
|
||||||
|
|
||||||
{-| Configuration for your table, describing your columns.
|
{-| Configuration for your table, describing your columns.
|
||||||
|
|
||||||
**Note:** Your `Config` should *never* be held in your model.
|
**Note:** Your `Config` should _never_ be held in your model.
|
||||||
It should only appear in `view` code.
|
It should only appear in `view` code.
|
||||||
|
|
||||||
-}
|
-}
|
||||||
type Config data msg =
|
type Config data msg
|
||||||
Config
|
= Config
|
||||||
{ toId : data -> String
|
{ toId : data -> String
|
||||||
, toMsg : State -> msg
|
, toMsg : State -> msg
|
||||||
, columns : List (ColumnData data msg)
|
, columns : List (ColumnData data msg)
|
||||||
|
@ -128,15 +138,16 @@ You provide the following information in your table configuration:
|
||||||
- `toId` — turn a `Person` into a unique ID. This lets us use
|
- `toId` — turn a `Person` into a unique ID. This lets us use
|
||||||
[`Html.Keyed`][keyed] under the hood to make resorts faster.
|
[`Html.Keyed`][keyed] under the hood to make resorts faster.
|
||||||
- `columns` — specify some columns to show.
|
- `columns` — specify some columns to show.
|
||||||
- `toMsg` — a way send new table states to your app as messages.
|
- `toMsg` — a way to send new table states to your app as messages.
|
||||||
|
|
||||||
See the [examples][] to get a better feel for this!
|
See the [examples] to get a better feel for this!
|
||||||
|
|
||||||
[keyed]: http://package.elm-lang.org/packages/elm-lang/html/latest/Html-Keyed
|
[keyed]: http://package.elm-lang.org/packages/elm-lang/html/latest/Html-Keyed
|
||||||
[examples]: https://github.com/evancz/elm-tables/tree/master/examples
|
[examples]: https://github.com/evancz/elm-sortable-table/tree/master/examples
|
||||||
|
|
||||||
-}
|
-}
|
||||||
config
|
config :
|
||||||
: { toId : data -> String
|
{ toId : data -> String
|
||||||
, toMsg : State -> msg
|
, toMsg : State -> msg
|
||||||
, columns : List (Column data msg)
|
, columns : List (Column data msg)
|
||||||
}
|
}
|
||||||
|
@ -152,8 +163,8 @@ config { toId, toMsg, columns } =
|
||||||
|
|
||||||
{-| Just like `config` but you can specify a bunch of table customizations.
|
{-| 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
|
||||||
, columns : List (Column data msg)
|
, columns : List (Column data msg)
|
||||||
, customizations : Customizations data msg
|
, customizations : Customizations data msg
|
||||||
|
@ -175,14 +186,15 @@ summaries of various columns. And maybe you want to put attributes on `<tbody>`
|
||||||
or on particular rows in the body. All these customizations are available to you.
|
or on particular rows in the body. All these customizations are available to you.
|
||||||
|
|
||||||
**Note:** The level of craziness possible in `<thead>` and `<tfoot>` are so
|
**Note:** The level of craziness possible in `<thead>` and `<tfoot>` are so
|
||||||
high that I could not see how to provide the full functionality *and* make it
|
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 Customizations 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
|
||||||
, tfoot : Maybe (HtmlDetails msg)
|
, tfoot : Maybe (HtmlDetails msg)
|
||||||
, tbodyAttrs : List (Attribute msg)
|
, tbodyAttrs : List (Attribute msg)
|
||||||
, rowAttrs : data -> List (Attribute msg)
|
, rowAttrs : data -> List (Attribute msg)
|
||||||
|
@ -212,13 +224,13 @@ defaultCustomizations =
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
simpleThead : List (String, Status, Attribute msg) -> HtmlDetails msg
|
simpleThead : List ( String, Status, Attribute msg ) -> HtmlDetails msg
|
||||||
simpleThead headers =
|
simpleThead headers =
|
||||||
HtmlDetails [] (List.map simpleTheadHelp headers)
|
HtmlDetails [] (List.map simpleTheadHelp headers)
|
||||||
|
|
||||||
|
|
||||||
simpleTheadHelp : ( String, Status, Attribute msg ) -> Html msg
|
simpleTheadHelp : ( String, Status, Attribute msg ) -> Html msg
|
||||||
simpleTheadHelp (name, status, onClick) =
|
simpleTheadHelp ( name, status, onClick_ ) =
|
||||||
let
|
let
|
||||||
content =
|
content =
|
||||||
case status of
|
case status of
|
||||||
|
@ -227,7 +239,11 @@ simpleTheadHelp (name, status, onClick) =
|
||||||
|
|
||||||
Sortable selected ->
|
Sortable selected ->
|
||||||
[ Html.text name
|
[ Html.text name
|
||||||
, if selected then darkGrey "↓" else lightGrey "↓"
|
, if selected then
|
||||||
|
darkGrey "↓"
|
||||||
|
|
||||||
|
else
|
||||||
|
lightGrey "↓"
|
||||||
]
|
]
|
||||||
|
|
||||||
Reversible Nothing ->
|
Reversible Nothing ->
|
||||||
|
@ -237,20 +253,26 @@ simpleTheadHelp (name, status, onClick) =
|
||||||
|
|
||||||
Reversible (Just isReversed) ->
|
Reversible (Just isReversed) ->
|
||||||
[ Html.text name
|
[ Html.text name
|
||||||
, darkGrey (if isReversed then "↑" else "↓")
|
, darkGrey
|
||||||
|
(if isReversed then
|
||||||
|
"↑"
|
||||||
|
|
||||||
|
else
|
||||||
|
"↓"
|
||||||
|
)
|
||||||
]
|
]
|
||||||
in
|
in
|
||||||
Html.th [ onClick ] content
|
Html.th [ onClick_ ] content
|
||||||
|
|
||||||
|
|
||||||
darkGrey : String -> Html msg
|
darkGrey : String -> Html msg
|
||||||
darkGrey symbol =
|
darkGrey symbol =
|
||||||
Html.span [ Attr.style [("color", "#555")] ] [ 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", "#ccc")] ] [ Html.text (" " ++ symbol) ]
|
Html.span [ Attr.style "color" "#ccc" ] [ Html.text (" " ++ symbol) ]
|
||||||
|
|
||||||
|
|
||||||
simpleRowAttrs : data -> List (Attribute msg)
|
simpleRowAttrs : data -> List (Attribute msg)
|
||||||
|
@ -272,6 +294,7 @@ simpleRowAttrs _ =
|
||||||
is sorted.
|
is sorted.
|
||||||
|
|
||||||
This information lets you do custom header decorations for each scenario.
|
This information lets you do custom header decorations for each scenario.
|
||||||
|
|
||||||
-}
|
-}
|
||||||
type Status
|
type Status
|
||||||
= Unsortable
|
= Unsortable
|
||||||
|
@ -285,8 +308,8 @@ type Status
|
||||||
|
|
||||||
{-| Describes how to turn `data` into a column in your table.
|
{-| Describes how to turn `data` into a column in your table.
|
||||||
-}
|
-}
|
||||||
type Column data msg =
|
type Column data msg
|
||||||
Column (ColumnData data msg)
|
= Column (ColumnData data msg)
|
||||||
|
|
||||||
|
|
||||||
type alias ColumnData data msg =
|
type alias ColumnData data msg =
|
||||||
|
@ -296,7 +319,7 @@ type alias ColumnData data msg =
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
{-|-}
|
{-| -}
|
||||||
stringColumn : String -> (data -> String) -> Column data msg
|
stringColumn : String -> (data -> String) -> Column data msg
|
||||||
stringColumn name toStr =
|
stringColumn name toStr =
|
||||||
Column
|
Column
|
||||||
|
@ -306,22 +329,22 @@ stringColumn name toStr =
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
{-|-}
|
{-| -}
|
||||||
intColumn : String -> (data -> Int) -> Column data msg
|
intColumn : String -> (data -> Int) -> Column data msg
|
||||||
intColumn name toInt =
|
intColumn name toInt =
|
||||||
Column
|
Column
|
||||||
{ name = name
|
{ name = name
|
||||||
, viewData = textDetails << toString << toInt
|
, viewData = textDetails << String.fromInt << toInt
|
||||||
, sorter = increasingOrDecreasingBy toInt
|
, sorter = increasingOrDecreasingBy toInt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
{-|-}
|
{-| -}
|
||||||
floatColumn : String -> (data -> Float) -> Column data msg
|
floatColumn : String -> (data -> Float) -> Column data msg
|
||||||
floatColumn name toFloat =
|
floatColumn name toFloat =
|
||||||
Column
|
Column
|
||||||
{ name = name
|
{ name = name
|
||||||
, viewData = textDetails << toString << toFloat
|
, viewData = textDetails << String.fromFloat << toFloat
|
||||||
, sorter = increasingOrDecreasingBy toFloat
|
, sorter = increasingOrDecreasingBy toFloat
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,11 +375,12 @@ quite cut it. You could define a custom column like this:
|
||||||
The `viewData` field means we will displays the number `12345.67` as `$12k`.
|
The `viewData` field means we will displays the number `12345.67` as `$12k`.
|
||||||
|
|
||||||
The `sorter` field specifies how the column can be sorted. In `dollarColumn` we
|
The `sorter` field specifies how the column can be sorted. In `dollarColumn` we
|
||||||
are saying that it can *only* be shown from highest-to-lowest monetary value.
|
are saying that it can _only_ be shown from highest-to-lowest monetary value.
|
||||||
More about sorters soon!
|
More about sorters soon!
|
||||||
|
|
||||||
-}
|
-}
|
||||||
customColumn
|
customColumn :
|
||||||
: { name : String
|
{ name : String
|
||||||
, viewData : data -> String
|
, viewData : data -> String
|
||||||
, sorter : Sorter data
|
, sorter : Sorter data
|
||||||
}
|
}
|
||||||
|
@ -366,13 +390,13 @@ customColumn { name, viewData, sorter } =
|
||||||
ColumnData name (textDetails << viewData) sorter
|
ColumnData name (textDetails << viewData) sorter
|
||||||
|
|
||||||
|
|
||||||
{-| It is *possible* that you want something crazier than `customColumn`. In
|
{-| It is _possible_ that you want something crazier than `customColumn`. In
|
||||||
that unlikely scenario, this function lets you have full control over the
|
that unlikely scenario, this function lets you have full control over the
|
||||||
attributes and children of each `<td>` cell in this column.
|
attributes and children of each `<td>` cell in this column.
|
||||||
|
|
||||||
So maybe you want to a dollars column, and the dollar signs should be green.
|
So maybe you want to a dollars column, and the dollar signs should be green.
|
||||||
|
|
||||||
import Html exposing (Html, Attribute, span, text)
|
import Html exposing (Attribute, Html, span, text)
|
||||||
import Html.Attributes exposing (style)
|
import Html.Attributes exposing (style)
|
||||||
import Table
|
import Table
|
||||||
|
|
||||||
|
@ -387,12 +411,13 @@ So maybe you want to a dollars column, and the dollar signs should be green.
|
||||||
viewDollars : Float -> Table.HtmlDetails msg
|
viewDollars : Float -> Table.HtmlDetails msg
|
||||||
viewDollars dollars =
|
viewDollars dollars =
|
||||||
Table.HtmlDetails []
|
Table.HtmlDetails []
|
||||||
[ span [ style [("color","green")] ] [ text "$" ]
|
[ span [ style [ ( "color", "green" ) ] ] [ text "$" ]
|
||||||
, text (toString (round (dollars / 1000)) ++ "k")
|
, text (toString (round (dollars / 1000)) ++ "k")
|
||||||
]
|
]
|
||||||
|
|
||||||
-}
|
-}
|
||||||
veryCustomColumn
|
veryCustomColumn :
|
||||||
: { name : String
|
{ name : String
|
||||||
, viewData : data -> HtmlDetails msg
|
, viewData : data -> HtmlDetails msg
|
||||||
, sorter : Sorter data
|
, sorter : Sorter data
|
||||||
}
|
}
|
||||||
|
@ -414,6 +439,7 @@ for the table belongs in your `view` code. I very strongly recommend against
|
||||||
putting `Config` in your model. Describe any potential table configurations
|
putting `Config` in your model. Describe any potential table configurations
|
||||||
statically, and look for a different library if you need something crazier than
|
statically, and look for a different library if you need something crazier than
|
||||||
that.
|
that.
|
||||||
|
|
||||||
-}
|
-}
|
||||||
view : Config data msg -> State -> List data -> Html msg
|
view : Config data msg -> State -> List data -> Html msg
|
||||||
view (Config { toId, toMsg, columns, customizations }) state data =
|
view (Config { toId, toMsg, columns, customizations }) state data =
|
||||||
|
@ -463,20 +489,23 @@ toHeaderInfo (State sortName isReversed) toMsg { name, sorter } =
|
||||||
IncOrDec _ ->
|
IncOrDec _ ->
|
||||||
if name == sortName then
|
if name == sortName then
|
||||||
( name, Reversible (Just isReversed), onClick name (not isReversed) toMsg )
|
( name, Reversible (Just isReversed), onClick name (not isReversed) toMsg )
|
||||||
|
|
||||||
else
|
else
|
||||||
( name, Reversible Nothing, onClick name False toMsg )
|
( name, Reversible Nothing, onClick name False toMsg )
|
||||||
|
|
||||||
DecOrInc _ ->
|
DecOrInc _ ->
|
||||||
if name == sortName then
|
if name == sortName then
|
||||||
( name, Reversible (Just isReversed), onClick name (not isReversed) toMsg )
|
( name, Reversible (Just isReversed), onClick name (not isReversed) toMsg )
|
||||||
|
|
||||||
else
|
else
|
||||||
( name, Reversible Nothing, onClick name False toMsg )
|
( name, Reversible Nothing, onClick name False toMsg )
|
||||||
|
|
||||||
|
|
||||||
onClick : String -> Bool -> (State -> msg) -> Attribute msg
|
onClick : String -> Bool -> (State -> msg) -> Attribute msg
|
||||||
onClick name isReversed toMsg =
|
onClick name isReversed toMsg =
|
||||||
E.on "click" <| Json.map toMsg <|
|
E.on "click" <|
|
||||||
Json.object2 State (Json.succeed name) (Json.succeed isReversed)
|
Json.map toMsg <|
|
||||||
|
Json.map2 State (Json.succeed name) (Json.succeed isReversed)
|
||||||
|
|
||||||
|
|
||||||
viewRow : (data -> String) -> List (ColumnData data msg) -> (data -> List (Attribute msg)) -> data -> ( String, Html msg )
|
viewRow : (data -> String) -> List (ColumnData data msg) -> (data -> List (Attribute msg)) -> data -> ( String, Html msg )
|
||||||
|
@ -492,7 +521,7 @@ viewRowHelp columns toRowAttrs data =
|
||||||
|
|
||||||
|
|
||||||
viewCell : data -> ColumnData data msg -> Html msg
|
viewCell : data -> ColumnData data msg -> Html msg
|
||||||
viewCell data {viewData} =
|
viewCell data { viewData } =
|
||||||
let
|
let
|
||||||
details =
|
details =
|
||||||
viewData data
|
viewData data
|
||||||
|
@ -520,17 +549,25 @@ applySorter isReversed sorter data =
|
||||||
None ->
|
None ->
|
||||||
data
|
data
|
||||||
|
|
||||||
Increasing sort ->
|
Increasing sort_ ->
|
||||||
sort data
|
sort_ data
|
||||||
|
|
||||||
Decreasing sort ->
|
Decreasing sort_ ->
|
||||||
List.reverse (sort data)
|
List.reverse (sort_ data)
|
||||||
|
|
||||||
IncOrDec sort ->
|
IncOrDec sort_ ->
|
||||||
if isReversed then List.reverse (sort data) else sort data
|
if isReversed then
|
||||||
|
List.reverse (sort_ data)
|
||||||
|
|
||||||
DecOrInc sort ->
|
else
|
||||||
if isReversed then sort data else List.reverse (sort data)
|
sort_ data
|
||||||
|
|
||||||
|
DecOrInc sort_ ->
|
||||||
|
if isReversed then
|
||||||
|
sort_ data
|
||||||
|
|
||||||
|
else
|
||||||
|
List.reverse (sort_ data)
|
||||||
|
|
||||||
|
|
||||||
findSorter : String -> List (ColumnData data msg) -> Maybe (Sorter data)
|
findSorter : String -> List (ColumnData data msg) -> Maybe (Sorter data)
|
||||||
|
@ -539,9 +576,10 @@ findSorter selectedColumn columnData =
|
||||||
[] ->
|
[] ->
|
||||||
Nothing
|
Nothing
|
||||||
|
|
||||||
{name, sorter} :: remainingColumnData ->
|
{ name, sorter } :: remainingColumnData ->
|
||||||
if name == selectedColumn then
|
if name == selectedColumn then
|
||||||
Just sorter
|
Just sorter
|
||||||
|
|
||||||
else
|
else
|
||||||
findSorter selectedColumn remainingColumnData
|
findSorter selectedColumn remainingColumnData
|
||||||
|
|
||||||
|
@ -575,6 +613,7 @@ want a table of people, sorted alphabetically by name, we would say this:
|
||||||
sorter : Sorter { a | name : comparable }
|
sorter : Sorter { a | name : comparable }
|
||||||
sorter =
|
sorter =
|
||||||
increasingBy .name
|
increasingBy .name
|
||||||
|
|
||||||
-}
|
-}
|
||||||
increasingBy : (data -> comparable) -> Sorter data
|
increasingBy : (data -> comparable) -> Sorter data
|
||||||
increasingBy toComparable =
|
increasingBy toComparable =
|
||||||
|
@ -588,13 +627,14 @@ would say this:
|
||||||
sorter : Sorter { a | population : comparable }
|
sorter : Sorter { a | population : comparable }
|
||||||
sorter =
|
sorter =
|
||||||
decreasingBy .population
|
decreasingBy .population
|
||||||
|
|
||||||
-}
|
-}
|
||||||
decreasingBy : (data -> comparable) -> Sorter data
|
decreasingBy : (data -> comparable) -> Sorter data
|
||||||
decreasingBy toComparable =
|
decreasingBy toComparable =
|
||||||
Decreasing (List.sortBy toComparable)
|
Decreasing (List.sortBy toComparable)
|
||||||
|
|
||||||
|
|
||||||
{-| Sometimes you want to be able to sort data in increasing *or* decreasing
|
{-| Sometimes you want to be able to sort data in increasing _or_ decreasing
|
||||||
order. Maybe you have a bunch of data about orange juice, and you want to know
|
order. Maybe you have a bunch of data about orange juice, and you want to know
|
||||||
both which has the most sugar, and which has the least sugar. Both interesting!
|
both which has the most sugar, and which has the least sugar. Both interesting!
|
||||||
This function lets you see both, starting with decreasing order.
|
This function lets you see both, starting with decreasing order.
|
||||||
|
@ -602,19 +642,21 @@ This function lets you see both, starting with decreasing order.
|
||||||
sorter : Sorter { a | sugar : comparable }
|
sorter : Sorter { a | sugar : comparable }
|
||||||
sorter =
|
sorter =
|
||||||
decreasingOrIncreasingBy .sugar
|
decreasingOrIncreasingBy .sugar
|
||||||
|
|
||||||
-}
|
-}
|
||||||
decreasingOrIncreasingBy : (data -> comparable) -> Sorter data
|
decreasingOrIncreasingBy : (data -> comparable) -> Sorter data
|
||||||
decreasingOrIncreasingBy toComparable =
|
decreasingOrIncreasingBy toComparable =
|
||||||
DecOrInc (List.sortBy toComparable)
|
DecOrInc (List.sortBy toComparable)
|
||||||
|
|
||||||
|
|
||||||
{-| Sometimes you want to be able to sort data in increasing *or* decreasing
|
{-| Sometimes you want to be able to sort data in increasing _or_ decreasing
|
||||||
order. Maybe you have race times for the 100 meter sprint. This function lets
|
order. Maybe you have race times for the 100 meter sprint. This function lets
|
||||||
sort by best time by default, but also see the other order.
|
sort by best time by default, but also see the other order.
|
||||||
|
|
||||||
sorter : Sorter { a | time : comparable }
|
sorter : Sorter { a | time : comparable }
|
||||||
sorter =
|
sorter =
|
||||||
increasingOrDecreasingBy .time
|
increasingOrDecreasingBy .time
|
||||||
|
|
||||||
-}
|
-}
|
||||||
increasingOrDecreasingBy : (data -> comparable) -> Sorter data
|
increasingOrDecreasingBy : (data -> comparable) -> Sorter data
|
||||||
increasingOrDecreasingBy toComparable =
|
increasingOrDecreasingBy toComparable =
|
||||||
|
|
Loading…
Reference in New Issue