|
1 | 1 | module Functora.Miso.Jsm
|
2 |
| - ( popupText, |
3 |
| - shareText, |
4 |
| - addFieldPair, |
5 |
| - addAsset, |
6 |
| - addPaymentMethod, |
7 |
| - moveUp, |
8 |
| - moveDown, |
9 |
| - removeAt, |
10 |
| - duplicateAt, |
11 |
| - openBrowserPage, |
12 |
| - enterOrEscapeBlur, |
13 |
| - insertStorage, |
14 |
| - selectStorage, |
15 |
| - selectClipboard, |
| 2 | + ( module X, |
16 | 3 | )
|
17 | 4 | where
|
18 | 5 |
|
19 |
| -import qualified Data.Generics as Syb |
20 |
| -import qualified Data.Text as T |
21 |
| -import qualified Data.Text.Lazy.Encoding as TL |
22 |
| -import Functora.Miso.Prelude |
23 |
| -import Functora.Miso.Types |
24 |
| -import Functora.Money (CurrencyCode (..), CurrencyInfo (..)) |
25 |
| -import qualified Functora.Prelude as Prelude |
26 |
| -import qualified Language.Javascript.JSaddle as JS |
27 |
| -import qualified Text.URI as URI |
28 |
| -import qualified Prelude ((!!)) |
29 |
| - |
30 |
| -popupText :: (Show a, Data a) => a -> JSM () |
31 |
| -popupText x = |
32 |
| - void |
33 |
| - $ JS.global |
34 |
| - ^. JS.js1 ("popupText" :: MisoString) (inspect x :: MisoString) |
35 |
| - |
36 |
| -shareText :: (Show a, Data a) => a -> model -> JSM model |
37 |
| -shareText x st = do |
38 |
| - let txt = inspect x |
39 |
| - unless (txt == mempty) $ do |
40 |
| - prom <- JS.global ^. JS.js1 ("shareText" :: MisoString) txt |
41 |
| - success <- JS.function $ \_ _ _ -> popupText @MisoString "Copied!" |
42 |
| - failure <- JS.function $ \_ _ _ -> popupText @MisoString "Failed to copy!" |
43 |
| - void $ prom ^. JS.js2 ("then" :: MisoString) success failure |
44 |
| - pure st |
45 |
| - |
46 |
| -addFieldPair :: |
47 |
| - ATraversal' model [FieldPair DynamicField Unique] -> model -> JSM model |
48 |
| -addFieldPair optic st = do |
49 |
| - item <- newFieldPair mempty $ DynamicFieldText mempty |
50 |
| - popupText @MisoString "Added note!" |
51 |
| - pure $ st & cloneTraversal optic %~ (<> [item]) |
52 |
| - |
53 |
| -addAsset :: ATraversal' model [Asset Unique] -> model -> JSM model |
54 |
| -addAsset optic st = do |
55 |
| - let cur = CurrencyInfo (CurrencyCode "usd") mempty |
56 |
| - item <- newAsset "Price" 0 cur |
57 |
| - popupText @MisoString "Added asset!" |
58 |
| - pure $ st & cloneTraversal optic %~ (<> [item]) |
59 |
| - |
60 |
| -addPaymentMethod :: |
61 |
| - ATraversal' model [PaymentMethod Unique] -> model -> JSM model |
62 |
| -addPaymentMethod optic st = do |
63 |
| - let cur = CurrencyInfo (CurrencyCode "btc") mempty |
64 |
| - item <- newPaymentMethod cur $ Just mempty |
65 |
| - popupText @MisoString "Added payment!" |
66 |
| - pure $ st & cloneTraversal optic %~ (<> [item]) |
67 |
| - |
68 |
| -moveUp :: ATraversal' model [item] -> Int -> model -> JSM model |
69 |
| -moveUp optic idx st = do |
70 |
| - popupText @MisoString $ "Moved #" <> inspect (idx + 1) <> " up!" |
71 |
| - pure $ st & cloneTraversal optic %~ swapAt (idx - 1) idx |
72 |
| - |
73 |
| -moveDown :: ATraversal' model [item] -> Int -> model -> JSM model |
74 |
| -moveDown optic idx st = do |
75 |
| - popupText @MisoString $ "Moved #" <> inspect (idx + 1) <> " down!" |
76 |
| - pure $ st & cloneTraversal optic %~ swapAt idx (idx + 1) |
77 |
| - |
78 |
| -removeAt :: ATraversal' model [a] -> Int -> model -> JSM model |
79 |
| -removeAt optic idx st = do |
80 |
| - popupText @MisoString $ "Removed #" <> inspect (idx + 1) <> "!" |
81 |
| - pure $ st & cloneTraversal optic %~ ((>>= uncurry updater) . zip [0 ..]) |
82 |
| - where |
83 |
| - updater loc el = |
84 |
| - if loc == idx |
85 |
| - then mempty |
86 |
| - else [el] |
87 |
| - |
88 |
| -duplicateAt :: |
89 |
| - forall model item. |
90 |
| - ( Data item |
91 |
| - ) => |
92 |
| - ATraversal' model [item] -> |
93 |
| - Int -> |
94 |
| - model -> |
95 |
| - JSM model |
96 |
| -duplicateAt optic idx st = do |
97 |
| - duplicator <- newUniqueDuplicator @MisoString |
98 |
| - let updater loc el = |
99 |
| - if loc == idx |
100 |
| - then [el, closed $ duplicator el] |
101 |
| - else [el] |
102 |
| - popupText @MisoString $ "Duplicated #" <> inspect (idx + 1) <> "!" |
103 |
| - pure $ st & cloneTraversal optic %~ ((>>= uncurry updater) . zip [0 ..]) |
104 |
| - where |
105 |
| - closed :: item -> item |
106 |
| - closed = Syb.everywhere $ Syb.mkT $ const Closed |
107 |
| - |
108 |
| -swapAt :: Int -> Int -> [a] -> [a] |
109 |
| -swapAt i j xs |
110 |
| - | i == j = xs |
111 |
| - | i < 0 || i >= len = xs |
112 |
| - | j < 0 || j >= len = xs |
113 |
| - | otherwise = do |
114 |
| - (idx, val) <- zip [0 ..] xs |
115 |
| - pure |
116 |
| - $ if |
117 |
| - | idx == i -> jval |
118 |
| - | idx == j -> ival |
119 |
| - | otherwise -> val |
120 |
| - where |
121 |
| - len = length xs |
122 |
| - ival = xs Prelude.!! i |
123 |
| - jval = xs Prelude.!! j |
124 |
| - |
125 |
| -openBrowserPage :: URI -> model -> JSM model |
126 |
| -openBrowserPage uri st = do |
127 |
| - void $ JS.global ^. JS.js1 @MisoString "openBrowserPage" (URI.render uri) |
128 |
| - pure st |
129 |
| - |
130 |
| -enterOrEscapeBlur :: Uid -> KeyCode -> model -> JSM model |
131 |
| -enterOrEscapeBlur uid (KeyCode code) st = do |
132 |
| - let enterOrEscape = [13, 27] :: [Int] |
133 |
| - when (code `elem` enterOrEscape) |
134 |
| - . void |
135 |
| - . JS.eval @MisoString |
136 |
| - $ "document.getElementById('" |
137 |
| - <> htmlUid uid |
138 |
| - <> "').getElementsByTagName('input')[0].blur();" |
139 |
| - pure st |
140 |
| - |
141 |
| -insertStorage :: (ToJSON a) => MisoString -> a -> JSM () |
142 |
| -insertStorage key raw = do |
143 |
| - val <- |
144 |
| - either throw (pure . toMisoString) |
145 |
| - . TL.decodeUtf8' |
146 |
| - . unTagged |
147 |
| - $ encodeJson raw |
148 |
| - void |
149 |
| - $ JS.global |
150 |
| - ^. JS.js2 @MisoString "insertStorage" key val |
151 |
| - |
152 |
| -selectStorage :: (FromJSON a) => MisoString -> (Maybe a -> JSM ()) -> JSM () |
153 |
| -selectStorage key after = do |
154 |
| - success <- JS.function $ \_ _ -> |
155 |
| - handleAny (\e -> consoleLog e >> after Nothing) . \case |
156 |
| - [val] -> do |
157 |
| - valExist <- ghcjsPure $ JS.isTruthy val |
158 |
| - if not valExist |
159 |
| - then after Nothing |
160 |
| - else do |
161 |
| - raw <- JS.fromJSVal @Prelude.Text val |
162 |
| - str <- maybe (throwString @MisoString "Storage bad type!") pure raw |
163 |
| - res <- either throwString pure $ decodeJson str |
164 |
| - after $ Just res |
165 |
| - _ -> |
166 |
| - throwString @MisoString "Storage bad argv!" |
167 |
| - failure <- |
168 |
| - JS.function $ \_ _ _ -> consoleLog @MisoString "Storage reader failure!" |
169 |
| - prom <- |
170 |
| - JS.global ^. JS.js1 @MisoString "selectStorage" key |
171 |
| - void |
172 |
| - $ prom |
173 |
| - ^. JS.js2 @MisoString "then" success failure |
174 |
| - |
175 |
| -selectClipboard :: (Maybe MisoString -> JSM ()) -> JSM () |
176 |
| -selectClipboard after = do |
177 |
| - success <- JS.function $ \_ _ -> |
178 |
| - handleAny (\e -> consoleLog e >> after Nothing) . \case |
179 |
| - [val] -> do |
180 |
| - valExist <- ghcjsPure $ JS.isTruthy val |
181 |
| - if not valExist |
182 |
| - then after Nothing |
183 |
| - else do |
184 |
| - raw <- JS.fromJSVal @Prelude.Text val |
185 |
| - str <- maybe (throwString @MisoString "Clipboard bad type!") pure raw |
186 |
| - popupText @MisoString "Inserted!" |
187 |
| - after . Just . from @Prelude.Text @MisoString $ T.strip str |
188 |
| - _ -> |
189 |
| - throwString @MisoString "Clipboard bad argv!" |
190 |
| - failure <- |
191 |
| - JS.function $ \_ _ _ -> |
192 |
| - popupText @MisoString "Failed to paste!" |
193 |
| - prom <- |
194 |
| - JS.global ^. JS.js0 @MisoString "selectClipboard" |
195 |
| - void |
196 |
| - $ prom |
197 |
| - ^. JS.js2 @MisoString "then" success failure |
| 6 | +import Functora.Miso.Jsm.Generic as X |
| 7 | +import Functora.Miso.Jsm.Specific as X |
0 commit comments