Skip to content

Commit a0376a5

Browse files
committed
break toggle-all again, and clean up toggleInput
1 parent d5e640a commit a0376a5

File tree

2 files changed

+32
-42
lines changed

2 files changed

+32
-42
lines changed

src/Reflex/TodoMVC.hs

+20-34
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,10 @@ todoMVC = el "div" $ do
8181
mainHeader
8282
rec tasks <- foldDyn ($) initialTasks $ mergeWith (.)
8383
[ fmap insertNew_ newTask
84-
, modifyTasks
8584
, listModifyTasks
8685
, fmap (const $ Map.filter $ not . taskCompleted) clearCompleted -- Call out the type and purpose of these things
8786
]
88-
(modifyTasks, newTask) <- el "header" $
89-
(,) <$> toggleAll tasks <*> taskEntry
87+
newTask <- taskEntry
9088
listModifyTasks <- taskList activeFilter tasks
9189
(activeFilter, clearCompleted) <- controls tasks
9290
return ()
@@ -107,25 +105,6 @@ stripDescription d =
107105
keyCodeIs :: Key -> KeyCode -> Bool
108106
keyCodeIs k c = keyCodeLookup c == k
109107

110-
toggleAll
111-
:: ( DomBuilder t m
112-
, DomBuilderSpace m ~ GhcjsDomSpace
113-
, MonadFix m
114-
, MonadHold t m
115-
, MonadSample t m
116-
, PostBuild t m
117-
)
118-
=> Dynamic t (Map k Task)
119-
-> m (Event t (Map k Task -> Map k Task))
120-
toggleAll tasks = do
121-
let toggleAllState = (\els -> not (null els) && all taskCompleted els) . Map.elems <$> tasks
122-
namedCheckmark = toggleInput $ "id" =: "toggle-all"
123-
-- Create "toggle all" button
124-
initialState <- sample $ current toggleAllState
125-
toggleAllClick <- switchDyn <$> widgetHold (namedCheckmark initialState) (namedCheckmark <$> updated toggleAllState)
126-
elAttr "label" ("for" =: "toggle-all") $ text ""
127-
pure $ fmap (\oldAllCompletedState -> fmap (\t -> t { taskCompleted = not oldAllCompletedState })) $ tag (current toggleAllState) toggleAllClick
128-
129108
-- | Display an input field; produce new Tasks when the user creates them
130109
taskEntry
131110
:: ( DomBuilder t m
@@ -134,7 +113,7 @@ taskEntry
134113
, DomBuilderSpace m ~ GhcjsDomSpace
135114
)
136115
=> m (Event t Task)
137-
taskEntry = do
116+
taskEntry = el "header" $ do
138117
-- Create the textbox; it will be cleared whenever the user presses enter
139118
rec let newValueEntered = keypress Enter descriptionBox
140119
descriptionBox <- inputElement $ def
@@ -166,6 +145,10 @@ taskList
166145
-> Dynamic t (Map k Task)
167146
-> m (Event t (Map k Task -> Map k Task))
168147
taskList activeFilter tasks = elAttr "section" ("class" =: "main") $ do
148+
let toggleAllState = all taskCompleted . Map.elems <$> tasks
149+
toggleAllAttrs = ffor tasks $ \t -> "class" =: "toggle-all" <> "name" =: "toggle" <> if Map.null t then "style" =: "visibility:hidden" else mempty
150+
toggleAll <- toggleInput toggleAllAttrs toggleAllState
151+
elAttr "label" ("for" =: "toggle-all") $ text "Mark all as complete"
169152
-- Filter the item list
170153
let visibleTasks = zipDynWith (Map.filter . satisfiesFilter) activeFilter tasks
171154
-- Hide the item list itself if there are no items
@@ -188,16 +171,20 @@ toggleInput
188171
, MonadHold t m
189172
, PostBuild t m
190173
)
191-
=> Map AttributeName Text
192-
-> Bool
174+
=> Dynamic t (Map AttributeName Text)
175+
-> Dynamic t Bool
193176
-> m (Event t ())
194-
toggleInput attrs checked = domEvent Click <$> inputElement (def
195-
& inputElementConfig_initialChecked .~ checked
196-
& inputElementConfig_elementConfig . elementConfig_initialAttributes .~
197-
mconcat [ "class" =: "toggle"
198-
, "type" =: "checkbox"
199-
, attrs
200-
])
177+
toggleInput dynAttrs dynChecked = do
178+
let attrs = (<> "class" =: "toggle") . ("type" =: "checkbox" <>) <$> dynAttrs
179+
updatedAttrs = fmap Just <$> updated dynAttrs
180+
updatedChecked = updated dynChecked
181+
initialAttrs <- sample $ current attrs
182+
initialChecked <- sample $ current dynChecked
183+
domEvent Click <$> inputElement (def
184+
& inputElementConfig_initialChecked .~ initialChecked
185+
& inputElementConfig_setChecked .~ updatedChecked
186+
& inputElementConfig_elementConfig . elementConfig_modifyAttributes .~ updatedAttrs
187+
& inputElementConfig_elementConfig . elementConfig_initialAttributes .~ initialAttrs)
201188

202189
buildCompletedCheckbox
203190
:: ( DomBuilder t m
@@ -212,8 +199,7 @@ buildCompletedCheckbox
212199
buildCompletedCheckbox todo description = elAttr "div" ("class" =: "view") $ do
213200
-- Display the todo item's completed status, and allow it to be set
214201
completed <- holdUniqDyn $ fmap taskCompleted todo
215-
initialState <- sample $ taskCompleted <$> current todo
216-
checkboxClicked <- switchDyn <$> widgetHold (toggleInput mempty initialState) (toggleInput mempty . taskCompleted <$> updated todo)
202+
checkboxClicked <- toggleInput (constDyn mempty) completed
217203
let setCompleted = fmap not $ tag (current completed) checkboxClicked
218204
-- Display the todo item's name for viewing purposes
219205
(descriptionLabel, _) <- el' "label" $ dynText description

style.css

+12-8
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ body {
111111
border-top: 1px solid #e6e6e6;
112112
}
113113

114-
#toggle-all {
114+
.toggle-all {
115115
width: 1px;
116116
height: 1px;
117117
border: none; /* Mobile Safari */
@@ -121,21 +121,25 @@ body {
121121
bottom: 100%;
122122
}
123123

124-
#toggle-all + label {
124+
.toggle-all + label {
125125
width: 60px;
126-
height: 66px;
127-
display: inline-block;
126+
height: 34px;
127+
font-size: 0;
128128
position: absolute;
129-
line-height: 66px;
130-
text-align: center;
129+
top: -52px;
130+
left: -13px;
131131
-webkit-transform: rotate(90deg);
132132
transform: rotate(90deg);
133+
}
134+
135+
.toggle-all + label:before {
136+
content: '❯';
133137
font-size: 22px;
134138
color: #e6e6e6;
135-
z-index: 10;
139+
padding: 10px 27px 10px 27px;
136140
}
137141

138-
#toggle-all:checked + label {
142+
.toggle-all:checked + label:before {
139143
color: #737373;
140144
}
141145

0 commit comments

Comments
 (0)