SHARE
TWEET

Untitled

a guest Oct 21st, 2019 69 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. port module Main exposing (..)
  2.  
  3. import Html exposing (..)
  4. import Html.Attributes exposing (class, value, autofocus, placeholder, style, type_, checked, href)
  5. import Html.Events exposing (onInput, onClick, onSubmit, onDoubleClick)
  6. import Random
  7. import Navigation
  8.  
  9.  
  10.  
  11.  
  12. --== STATE MACHINES ==--
  13.  
  14.  
  15.  
  16.  
  17. -- STATE --
  18.  
  19.  
  20. type alias Todo =
  21.     { id : Int
  22.     , text : String
  23.     , completed : Bool
  24.     }
  25.    
  26. type alias TodoEdit =
  27.     { id : Int
  28.     , text : String
  29.     }
  30.  
  31. type Filter
  32.     = All
  33.     | Incomplete
  34.     | Completed
  35.  
  36. type alias Model =
  37.     { text : String
  38.     , todos : List Todo
  39.     , editing : Maybe TodoEdit
  40.     , filter : Filter
  41.     }
  42.  
  43.  
  44. init : Flags -> Navigation.Location -> ( Model, Cmd Msg )
  45. init flags location =
  46.     ( Model "" flags.todos Nothing (locationToFilter location)
  47.     , Cmd.none
  48.     )
  49.    
  50.    
  51. -- ACTIONS --
  52.  
  53.  
  54. type Msg
  55.     = UpdateText String
  56.     | GenerateTodoId
  57.     | AddTodo Int
  58.     | RemoveTodo Int
  59.     | Edit Int String
  60.     | EditSave Int String
  61.     | ToggleTodo Int
  62.     | SetFilter Filter
  63.     | UrlChange Navigation.Location
  64.  
  65.  
  66. -- UPDATE --
  67.  
  68.  
  69. update : Msg -> Model -> ( Model, Cmd Msg )
  70. update msg model =
  71.     case msg of
  72.         UpdateText newText ->
  73.             ( { model | text = newText }
  74.             , Cmd.none
  75.             )
  76.  
  77.         GenerateTodoId ->
  78.             ( model
  79.             , Random.generate AddTodo (Random.int Random.minInt Random.maxInt)
  80.             )
  81.  
  82.         AddTodo todoId ->
  83.             let
  84.                 newTodos =
  85.                     model.todos ++ [ Todo todoId model.text False ]
  86.             in
  87.                 ( { model | text = "", todos = newTodos }
  88.                 , saveTodos newTodos
  89.                 )
  90.  
  91.         RemoveTodo todoId ->
  92.             let
  93.                 newTodos =
  94.                     List.filter (\todo -> todo.id /= todoId) model.todos
  95.             in
  96.                 ( { model | todos = newTodos }
  97.                 , saveTodos newTodos
  98.                 )
  99.  
  100.         Edit todoId todoText ->
  101.             ( { model | editing = Just { id = todoId, text = todoText } }
  102.             , Cmd.none
  103.             )
  104.  
  105.         EditSave index todoText ->
  106.             let
  107.                 newTodos =
  108.                     List.indexedMap
  109.                         (\i todo ->
  110.                             if i == index then
  111.                                 { todo | text = todoText }
  112.                             else
  113.                                 todo
  114.                         )
  115.                         model.todos
  116.             in
  117.                 ( { model | editing = Nothing, todos = newTodos }
  118.                 , saveTodos newTodos
  119.                 )
  120.  
  121.         ToggleTodo todoId ->
  122.             let
  123.                 newTodos =
  124.                     List.map
  125.                         (\todo ->
  126.                             if todo.id == todoId then
  127.                                 { todo | completed = not todo.completed }
  128.                             else
  129.                                 todo
  130.                         )
  131.                         model.todos
  132.             in
  133.                 ( { model | todos = newTodos }
  134.                 , saveTodos newTodos
  135.                 )
  136.  
  137.         SetFilter filter ->
  138.             ( { model | filter = filter }
  139.             , Cmd.none
  140.             )
  141.  
  142.         UrlChange location ->
  143.             ( { model | filter = locationToFilter location }
  144.             , Cmd.none
  145.             )
  146.  
  147.  
  148.  
  149.  
  150.  
  151. --== VIEWS ==--
  152.  
  153.  
  154.  
  155.  
  156. view : Model -> Html Msg
  157. view model =
  158.     let
  159.         viewFilters : Filter -> Html Msg
  160.         viewFilters filter =
  161.             div
  162.                 []
  163.                 [ viewFilter All (filter == All) "All"
  164.                 , viewFilter Incomplete (filter == Incomplete) "Incomplete"
  165.                 , viewFilter Completed (filter == Completed) "Completed"
  166.                 ]
  167.  
  168.  
  169.         viewFilter : Filter -> Bool -> String -> Html Msg
  170.         viewFilter filter isFilter filterText =
  171.             if isFilter then
  172.                 span
  173.                     [ class "mr-3" ]
  174.                     [ text filterText ]
  175.             else
  176.                 a
  177.                     [ class "text-primary mr-3"
  178.                     , href ("#" ++ String.toLower filterText)
  179.                     , onClick (SetFilter filter)
  180.                     , style [ ( "cursor", "pointer" ) ]
  181.                     ]
  182.                     [ text filterText ]
  183.  
  184.  
  185.         viewTodo : Maybe TodoEdit -> Todo -> Html Msg
  186.         viewTodo editing todo =
  187.             case editing of
  188.                 Just todoEdit ->
  189.                     if todoEdit.id == todo.id then
  190.                         viewEditTodo todoEdit
  191.                     else
  192.                         viewNormalTodo todo
  193.  
  194.                 Nothing ->
  195.                     viewNormalTodo todo
  196.  
  197.  
  198.         viewEditTodo : TodoEdit -> Html Msg
  199.         viewEditTodo todoEdit =
  200.             div
  201.                 [ class "card" ]
  202.                 [ div [ class "card-block" ]
  203.                     [ form [ onSubmit (EditSave todoEdit.id todoEdit.text) ]
  204.                         [ input
  205.                             [ onInput (Edit todoEdit.id)
  206.                             , class "form-control"
  207.                             , value todoEdit.text
  208.                             ]
  209.                             []
  210.                         ]
  211.                     ]
  212.                 ]
  213.  
  214.  
  215.         viewNormalTodo : Todo -> Html Msg
  216.         viewNormalTodo todo =
  217.             div
  218.                 [ class "card" ]
  219.                 [ div
  220.                     [ class "card-block" ]
  221.                     [ input
  222.                         [ onClick (ToggleTodo todo.id)
  223.                         , type_ "checkbox"
  224.                         , checked todo.completed
  225.                         , class "mr-3"
  226.                         ]
  227.                         []
  228.                     , span
  229.                         [ onDoubleClick (Edit todo.id todo.text)
  230.                         , style
  231.                             [ ( "text-decoration"
  232.                               , if todo.completed then
  233.                                     "line-through"
  234.                                 else
  235.                                     "none"
  236.                               )
  237.                             ]
  238.                         ]
  239.                         [ text todo.text ]
  240.                     , span
  241.                         [ onClick (RemoveTodo todo.id)
  242.                         , class "float-right"
  243.                         ]
  244.                         [ text "✖" ]
  245.                     ]
  246.                 ]
  247.  
  248.  
  249.     in
  250.  
  251.  
  252.         div
  253.             [ class "col-12 col-sm-6 offset-sm-3" ]
  254.             [ form
  255.                 [ class "row", onSubmit GenerateTodoId ]
  256.                 [ div
  257.                     [ class "col-9" ]
  258.                     [ input
  259.                         [ onInput UpdateText
  260.                         , value model.text
  261.                         , autofocus True
  262.                         , class "form-control"
  263.                         , placeholder "Enter a todo"
  264.                         ]
  265.                         []
  266.                     ]
  267.                 , div
  268.                     [ class "col-3" ]
  269.                     [ button
  270.                         [ class "btn btn-primary form-control" ]
  271.                         [ text "+" ]
  272.                     ]
  273.                 ]
  274.             , viewFilters model.filter
  275.             , div
  276.                 [] <|
  277.                 List.map
  278.                     (viewTodo model.editing)
  279.                     (filterTodos model.filter model.todos)
  280.             ]
  281.  
  282.  
  283. filterTodos : Filter -> List Todo -> List Todo
  284. filterTodos filter todos =
  285.     case filter of
  286.         All ->
  287.             todos
  288.  
  289.         Incomplete ->
  290.             List.filter (\t -> not t.completed) todos
  291.  
  292.         Completed ->
  293.             List.filter (\t -> t.completed) todos
  294.  
  295.  
  296. locationToFilter : Navigation.Location -> Filter
  297. locationToFilter location =
  298.     case String.toLower location.hash of
  299.         "#incomplete" ->
  300.             Incomplete
  301.  
  302.         "#completed" ->
  303.             Completed
  304.  
  305.         _ ->
  306.             All
  307.  
  308.  
  309. port saveTodos : List Todo -> Cmd msg
  310.  
  311.  
  312. subscriptions : Model -> Sub Msg
  313. subscriptions model =
  314.     Sub.none
  315.  
  316.  
  317.  
  318.  
  319.  
  320. type alias Flags =
  321.     { todos : List Todo
  322.     }
  323.    
  324.  
  325.  
  326.  
  327. --== MAIN ==--
  328.  
  329.  
  330.  
  331.  
  332. main : Program Flags Model Msg
  333. main =
  334.     Navigation.programWithFlags UrlChange
  335.         { init = init
  336.         , view = view
  337.         , update = update
  338.         , subscriptions = subscriptions
  339.         }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top