Advertisement
Guest User

Untitled

a guest
Oct 21st, 2019
99
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.13 KB | None | 0 0
  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. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement