on develop help sign in
Improve efficiency of inputElement for ImmediateDomBuilderT
commite2ff6e8049fb557fbcfd94ddcda298ec0e66c196 authorDaniel Haraj <dan@obsidian.systems> dateSat 28 Jan 2017, 19:40 (10 years ago) parent8290c80
3 files changed+31−9
src/Reflex/Dom/Builder/Class.hs+14−6 src/Reflex/Dom/Builder/Class/TH.hs+12 src/Reflex/Dom/Builder/Immediate.hs+5−3
src/Reflex/Dom/Builder/Class.hs+14−6
@@ -22,6 +22,7 @@ module Reflex.Dom.Builder.Class
2222
2323import Reflex.Class as Reflex
2424import Reflex.Dom.Builder.Class.Events
25+import Reflex.Dom.Builder.Class.TH
2526import Reflex.DynamicWriter
2627import Reflex.EventWriter
2728import Reflex.PerformEvent.Class
@@ -240,7 +241,7 @@ data Placeholder above t
240241
241242data InputElementConfig er t m
242243 = InputElementConfig { _inputElementConfig_initialValue :: Text
243− , _inputElementConfig_setValue :: Event t Text
244+ , _inputElementConfig_setValue :: Maybe (Event t Text)
244245 , _inputElementConfig_initialChecked :: Bool
245246 , _inputElementConfig_setChecked :: Event t Bool
246247 , _inputElementConfig_elementConfig :: ElementConfig er t m
@@ -250,7 +251,7 @@ instance (Reflex t, er ~ EventResult, DomBuilder t m) => Default (InputElementCo
250251 {-# INLINABLE def #-}
251252 def = InputElementConfig
252253 { _inputElementConfig_initialValue = ""
253− , _inputElementConfig_setValue = never
254+ , _inputElementConfig_setValue = Nothing
254255 , _inputElementConfig_initialChecked = False
255256 , _inputElementConfig_setChecked = never
256257 , _inputElementConfig_elementConfig = def
@@ -327,9 +328,8 @@ data SelectElement er d t = SelectElement
327328 , _selectElement_raw :: RawSelectElement d
328329 }
329330
330−makeLensesFor
331− [("_textNodeConfig_initialContents", "textNodeConfig_initialContents")]
332− ''TextNodeConfig
331+makeLensesWithoutField "_textNodeConfig_setContents" ''TextNodeConfig
332+makeLensesWithoutField "_inputElementConfig_setValue" ''InputElementConfig
333333
334334-- | This lens is technically illegal. The implementation of 'TextNodeConfig' uses a 'Maybe' under the hood for efficiency reasons. However, always interacting with 'TextNodeConfig' via lenses will always behave correctly, and if you pattern match on it, you should always treat 'Nothing' as 'never'.
335335textNodeConfig_setContents :: Reflex t => Lens (TextNodeConfig t) (TextNodeConfig t) (Event t Text) (Event t Text)
@@ -340,10 +340,18 @@ textNodeConfig_setContents =
340340 setter t e = t { _textNodeConfig_setContents = Just e }
341341 in lens getter setter
342342
343+-- | This lens is technically illegal. The implementation of 'InputElementConfig' uses a 'Maybe' under the hood for efficiency reasons. However, always interacting with 'InputElementConfig' via lenses will always behave correctly, and if you pattern match on it, you should always treat 'Nothing' as 'never'.
344+inputElementConfig_setValue :: Reflex t => Lens (InputElementConfig er t m) (InputElementConfig er t m) (Event t Text) (Event t Text)
345+inputElementConfig_setValue =
346+ let getter t = case _inputElementConfig_setValue t of
347+ Nothing -> never
348+ Just e -> e
349+ setter t e = t { _inputElementConfig_setValue = Just e }
350+ in lens getter setter
351+
343352concat <$> mapM makeLenses
344353 [ ''ElementConfig
345354 , ''PlaceholderConfig
346− , ''InputElementConfig
347355 , ''TextAreaElementConfig
348356 , ''SelectElementConfig
349357 , ''RawElementConfig
src/Reflex/Dom/Builder/Class/TH.hsnew file+12
@@ -0,0 +1,12 @@
1+module Reflex.Dom.Builder.Class.TH where
2+
3+import Control.Lens
4+import Language.Haskell.TH.Syntax (Name, nameBase)
5+import Language.Haskell.TH.Lib (DecsQ)
6+
7+namer :: String -> Name -> [Name] -> Name -> [DefName]
8+namer s n ks t | s == nameBase t = []
9+ | otherwise = underscoreNoPrefixNamer n ks t
10+
11+makeLensesWithoutField :: String -> Name -> DecsQ
12+makeLensesWithoutField s = makeLensesWith (lensRules & lensField .~ namer s)
src/Reflex/Dom/Builder/Immediate.hs+5−3
@@ -313,9 +313,11 @@ instance SupportsImmediateDomBuilder t m => DomBuilder t (ImmediateDomBuilderT t
313313 Just v0 <- Input.getValue domInputElement
314314 let getMyValue = fromMaybe "" <$> Input.getValue domInputElement
315315 valueChangedByUI <- performEvent $ getMyValue <$ Reflex.select (_element_events e) (WrapArg Input)
316− valueChangedBySetValue <- performEvent $ ffor (cfg ^. inputElementConfig_setValue) $ \v' -> do
317− Input.setValue domInputElement $ Just v'
318− getMyValue -- We get the value after setting it in case the browser has mucked with it somehow
316+ valueChangedBySetValue <- case _inputElementConfig_setValue cfg of
317+ Nothing -> return never
318+ Just eSetValue -> performEvent $ ffor eSetValue $ \v' -> do
319+ Input.setValue domInputElement $ Just v'
320+ getMyValue -- We get the value after setting it in case the browser has mucked with it somehow
319321 v <- holdDyn v0 $ leftmost
320322 [ valueChangedBySetValue
321323 , valueChangedByUI