plzwrk (empty) → 0.0.0.0
raw patch · 16 files changed
+5493/−0 lines, 16 filesdep +aesondep +asterius-preludedep +basesetup-changed
Dependencies added: aeson, asterius-prelude, base, bytestring, containers, hspec, mtl, neat-interpolation, plzwrk, random, text, transformers, unordered-containers
Files
- ChangeLog.md +5/−0
- LICENSE +30/−0
- README.md +110/−0
- Setup.hs +2/−0
- hello-world/Main.hs +17/−0
- kitchen-sink/Main.hs +363/−0
- kitchen-sink/Nouns.hs +519/−0
- plzwrk.cabal +117/−0
- src/Web/Framework/Plzwrk.hs +38/−0
- src/Web/Framework/Plzwrk/Asterius.hs +209/−0
- src/Web/Framework/Plzwrk/Base.hs +68/−0
- src/Web/Framework/Plzwrk/Browserful.hs +33/−0
- src/Web/Framework/Plzwrk/Domify.hs +346/−0
- src/Web/Framework/Plzwrk/MockJSVal.hs +483/−0
- src/Web/Framework/Plzwrk/Tag.hs +3051/−0
- test/Spec.hs +102/−0
+ ChangeLog.md view
@@ -0,0 +1,5 @@+# Changelog for plzwrk++## 0.0.0.0++- Initial release.
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Author name here (c) 2020++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Author name here nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,110 @@+# plzwrk + +A Haskell front-end framework. + +## Hello world + +```haskell +import Web.Framework.Plzwrk +import Web.Framework.Plzwrk.Asterius +import Web.Framework.Plzwrk.Tag (p__) + +main :: IO () +main = do + browser <- asteriusBrowser + plzwrk'_ (p__ "Hello world!") browser +``` + +See it [live](https://plzwrk-hello-world.surge.sh). + +## Kitchen sink + +Check out the code [here](./kitchen-sink/Main.hs). + +See it [live](https://plzwrk-kitchen-sink.surge.sh). + +## Installation + +Add `plzwrk` to the `build-depends` stanza of your `.cabal` file. + +Also, add `plzwrk-X.Y.Z.?` to the `extra-deps` list of your `stack.yaml` file if you're using stack. + +## Making a webpage + +`plzwrk` uses [Asterius](https://github.com/tweag/asterius) as its backend for web development. Compiling an application using `plzwrk` is no different than compiling an application using `ahc-cabal` and `ahc-dist` as described in the [Asterius documentation](https://asterius.netlify.app) with **one caveat**. You **must** use `-f plzwrk-enable-asterius` when running `ahc-cabal`. + +A minimal flow is shown below, mostly copied from the asterius documentation. It assumes that you have a cabal-buildable project in the root directory. Note the use of the `-f plzwrk-enable-asterius` flag in the `ahc-cabal` step. + +```bash +username@hostname:~/my-dir$ docker run --rm -it -v $(pwd):/project -w /project terrorjack/asterius +asterius@hostname:/project$ ahc-cabal new-install -f plzwrk-enable-asterius --installdir <inst-dir> <exec-name> +asterius@hostname:/project$ cd <inst-dir> && ahc-dist --input-exe <exec-name> --browser --bundle +``` + +## Documentation + +The main documentation for `plzwrk` is on [hackage](https://https://hackage.haskell.org/package/plzwrk). The four importable modules are: + +- `Web.Frameworks.Plzwrk` for the basic functions +- `Web.Frameworks.Plzwrk.Tag` for helper functions to make takes like `input` or `br`. +- `Web.Frameworks.Plzwrk.MockJSVal` to use a mock browser. +- `Web.Frameworks.Plzwrk.Asterius` to use a bindings for a real browser courtesy of [Asterius](https://github.com/tweag/asterius). + +## Design + +`plzwrk` is inspired by [redux](https://redux.js.org/) for its state management. The main idea is that you have a HTML-creation function that accepts one or more variables from a state that is composed, via applicative functors, with getters from a state. + +```haskell + +-- State +data MyState = MkMyState { _name :: Text, age :: Int, _tags :: [Text] } + +-- Function hydrating a DOM with elementse from the state +makeP = (\name age -> p'__ concat [name, " is the name and ", show age, " is my age."]) <$> _name <*> _age +``` + +HTML-creation functions can be nested, allowing for powerful abstractions. + +```haskell +nested = div_ (take 10 $ repeat makeP) +``` + +HTML-creation functions use an apostrophe after the tag name (ie `div'`) if they accept arguments and no apostrophe (ie `div`) if they don't. Additionally, tags that do not have any attributes (class, style etc) are marked with a trailing underscore (`div_ [p__ "hello"]`), and tags that only accept text are marked with two trailing underscores (`p__ "hello"`). + +The HTML-creation function itself should be pure with type `(s -> Node s opq)`, where `s` is the type of the state and `opq` is the type of the opaque pointer used to represent a JavaScript value. `opq` will rarely need to be provided manually as it is induced from the compiler based on the `Browserful` being used (ie `asteriusBrowser`). + +Event handlers take two arguments - an opaque pointer to the event and the current state - and return a new state (which could just be the original state) in the `IO` monad. For example, if the state is an integer, a valid event handler could be: + +``` +eh :: opq -> Int -> IO Int +eh _ i = pure $ i + 1 +``` + +To handle events (ie extract values from input events, etc) you can use one of the functions exported by `Web.Framework.Plzwrk`. Please see the [hackage documentation](https://hackage.haskell.org/package/plzwrk) for more information. + +> If you are using the Asterius backend, callback functions are still quite fragile and subject to breakage. The less third-party libraries you use in them, the better. For example, avoid using `Data.Text` and `aeson` if possible. + +## Testing your code + +Plzwrk comes with a mock browser that can act as a drop-in replacement for your browser. Use this in your tests. + +```haskell +import Web.Framework.Plzwrk.MockJSVal + +main :: IO () + browser <- makeMockBrowser + print "Now I'm using the mock browser." +``` + +## Using + +Plzwrk should be considered experimental. It is unfit for production and the syntax will change frequently, often in non-backward-compatible ways. There is a [changelog](ChangeLog.md). + +## Contributing + +Thanks for your interest in contributing! Here is a small list of things I'd really appreciate help with: + +- Static site rendering +- Automatic code splitting +- Hot reloading +- Documentation
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ hello-world/Main.hs view
@@ -0,0 +1,17 @@+{-# LANGUAGE CPP #-} + +import Web.Framework.Plzwrk +#if defined(PLZWRK_ENABLE_ASTERIUS) +import Web.Framework.Plzwrk.Asterius +import Web.Framework.Plzwrk.Tag (p__) + +main :: IO () +main = do + browser <- asteriusBrowser + plzwrk'_ (p__ "Hello world!") browser + + +# else +main :: IO () +main = print "If you're using ahc, please set -DPLZWRK_ENABLE_ASTERIUS as a flag to run this executable." +# endif
+ kitchen-sink/Main.hs view
@@ -0,0 +1,363 @@+{-# LANGUAGE CPP #-} +{-# LANGUAGE OverloadedStrings #-} +#if defined(PLZWRK_ENABLE_ASTERIUS) +{-# LANGUAGE QuasiQuotes #-} + + +import Asterius.Types +import Control.Monad +import Data.HashMap.Strict hiding ( null ) +import Data.IORef +import NeatInterpolation +import qualified Data.Set as S +import qualified Data.Text as DT +import Nouns +import Prelude hiding ( div + , span + ) +import Web.Framework.Plzwrk +import Web.Framework.Plzwrk.Asterius +import Web.Framework.Plzwrk.Tag + hiding ( main + , main_ + , main'_ + ) +import qualified Web.Framework.Plzwrk.Tag as T + ( main + , main_ + , main'_ + ) +data MyState = MyState + { _name :: String + , _abstractToConcrete :: [(String, String)] + , _myNoun :: String + } + deriving Show + +main :: IO () +main = do + browser <- asteriusBrowser + -- add some css! + _head <- (getHead browser) + _style <- (createElement browser) "style" + _css <- (createTextNode browser) (DT.unpack myCss) + (appendChild browser) _style _css + (appendChild browser) _head _style + -- here is our "surprise" aphorism + let surpriseF = + (\noun -> if (length noun == 0) + then div'_ [] + else p'__ $ concat ["Life is like", a_n noun, noun] + ) + <$> _myNoun + -- here is our input + let + inputF = input + (pure dats' + { _simple = singleton "type" "text" + , _style = singleton "box-sizing" "content-box" + , _handlers = singleton + "input" + (\e s -> do + opq <- (getOpaque browser) e "target" + v <- maybe (pure Nothing) + (\y -> (getString browser) y "value") + opq + return $ maybe s (\q -> s { _myNoun = q }) v + ) + } + ) + [] + -- and here is our main div + let + mainDivF = + (\abstractToConcrete name -> T.main'_ + [ section + (pure dats' { _class = S.singleton "content" }) + [ h1__ "Aphorism Machine" + , ul + (pure dats' { _class = S.singleton "res" }) + (fmap + (\(abs, conc) -> + (li__ (concat [abs, " is like", a_n conc, conc])) + ) + abstractToConcrete + ) + , br + , surpriseF + , div + (pure dats' + { _style = fromList + [("width", "100%"), ("display", "inline-block")] + } + ) + [ button + (pure dats' + { _simple = singleton "id" "incr" + , _class = S.singleton "dim" + , _handlers = singleton + "click" + (\_ s -> do + (consoleLog browser) + $ "Here is the current state " + <> show s + concept <- randAbstract (random01 browser) + comparedTo <- randConcrete (random01 browser) + let + newS = s + { _abstractToConcrete = (concept, comparedTo) + : abstractToConcrete + } + (consoleLog browser) + $ "Here is the new state " + <> show newS + return $ newS + ) + } + ) + [txt "More aphorisms"] + , button + (pure dats' + { _simple = singleton "id" "decr" + , _class = S.singleton "dim" + , _handlers = singleton + "click" + (\_ s -> pure $ s + { _abstractToConcrete = if (null abstractToConcrete) + then [] + else tail abstractToConcrete + } + ) + } + ) + [txt "Less aphorisms"] + ] + , inputF + , p_ + [ txt "Logged in as: " + , span (pure dats' { _class = S.singleton "username" }) [txt name] + ] + ] + ] + ) + <$> _abstractToConcrete + <*> _name + let state = MyState "Bob" [] "" + plzwrk' mainDivF state browser + + +randFromList :: [String] -> IO Double -> IO String +randFromList l f = do + z <- f + let i = round $ (fromIntegral $ length l) * z + return $ l !! i + + +a_n :: String -> String +a_n x = + let hd = take 1 x + in if (hd == "a" || hd == "e" || hd == "i" || hd == "o" || hd == "u") + then " an " + else " a " + +randAbstract :: IO Double -> IO String +randAbstract = randFromList abstract + +randConcrete :: IO Double -> IO String +randConcrete = randFromList concrete + +myCss = [text| +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; +} + +html, +body { + height: 100%; +} + +body>div:first-child, +body>div:first-child>div:first-child, +body>div:first-child>div:first-child>div { + height: inherit; +} + +input { + box-sizing: border-box; + padding: 9.5px 15px; + border: 0; + text-align: center; + border-bottom: 1px solid #d8d8d8; + font-size: 14px; + transition: border-bottom-color 100ms ease-in, color 100ms ease-in; + max-width: 250px; + border-radius: 0; +} + +input:focus { + outline: none; + border-color: #000; +} + +.dim { + opacity: 1; + transition: opacity .15s ease-in; + cursor: pointer; +} +.dim:hover, +.dim:focus { + opacity: .5; + transition: opacity .15s ease-in; +} +.dim:active { + opacity: .8; + transition: opacity .15s ease-out; +} + +@media (min-width: 768px) { + input { + min-width: 300px; + max-width: 620px; + } +} + +ul { + list-style: none; + padding-left: 0; +} + +hr { + margin-top: 15px; + margin-bottom: 15px; + width: 70%; +} + +main { + width: 100%; + height: 100%; + display: flex; + justify-content: center; + align-items: center; + padding: 20px; + box-sizing: border-box; + flex-direction: column; +} + +.content { + text-align: center; + max-width: 100%; + -webkit-animation: fadein 2s; + -moz-animation: fadein 2s; + -ms-animation: fadein 2s; + -o-animation: fadein 2s; + animation: fadein 2s; +} + +h1 { + font-family: 'Montserrat', sans-serif; + font-weight: normal; + font-size: 32px; + text-align: center; + margin-bottom: 25px; +} + +aside { + display: flex; + justify-content: center; + align-items: center; + padding: 50px 0 40px 0; + position: absolute; + bottom: 0; + left: 0; + right: 0; +} + +aside nav { + height: 18px; + display: flex; + justify-content: center; + align-items: center; +} + +aside nav a { + font-size: 13px; + color: #b2b2b2; + text-decoration: none; + transition: color 100ms ease-in; +} + +aside nav b { + display: block; + background: #b2b2b2; + width: 1px; + height: 100%; + margin: 0 10px; +} + +.username { + font-weight: 500; +} + +p { + font-weight: 400; + font-size: 14px; + line-height: 24px; + max-width: 390px; + text-align: center; + margin: 14px auto 30px auto; +} + +button { + background-color: rgba(0, 0, 0, 0.671); + border: none; + color: white; + padding: 10px 12px; + margin: 10px; + text-align: center; + border-radius: 12px; + text-decoration: none; + display: inline-block; + font-size: 14px; + } + +@keyframes fadein { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +@-moz-keyframes fadein { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +@-webkit-keyframes fadein { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +@media (max-height: 400px) { + aside { + display: none; + } +} + |] + +# else +main :: IO () +main = print "If you're using ahc, please set -DPLZWRK_ENABLE_ASTERIUS as a flag to run this executable." +# endif
+ kitchen-sink/Nouns.hs view
@@ -0,0 +1,519 @@+module Nouns(abstract, concrete) where + +abstract = + [ "Ability" + , "Absurdity" + , "Achievement" + , "Action" + , "Adoration" + , "Adventure" + , "Advice" + , "Agitation" + , "Agony" + , "Alacrity" + , "Amazement" + , "Anger" + , "Anguish" + , "Anxiety" + , "Apathy" + , "Arrogance" + , "Artistry" + , "Audacity" + , "Awareness" + , "Awe" + , "Beauty" + , "Being" + , "Boredom" + , "Bravery" + , "Breadth" + , "Brilliance" + , "Brutality" + , "Calm" + , "Candor" + , "Care" + , "Chaos" + , "Charisma" + , "Charity" + , "Charm" + , "Childhood" + , "Clarity" + , "Cleverness" + , "Cohesion" + , "Coldness" + , "Comfort" + , "Communication" + , "Compassion" + , "Complexity" + , "Conceit" + , "Confidence" + , "Conflict" + , "Conformity" + , "Confusion" + , "Consciousness" + , "Control" + , "Courage" + , "Cowardice" + , "Crime" + , "Culture" + , "Dawn" + , "Day" + , "Death" + , "Deceit" + , "Defeat" + , "Delight" + , "Democracy" + , "Despair" + , "Disappointment" + , "Disbelief" + , "Discord" + , "Dishonesty" + , "Dissension" + , "Ego" + , "Elation" + , "Energy" + , "Ennui" + , "Enthusiasm" + , "Envy" + , "Evening" + , "Evil" + , "Excitement" + , "Exhilaration" + , "Exuberance" + , "Failure" + , "Faith" + , "Fear" + , "Fiction" + , "Forgiveness" + , "Freedom" + , "Genius" + , "Goodness" + , "Grace" + , "Greatness" + , "Grief" + , "Growth" + , "Happiness" + , "Hate" + , "Honesty" + , "Honor" + , "Hope" + , "Hubris" + , "Humility" + , "Humor" + , "Hunger" + , "Impudence" + , "Indifference" + , "Infatuation" + , "Insanity" + , "Integrity" + , "Intelligence" + , "Irritation" + , "Jealousy" + , "Joy" + , "Jubilation" + , "Justice" + , "Justification" + , "Kindness" + , "Kingship" + , "Knack" + , "Knell" + , "Knowledge" + , "Laughter" + , "Lavishness" + , "Law" + , "Leadership" + , "Leer" + , "Legitimacy" + , "Leisure" + , "Length" + , "Liberty" + , "Lie" + , "Life" + , "Listlessness" + , "Loneliness" + , "Loss" + , "Love" + , "Loyalty" + , "Luck" + , "Luxury" + , "Malice" + , "Maliciousness" + , "Malignity" + , "Manhood" + , "Marriage" + , "Martyrdom" + , "Maturity" + , "Meekness" + , "Membership" + , "Memory" + , "Mercy" + , "Meticulousness" + , "Mien" + , "Minute" + , "Misery" + , "Modesty" + , "Modicum" + , "Moment" + , "Monotony" + , "Month" + , "Morning" + , "Mortification" + , "Motivation" + , "Movement" + , "Movement" + , "Music" + , "Myriad" + , "Nadir" + , "Naivete" + , "Nap" + , "Narcissism" + , "Nausea" + , "Need" + , "Negativity" + , "Nervousness" + , "" + , "Newness" + , "Nonconformity" + , "Normalcy" + , "Nouns" + , "Nuance" + , "Obnoxiousness" + , "Occasion" + , "Omen" + , "Openness" + , "Opinion" + , "Opportunism" + , "Opportunity" + , "Optimism" + , "Pain" + , "Panacea" + , "Parenthood" + , "Parsimony" + , "Particularity" + , "Passiveness" + , "Past" + , "Patience" + , "Patriotism" + , "Peace" + , "Peculiar" + , "Peculiarity" + , "Penchant" + , "Permanence" + , "Permission" + , "Perseverance" + , "Perusal" + , "Pessimism" + , "Philosophy" + , "Placidity" + , "Pleasure" + , "Plethora" + , "Positivity" + , "Poverty" + , "Power" + , "Precision" + , "Predilection" + , "Preeminence" + , "Pride" + , "Principle" + , "Progress" + , "Prominence" + , "Prosperity" + , "Rage" + , "Reality" + , "Reason" + , "Redemption" + , "Refreshment" + , "Refusal" + , "Refutation" + , "Relaxation" + , "Relief" + , "Religion" + , "Reminiscence" + , "Repercussion" + , "Replacement" + , "Repulsiveness" + , "Resiliency" + , "Restoration" + , "Retirement" + , "Rhythm" + , "Riches" + , "Right" + , "Romance" + , "Rumor" + , "Rumour" + , "Ruthlessness" + , "Sacrifice" + , "Sadness" + , "Sale" + , "Sanity" + , "Satisfaction" + , "Scholarship" + , "Scrupulousness" + , "Security" + , "Self" + , "Sensitivity" + , "Serendipity" + , "Serenity" + , "Service" + , "Shock" + , "Silliness" + , "Sincerity" + , "Situation" + , "Skill" + , "Slave" + , "Slavery" + , "Sleep" + , "Solace" + , "Solitude" + , "Sophistication" + , "Sorrow" + , "Sparkle" + , "Speculation" + , "Speech" + , "Speed" + , "Spitefulness" + , "Squandering" + , "Stance" + , "Stardom" + , "States" + , "States" + , "Stinginess" + , "Strength" + , "Stress" + , "Strict" + , "Strictness" + , "Strife" + , "Stupidity" + , "Submission" + , "Success" + , "Suffering" + , "Surprise" + , "Susceptibleness" + , "Sympathy" + , "Talent" + , "Tediousness" + , "Tedium" + , "Tender" + , "Testimony" + , "Thirst" + , "Thoroughness" + , "Thought" + , "Thrill" + , "Time" + , "Timidness" + , "Timing" + , "Tired" + , "Tiredness" + , "Tolerance" + , "Torment" + , "Tranquility" + , "Treachery" + , "Treatment" + , "Trend" + , "Trouble" + , "Trust" + , "Truth" + , "Turbulence" + , "Turmoil" + , "Ubiquity" + , "Ugliness" + , "Umbrage" + , "Uncertainty" + , "Uncouthness" + , "Unease" + , "Unemployment" + , "Union" + , "Uniqueness" + , "Unreality" + , "Utility" + , "Vanity" + , "Viciousness" + , "Victory" + , "Vulnerability" + , "Wariness" + , "Warmth" + , "Wary" + , "Weakness" + , "Wealth" + , "Weariness" + , "Week" + , "Width" + , "Wisdom" + , "Wit" + ] + +concrete = + [ "whisker" + , "paw" + , "mammoth" + , "spider" + , "moth" + , "bug" + , "bat" + , "vulture" + , "owl" + , "turtle" + , "worm" + , "earthworm" + , "toad" + , "porcupine" + , "armadillo" + , "rat" + , "squirrel" + , "hedgehog" + , "chipmunk" + , "gerbil" + , "hamster" + , "mouse" + , "mole" + , "anteater" + , "platypus" + , "cow" + , "oxen" + , "cattle" + , "sheep" + , "lamb" + , "ram" + , "goat" + , "kid" + , "pig" + , "hog" + , "shoat" + , "sow" + , "fox" + , "vixen" + , "lemur" + , "raccoon" + , "weasel monkey" + , "ape" + , "chimpanzee" + , "orangutan" + , "baboon" + , "pony" + , "pinto" + , "mare" + , "filly" + , "gelding" + , "bronco" + , "colt" + , "stallion" + , "donkey" + , "zebra" + , "mule" + , "camel" + , "dromedary" + , "gazelle" + , "tom" + , "bird" + , "goose" + , "duck" + , "drake" + , "gander" + , "turkey" + , "songbird" + , "lark" + , "nightingale" + , "wren" + , "eagle" + , "hawk" + , "kitten" + , "chick" + , "rooster" + , "hen" + , "crow" + , "raven" + , "cat" + , "kitten" + , "mutt" + , "wolf" + , "cub" + , "tiger" + , "lion" + , "elephant" + , "cheetah" + , "puma" + , "jackal" + , "jaguar" + , "ocelot" + , "rhinoceros" + , "alpaca" + , "antelope" + , "deer" + , "doe" + , "fawn" + , "stag" + , "kangaroo" + , "joey" + , "koala" + , "sloth" + , "wombat" + , "bear" + , "hyena" + , "crocodile" + , "snake" + , "giraffe" + , "whale" + , "shark" + , "dolphin" + , "seal" + , "bed" + , "hammock" + , "hassock" + , "mirror" + , "hutch" + , "locker" + , "painting" + , "chalice" + , "cage" + , "urn" + , "bow" + , "sword" + , "dart" + , "dagger" + , "hatchet" + , "candle" + , "mop" + , "pail" + , "pipe" + , "brush" + , "easel" + , "gun" + , "rope" + , "balloon" + , "vase" + , "typewriter" + , "stylus" + , "pencil" + , "desk" + , "backpack" + , "saddle" + , "cash machine pot" + , "plate" + , "dish" + , "fork" + , "spoon" + , "samovar" + , "monsoon" + , "hurricane" + , "typhoon" + , "rain" + , "storm" + , "hail" + , "blizzard" + , "breeze" + , "whirlwind" + , "maelstrom" + , "dust storm" + , "cloudburst" + , "tornado" + , "twister" + , "cloud" + , "flood" + , "aftershock" + , "tremor" + , "earthquake" + , "lightning avalanche" + , "eclipse" + , "meteor shower" + , "thunderbolt" + , "tsunami" + ]
+ plzwrk.cabal view
@@ -0,0 +1,117 @@+cabal-version: 1.12++-- This file has been generated from package.yaml by hpack version 0.31.2.+--+-- see: https://github.com/sol/hpack+--+-- hash: 8099ceb0d406f862d89306de053aba4c75999a9e0d74ac6a502458d503e7dcc1++name: plzwrk+version: 0.0.0.0+category: Web+synopsis: A front-end framework+description: Please see the README on GitHub at <https://github.com/meeshkan/plzwrk#readme>+homepage: https://github.com/meeshkan/plzwrk#readme+bug-reports: https://github.com/meeshkan/plzwrk/issues+author: Mike Solomon+maintainer: mike@meeshkan.com+copyright: 2020 Mike Solomon+license: BSD3+license-file: LICENSE+build-type: Simple+extra-source-files:+ README.md+ ChangeLog.md++source-repository head+ type: git+ location: https://github.com/meeshkan/plzwrk++flag plzwrk-enable-asterius+ Description: Enable asterius+ Default: False+ Manual: True++library+ exposed-modules:+ Web.Framework.Plzwrk+ , Web.Framework.Plzwrk.Asterius+ , Web.Framework.Plzwrk.MockJSVal+ , Web.Framework.Plzwrk.Tag+ other-modules:+ Paths_plzwrk+ , Web.Framework.Plzwrk.Base+ , Web.Framework.Plzwrk.Browserful+ , Web.Framework.Plzwrk.Domify+ hs-source-dirs:+ src+ build-depends:+ base >=4.7 && <5+ , aeson >= 1.4.7 && < 1.5+ , bytestring >= 0.10.10 && < 0.11+ , containers >= 0.6.2 && < 0.7+ , mtl >= 2.2.2 && < 2.3+ , random >= 1.1 && < 1.2+ , text >= 1.2.3 && < 1.3+ , transformers >= 0.5.6 && < 0.6+ , unordered-containers >= 0.2.10 && < 0.3+ default-language: Haskell2010+ if flag(plzwrk-enable-asterius)+ cpp-options:+ -DPLZWRK_ENABLE_ASTERIUS+ build-depends:+ asterius-prelude++executable kitchen-sink-exe+ main-is: Main.hs+ other-modules:+ Nouns+ , Paths_plzwrk+ hs-source-dirs:+ kitchen-sink+ ghc-options: -rtsopts -with-rtsopts=-N+ build-depends:+ base >=4.7 && <5+ , plzwrk+ , containers >= 0.6.2 && < 0.7+ , neat-interpolation >= 0.5.1 && < 0.6+ , text >= 1.2.3 && < 1.3+ , unordered-containers >= 0.2.10 && < 0.3+ + default-language: Haskell2010+ if flag(plzwrk-enable-asterius)+ cpp-options:+ -DPLZWRK_ENABLE_ASTERIUS++executable hello-world-exe+ main-is: Main.hs+ other-modules:+ Paths_plzwrk+ hs-source-dirs:+ hello-world+ ghc-options: -rtsopts -with-rtsopts=-N+ build-depends:+ base >=4.7 && <5+ , plzwrk+ , text >= 1.2.3 && < 1.3+ default-language: Haskell2010+ if flag(plzwrk-enable-asterius)+ cpp-options:+ -DPLZWRK_ENABLE_ASTERIUS++test-suite plzwrk-test+ type: exitcode-stdio-1.0+ main-is: Spec.hs+ other-modules:+ Paths_plzwrk+ hs-source-dirs:+ test+ ghc-options: -threaded -rtsopts -with-rtsopts=-N+ build-depends:+ base >=4.7 && <5+ , hspec >=2.7.0 && <2.7.1+ , mtl >=2.2.2 && <2.3+ , plzwrk+ , text >=1.2.3 && <1.3+ , unordered-containers >=0.2.10 && <0.3+ default-language: Haskell2010
+ src/Web/Framework/Plzwrk.hs view
@@ -0,0 +1,38 @@+{-| +Module : Web.Framework.Plzwrk +Description : Base functions for plzwrk +Copyright : (c) Mike Solomon 2020 +License : GPL-3 +Maintainer : mike@meeshkan.com +Stability : experimental +Portability : POSIX, Windows + +This module contains the base functions for plzwrk, notably +the family of plzwrk functions needed for plzwrk to work. It +also exports most of the utility functions used for building +web applications, like event handling and attribute wrangling. +-} + +module Web.Framework.Plzwrk + ( hydrate + , dats + , dats' + , Node(..) + , HydratedNode(..) + , Attributes(..) + , cssToStyle + , Browserful(..) + , reconcile + , plzwrk + , plzwrk' + , plzwrk'_ + , OldStuff(..) + ) +where + +-- need to hide div from prelude + +import Prelude hiding ( div ) +import Web.Framework.Plzwrk.Base +import Web.Framework.Plzwrk.Browserful +import Web.Framework.Plzwrk.Domify
+ src/Web/Framework/Plzwrk/Asterius.hs view
@@ -0,0 +1,209 @@+{-# LANGUAGE CPP #-} +#if defined(PLZWRK_ENABLE_ASTERIUS) +{-# LANGUAGE InterruptibleFFI #-} +module Web.Framework.Plzwrk.Asterius (asteriusBrowser) where + +import Asterius.Aeson +import Asterius.ByteString +import Asterius.Types +import qualified Data.ByteString as BS +import Data.ByteString.Unsafe +import Data.Coerce +import Foreign.Ptr +import Web.Framework.Plzwrk.Browserful + +asteriusBrowser :: IO (Browserful JSVal) +asteriusBrowser = return Browserful + { addEventListener = _addEventListener + , appendChild = _appendChild + , click = _click + , consoleLog = _consoleLog + , consoleLog' = _consoleLog' + , createElement = _createElement + , createTextNode = _createTextNode + , freeCallback = _freeCallback + , getBody = _getBody + , getBool = _getBool + , getDouble = _getDouble + , getChildren = _getChildren + , getElementById = _getElementById + , getHead = _getHead + , getInt = _getInt + , getOpaque = _getOpaque + , getString = _getString + , getTag = _getTag + , insertBefore = _insertBefore + , invokeOn = _invokeOn + , makeHaskellCallback = _makeHaskellCallback + , random01 = _random01 + , removeChild = _removeChild + , removeEventListener = _removeEventListener + , setAttribute = _setAttribute + , textContent = _textContent + } + +_createElement :: String -> IO JSVal +_createElement = js_createElement . toJSString + +_getTag :: JSVal -> IO String +_getTag x = do + v <- js_getTag x + return $ fromJSString v + +_textContent :: JSVal -> IO String +_textContent x = do + v <- js_textContent x + return $ fromJSString v + +_setAttribute :: JSVal -> String -> String -> IO () +_setAttribute e k v = js_setAttribute e (toJSString k) (toJSString v) + +_getOpaque :: JSVal -> String -> IO (Maybe JSVal) +_getOpaque n k = do + isUndef <- js_null_or_undef n + if isUndef then pure Nothing else (do + v <- _js_getOpaque n (toJSString k) + isUndef' <- js_null_or_undef v + if isUndef' then pure Nothing else pure (Just v) + ) + +_getString :: JSVal -> String -> IO (Maybe String) +_getString n k = _getGeneric (\v -> (jsonFromJSVal v) :: Either String String) n k + +_getBool :: JSVal -> String -> IO (Maybe Bool) +_getBool n k = _getGeneric (\v -> (jsonFromJSVal v) :: Either String Bool) n k + +_getInt :: JSVal -> String -> IO (Maybe Int) +_getInt n k = _getGeneric (\v -> (jsonFromJSVal v) :: Either String Int) n k + +_getDouble :: JSVal -> String -> IO (Maybe Double) +_getDouble n k = _getGeneric (\v -> (jsonFromJSVal v) :: Either String Double) n k + +_getGeneric :: (JSVal -> Either String a) -> JSVal -> String -> IO (Maybe a) +_getGeneric f n k = do + isUndef <- js_null_or_undef n + if isUndef then pure Nothing else (do + v <- _js_getOpaque n (toJSString k) + isUndef' <- js_null_or_undef v + if isUndef' then pure Nothing else ( + let q = f v in + either (\_ -> pure Nothing) (pure . Just) q) + ) + +_consoleLog :: String -> IO () +_consoleLog t = _js_consoleLog (toJSString t) + +_consoleLog' :: JSVal -> IO () +_consoleLog' v = _js_consoleLog' v + + +_addEventListener :: JSVal -> String -> JSVal -> IO () +_addEventListener target event callback = + js_addEventListener target (toJSString event) callback + +_removeEventListener :: JSVal -> String -> JSVal -> IO () +_removeEventListener target event callback = + js_removeEventListener target (toJSString event) callback + +_createTextNode :: String -> IO JSVal +_createTextNode = js_createTextNode . toJSString + +_invokeOn :: JSVal -> String -> IO () +_invokeOn e s = _js_invokeOn e (toJSString s) + + +_getElementById :: String -> IO (Maybe JSVal) +_getElementById k = do + v <- js_getElementById (toJSString k) + u <- js_null_or_undef v + return $ if u then Nothing else Just v + +getJSVal :: JSFunction -> JSVal +getJSVal (JSFunction x) = x + +_makeHaskellCallback :: (JSVal -> IO ()) -> IO JSVal +_makeHaskellCallback a = do + x <- makeHaskellCallback1 a + return $ getJSVal x + +_freeCallback :: JSVal -> IO () +_freeCallback v = freeHaskellCallback (JSFunction v) + +foreign import javascript "console.log($1)" + _js_consoleLog :: JSString -> IO () + +foreign import javascript "console.log($1)" + _js_consoleLog' :: JSVal -> IO () + + +foreign import javascript "$1[$2]()" + _js_invokeOn :: JSVal -> JSString -> IO () + +foreign import javascript "$1[$2]" + _js_getOpaque :: JSVal -> JSString -> IO JSVal + +foreign import javascript "document.createElement($1)" + js_createElement :: JSString -> IO JSVal + +foreign import javascript "Math.random()" + _random01 :: IO Double + +foreign import javascript "document.body" + _getBody :: IO JSVal + +foreign import javascript "document.head" + _getHead :: IO JSVal + +foreign import javascript "$1.tagName" + js_getTag :: JSVal -> IO JSString + +foreign import javascript "$1.textContent" + js_textContent :: JSVal -> IO JSString + +foreign import javascript "$1.setAttribute($2,$3)" + js_setAttribute :: JSVal -> JSString -> JSString -> IO () + +foreign import javascript "$1.appendChild($2)" + _appendChild :: JSVal -> JSVal -> IO () + +foreign import javascript "($1 == null) || ($1 == undefined)" + js_null_or_undef :: JSVal -> IO Bool + +foreign import javascript "$1.childNodes" + _js_getChildren :: JSVal -> IO JSArray + +_getChildren :: JSVal -> IO [JSVal] +_getChildren x = do + v <- _js_getChildren x + return $ fromJSArray v + +foreign import javascript "$1.click()" + _click :: JSVal -> IO () + +foreign import javascript "$1.insertBefore($2,$3)" + _insertBefore :: JSVal -> JSVal -> JSVal -> IO () + +foreign import javascript "$1.removeChild($2)" + _removeChild :: JSVal -> JSVal -> IO () + +foreign import javascript "$1.addEventListener($2,$3)" + js_addEventListener :: JSVal -> JSString -> JSVal -> IO () + +foreign import javascript "$1.removeEventListener($2,$3)" + js_removeEventListener :: JSVal -> JSString -> JSVal -> IO () + +foreign import javascript "document.createTextNode($1)" + js_createTextNode :: JSString -> IO JSVal + +foreign import javascript "document.getElementById($1)" + js_getElementById :: JSString -> IO JSVal + +foreign import javascript "wrapper oneshot" + makeHaskellCallback1 :: (JSVal -> IO ()) -> IO JSFunction + +# else +module Web.Framework.Plzwrk.Asterius where + +ignoreMe :: IO () +ignoreMe = print "ignore me" +# endif
+ src/Web/Framework/Plzwrk/Base.hs view
@@ -0,0 +1,68 @@+module Web.Framework.Plzwrk.Base + ( hydrate + , dats + , dats' + , Node(..) + , HydratedNode(..) + , Attributes(..) + , cssToStyle + ) +where + +import Data.List + +import Data.HashMap.Strict +import Data.Set hiding ( empty + , toList + ) +import qualified Data.Set as S + +cssToStyle :: (HashMap String String) -> String +cssToStyle css = + (intercalate ";" $ fmap (\(x, y) -> x <> ":" <> y) (toList css)) + +-- data classes + +data Attributes s opq = MkAttributes + { _style :: HashMap String String + , _class :: Set String + , _simple :: HashMap String String + , _handlers :: HashMap String (opq -> s -> IO s) + } + +dats = (\_ -> MkAttributes empty S.empty empty empty) +dats' = MkAttributes empty S.empty empty empty + + +instance Show (Attributes s opq) where + show (MkAttributes __style __class __simple _) = + "Attributes (" + <> show __style + <> ", " + <> show __class + <> ", " + <> show __simple + <> ")" + +data Node s opq = Element String (s -> Attributes s opq) [s -> Node s opq] + | TextNode String + +instance Show (Node s opq) where + show (Element t _ _) = show t + show (TextNode t ) = show t + +data HydratedNode s opq = HydratedElement + { _hy_tag :: String + , _hy_attr :: (Attributes s opq) + , _hy_kids :: [HydratedNode s opq] + } + | HydratedTextNode String + deriving (Show) + +_hydrate :: s -> Node s opq -> HydratedNode s opq +_hydrate s (Element a b c) = + HydratedElement a (b s) (fmap (\x -> hydrate s x) c) +_hydrate s (TextNode t) = HydratedTextNode t + +hydrate :: s -> (s -> Node s opq) -> HydratedNode s opq +hydrate s f = _hydrate s (f s)
+ src/Web/Framework/Plzwrk/Browserful.hs view
@@ -0,0 +1,33 @@+module Web.Framework.Plzwrk.Browserful + ( Browserful(..) + ) +where + +data Browserful jsval = Browserful + { addEventListener :: jsval -> String -> jsval -> IO () + , appendChild :: jsval -> jsval -> IO () + , consoleLog :: String -> IO () + , consoleLog' :: jsval -> IO () + , click :: jsval -> IO () + , createElement :: String -> IO jsval + , createTextNode :: String -> IO jsval + , freeCallback :: jsval -> IO () + , getBody :: IO jsval + , getBool :: jsval -> String -> IO (Maybe Bool) + , getChildren :: jsval -> IO [jsval] + , getDouble :: jsval -> String -> IO (Maybe Double) + , getHead :: IO jsval + , getElementById :: String -> IO (Maybe jsval) + , getInt :: jsval -> String -> IO (Maybe Int) + , getOpaque :: jsval -> String -> IO (Maybe jsval) + , getString :: jsval -> String -> IO (Maybe String) + , getTag :: jsval -> IO String + , insertBefore :: jsval -> jsval -> jsval -> IO () + , invokeOn :: jsval -> String -> IO () + , makeHaskellCallback :: (jsval -> IO ()) -> IO jsval + , random01 :: IO Double + , removeChild :: jsval -> jsval -> IO () + , removeEventListener :: jsval -> String -> jsval -> IO () + , setAttribute :: jsval -> String -> String -> IO () + , textContent :: jsval -> IO String + }
+ src/Web/Framework/Plzwrk/Domify.hs view
@@ -0,0 +1,346 @@+module Web.Framework.Plzwrk.Domify + ( reconcile + , plzwrk + , plzwrk' + , plzwrk'_ + , OldStuff(..) + ) +where + +import Control.Applicative +import Control.Monad +import Control.Monad.Reader +import Control.Monad.Trans +import Control.Monad.Trans.Maybe +import qualified Data.HashMap.Strict as HM +import Data.IORef +import Data.Maybe ( catMaybes ) +import qualified Data.Set as S +import Web.Framework.Plzwrk.Base +import Web.Framework.Plzwrk.Browserful + +data DomifiedAttributes jsval = MkDomifiedAttributes + { _d_style :: HM.HashMap String String + , _d_class :: S.Set String + , _d_simple :: HM.HashMap String String + , _d_handlers :: HM.HashMap String jsval + } + +data DomifiedNode jsval = DomifiedElement + { _dom_tag :: String + , _dom_attr :: (DomifiedAttributes jsval) + , _dom_kids :: [DomifiedNode jsval] + , _dom_ptr :: jsval + } + | DomifiedTextNode String jsval + +data OldStuff state jsval = OldStuff { + _oldState :: state, + _oldDom :: Maybe (DomifiedNode jsval) +} + +---------- reader functions + + + +freeAttrFunctions + :: DomifiedAttributes jsval -> ReaderT (Browserful jsval) IO () +freeAttrFunctions (MkDomifiedAttributes _ _ _ __d_handlers) = do + _freeCallback <- asks freeCallback + liftIO $ void (mapM _freeCallback (HM.elems __d_handlers)) + +freeFunctions :: DomifiedNode jsval -> ReaderT (Browserful jsval) IO () +freeFunctions (DomifiedElement _ b c _) = do + freeAttrFunctions b + mapM_ freeFunctions c +freeFunctions _ = pure () + +nodesEq + :: String + -> String + -> DomifiedAttributes jsval + -> Attributes state jsval + -> Bool +nodesEq t0 t1 (MkDomifiedAttributes __d_style __d_class __d_simple _) (MkAttributes __style __class __simple _) + = (t0 == t1) + && (__d_style == __style) + && (__d_class == __class) + && (__d_simple == __simple) + +padr :: Int -> a -> [a] -> [a] +padr i v l = if (length l >= i) then l else padr i v (l ++ [v]) + +reconcile + :: IORef (OldStuff state jsval) + -> (state -> Node state jsval) + -> jsval + -> jsval + -> Maybe (DomifiedNode jsval) + -> Maybe (HydratedNode state jsval) + -> ReaderT + (Browserful jsval) + IO + (Maybe (DomifiedNode jsval)) +reconcile refToOldStuff domCreationF parentNode topLevelNode (Just (DomifiedElement currentTag currentAttributes currentChildren currentNode)) (Just maybeNewNode@(HydratedElement maybeNewTag maybeNewAttributes maybeNewChildren)) + = if (nodesEq currentTag maybeNewTag currentAttributes maybeNewAttributes) + then + (do +-- the tags and attributes are equal + + + let maxlen = max (length maybeNewChildren) (length currentChildren) + newChildren <- sequence $ getZipList + ( (reconcile refToOldStuff domCreationF currentNode topLevelNode) + <$> (ZipList (padr maxlen Nothing (fmap Just currentChildren))) + <*> (ZipList (padr maxlen Nothing (fmap Just maybeNewChildren))) + ) + -- make new attributes to set event handlers + + + currentAttributes <- hydratedAttrsToDomifiedAttrs refToOldStuff + domCreationF + parentNode + maybeNewAttributes + removeEventHandlers currentNode currentAttributes + setEventHandlers currentNode currentAttributes + return $ Just + (DomifiedElement currentTag + currentAttributes + (catMaybes newChildren) + currentNode + ) + ) + else + (do + res <- domify refToOldStuff + domCreationF + parentNode + topLevelNode + (Just currentNode) + maybeNewNode + return $ Just res + ) +reconcile refToOldStuff domCreationF parentNode topLevelNode (Just currentDomifiedString@(DomifiedTextNode currentString currentNode)) (Just maybeNewNode@(HydratedTextNode maybeNewString)) + = if (currentString == maybeNewString) + then pure (Just currentDomifiedString) + else + (do + res <- domify refToOldStuff + domCreationF + parentNode + topLevelNode + (Just currentNode) + maybeNewNode + return $ Just res + ) +reconcile refToOldStuff domCreationF parentNode topLevelNode (Just (DomifiedElement _ _ _ currentNode)) (Just maybeNewNode@(HydratedTextNode _)) + = do + res <- domify refToOldStuff + domCreationF + parentNode + topLevelNode + (Just currentNode) + maybeNewNode + return $ Just res +reconcile refToOldStuff domCreationF parentNode topLevelNode (Just (DomifiedTextNode _ currentNode)) (Just maybeNewNode@(HydratedElement _ _ _)) + = do + res <- domify refToOldStuff + domCreationF + parentNode + topLevelNode + (Just currentNode) + maybeNewNode + return $ Just res +reconcile refToOldStuff domCreationF parentNode topLevelNode Nothing (Just maybeNewNode) + = do + res <- domify refToOldStuff + domCreationF + parentNode + topLevelNode + Nothing + maybeNewNode + return $ Just res +reconcile refToOldStuff domCreationF parentNode _ (Just (DomifiedElement _ _ _ currentNode)) Nothing + = do + _removeChild <- asks removeChild + liftIO $ _removeChild parentNode currentNode + return Nothing +reconcile refToOldStuff domCreationF parentNode _ (Just (DomifiedTextNode _ currentNode)) Nothing + = do + _removeChild <- asks removeChild + liftIO $ _removeChild parentNode currentNode + return Nothing +reconcile _ _ _ _ _ _ = error "Inconsistent state" + +cbMaker + :: IORef (OldStuff state jsval) + -> (state -> Node state jsval) + -> jsval + -> (jsval -> state -> IO state) + -> Browserful jsval + -> jsval + -> IO () +cbMaker refToOldStuff domCreationF topLevelNode eventToState env event = do + oldStuff <- readIORef refToOldStuff + let oldDom = _oldDom oldStuff + let oldState = _oldState oldStuff + newState <- eventToState event oldState + let newHydratedDom = hydrate newState domCreationF + newDom <- runReaderT + (reconcile refToOldStuff + domCreationF + topLevelNode + topLevelNode + oldDom + (Just newHydratedDom) + ) + env + maybe (pure ()) (\x -> runReaderT (freeFunctions x) env) oldDom + writeIORef refToOldStuff (OldStuff newState newDom) + +eventable + :: IORef (OldStuff state jsval) + -> (state -> Node state jsval) + -> jsval + -> (jsval -> state -> IO state) + -> ReaderT (Browserful jsval) IO jsval +eventable refToOldStuff domCreationF topLevelNode eventToState = do + _makeHaskellCallback <- asks makeHaskellCallback + env <- ask + liftIO $ _makeHaskellCallback + (cbMaker refToOldStuff domCreationF topLevelNode eventToState env) + +hydratedAttrsToDomifiedAttrs + :: IORef (OldStuff state jsval) + -> (state -> Node state jsval) + -> jsval + -> Attributes state jsval + -> ReaderT (Browserful jsval) IO (DomifiedAttributes jsval) +hydratedAttrsToDomifiedAttrs refToOldStuff domCreationF topLevelNode (MkAttributes __style __class __simple __handlers) + = do + handlers <- mapM + (\(k, v) -> do + func <- eventable refToOldStuff domCreationF topLevelNode v + return $ (k, func) + ) + (HM.toList __handlers) + return + $ MkDomifiedAttributes __style __class __simple (HM.fromList handlers) + +setAtts :: jsval -> DomifiedAttributes jsval -> ReaderT (Browserful jsval) IO () +setAtts currentNode domifiedAttributes@(MkDomifiedAttributes __style __class __simple _) + = do + _setAttribute <- asks setAttribute + liftIO $ if (HM.null __style) + then (pure ()) + else (_setAttribute currentNode "style") . cssToStyle $ __style + liftIO $ if (S.null __class) + then (pure ()) + else ((_setAttribute currentNode "class") . unwords . S.toList) $ __class + liftIO $ mapM_ (\x -> _setAttribute currentNode (fst x) (snd x)) + (HM.toList __simple) + setEventHandlers currentNode domifiedAttributes + +handleOnlyEventListeners + :: (jsval -> String -> jsval -> IO ()) + -> jsval + -> DomifiedAttributes jsval + -> IO () +handleOnlyEventListeners eventListenerHandlerF currentNode domifiedAttributes = + void $ mapM (\(k, v) -> eventListenerHandlerF currentNode k v) + (HM.toList . _d_handlers $ domifiedAttributes) + +setEventHandlers + :: jsval -> DomifiedAttributes jsval -> ReaderT (Browserful jsval) IO () +setEventHandlers currentNode domifiedAttributes = do + _addEventListener <- asks addEventListener + liftIO $ handleOnlyEventListeners _addEventListener + currentNode + domifiedAttributes + +removeEventHandlers + :: jsval -> DomifiedAttributes jsval -> ReaderT (Browserful jsval) IO () +removeEventHandlers currentNode domifiedAttributes = do + _removeEventListener <- asks removeEventListener + liftIO $ handleOnlyEventListeners _removeEventListener + currentNode + domifiedAttributes + +domify + :: IORef (OldStuff state jsval) + -> (state -> Node state jsval) + -> jsval + -> jsval + -> Maybe jsval + -> HydratedNode state jsval + -> ReaderT (Browserful jsval) IO (DomifiedNode jsval) +domify refToOldStuff domCreationF parentNode topLevelNode replacing (HydratedElement tag attrs children) + = do + _createElement <- asks createElement + _appendChild <- asks appendChild + _insertBefore <- asks insertBefore + _removeChild <- asks removeChild + newNode <- liftIO $ _createElement tag + newAttributes <- hydratedAttrsToDomifiedAttrs refToOldStuff + domCreationF + topLevelNode + attrs + setAtts newNode newAttributes + newChildren <- mapM + (domify refToOldStuff domCreationF newNode topLevelNode Nothing) + children + maybe + (liftIO $ _appendChild parentNode newNode) + (\x -> do + liftIO $ _insertBefore parentNode newNode x + liftIO $ _removeChild parentNode x + ) + replacing + liftIO $ return (DomifiedElement tag newAttributes newChildren newNode) +domify _ _ parentNode topLevelNode replacing (HydratedTextNode text) = do + _createElement <- asks createElement + _appendChild <- asks appendChild + _insertBefore <- asks insertBefore + _removeChild <- asks removeChild + _createTextNode <- asks createTextNode + newTextNode <- liftIO $ _createTextNode text + maybe + (liftIO $ _appendChild parentNode newTextNode) + (\x -> do + liftIO $ _insertBefore parentNode newTextNode x + liftIO $ _removeChild parentNode x + ) + replacing + liftIO $ return (DomifiedTextNode text newTextNode) + +plzwrk + :: (state -> Node state jsval) -> state -> Browserful jsval -> String -> IO () +plzwrk domF state env nodeId = do + refToOldStuff <- newIORef (OldStuff state Nothing) + parentNode <- (getElementById env) nodeId + newDom <- maybe + (error $ ("Cannot find node with id " <> nodeId)) + (\x -> runReaderT + (reconcile refToOldStuff domF x x Nothing (Just $ hydrate state domF)) + env + ) + parentNode + writeIORef refToOldStuff (OldStuff state newDom) + +plzwrk' :: (state -> Node state jsval) -> state -> Browserful jsval -> IO () +plzwrk' domF state env = do + refToOldStuff <- newIORef (OldStuff state Nothing) + parentNode <- (getBody env) + newDom <- runReaderT + (reconcile refToOldStuff + domF + parentNode + parentNode + Nothing + (Just $ hydrate state domF) + ) + env + writeIORef refToOldStuff (OldStuff state newDom) + +plzwrk'_ :: (Int -> Node Int jsval) -> Browserful jsval -> IO () +plzwrk'_ domF env = plzwrk' domF 0 env
+ src/Web/Framework/Plzwrk/MockJSVal.hs view
@@ -0,0 +1,483 @@+module Web.Framework.Plzwrk.MockJSVal + ( MockJSVal(..) + , makeMockBrowser + , defaultInternalBrowser + , makeMockBrowserWithContext + ) +where + +import Data.Aeson ( FromJSON ) +import Data.HashMap.Strict hiding ( foldr + , null + ) +import Data.IORef +import Data.List ( elemIndex ) +import Prelude hiding ( lookup ) +import System.Random +import Web.Framework.Plzwrk.Base +import Web.Framework.Plzwrk.Browserful + +data LogEvent = ListenerReceived String Int + | AddedAsListenerTo Int + | AttributeReceived String String + | ChildReceived Int + | AddedAsChildTo Int + | RemovedNode Int + | RemovedAsNodeFrom Int + | RemovedListener String Int + | RemovedAsListenerFrom Int + | CreatedElement Int + | CreatedTextNode Int + | InsertedChildBefore Int Int + | InsertedAsChildBefore Int Int + | ElementAddedBefore Int + | GotElementById + | MadeCallback Int + | FreeCallback Int + deriving (Show, Eq) + + +data MockAttributes = MockAttributes + { _d_attrs :: HashMap String String + , _d_events :: HashMap String MockJSVal + } + deriving Show + +data MockJSVal = MockJSElement Int String MockAttributes [MockJSVal] [LogEvent] + | MockJSTextNode Int String [LogEvent] + | MockJSFunction Int (MockJSVal -> IO ()) [LogEvent] + | MockJSObject Int (HashMap String MockJSVal) [LogEvent] + | MockJSString Int String [LogEvent] + | MockJSNumber Int Double [LogEvent] + | MockJSArray Int [MockJSVal] [LogEvent] + | MockMouseEvent Int + +instance Show MockJSVal where + show (MockJSElement a b c d e) = + show a + <> " " + <> " " + <> show b + <> " " + <> show c + <> " " + <> show d + <> " " + <> show e + show (MockJSTextNode a b c) = show a <> " " <> show b <> " " <> show c + show (MockJSFunction a _ c) = show a <> " " <> show c + show (MockJSObject a b c) = show a <> " " <> show b <> " " <> show c + show (MockJSString a b c) = show a <> " " <> show b <> " " <> show c + show (MockJSNumber a b c) = show a <> " " <> show b <> " " <> show c + show (MockJSArray a b c) = show a <> " " <> show b <> " " <> show c + show (MockMouseEvent a ) = show a + +_withNewLog :: MockJSVal -> [LogEvent] -> MockJSVal +_withNewLog (MockJSElement a b c d _) log = MockJSElement a b c d log +_withNewLog (MockJSTextNode a b _ ) log = MockJSTextNode a b log +_withNewLog (MockJSFunction a b _ ) log = MockJSFunction a b log +_withNewLog (MockJSObject a b _ ) log = MockJSObject a b log +_withNewLog (MockJSString a b _ ) log = MockJSString a b log +_withNewLog (MockJSNumber a b _ ) log = MockJSNumber a b log +_withNewLog (MockJSArray a b _ ) log = MockJSArray a b log + +_withNewAttrs :: MockJSVal -> MockAttributes -> MockJSVal +_withNewAttrs (MockJSElement n tg _ chlds log) newat = + MockJSElement n tg newat chlds log +_withNewAttrs a _ = a + +_withNewKids :: MockJSVal -> [MockJSVal] -> MockJSVal +_withNewKids (MockJSElement n tg attrs _ log) newKids = + MockJSElement n tg attrs newKids log +_withNewKids a _ = a + +_ptr :: MockJSVal -> Int +_ptr (MockJSElement a _ _ _ _) = a +_ptr (MockJSTextNode a _ _ ) = a +_ptr (MockJSFunction a _ _ ) = a +_ptr (MockJSObject a _ _ ) = a +_ptr (MockJSString a _ _ ) = a +_ptr (MockJSNumber a _ _ ) = a +_ptr (MockJSArray a _ _ ) = a + +_addEventListener + :: MockJSVal + -> String + -> MockJSVal + -> IO (MockAttributes, [LogEvent], [LogEvent]) +_addEventListener (MockJSElement n _ (MockAttributes atts lstns) _ logn) evt fn@(MockJSFunction m _ logm) + = pure + $ ( MockAttributes atts $ insert evt fn lstns + , logn <> [ListenerReceived evt m] + , logm <> [AddedAsListenerTo n] + ) +_addEventListener _ _ _ = error "Can only add event listener to element" + +_setAttribute :: MockJSVal -> String -> String -> IO (MockAttributes, [LogEvent]) +_setAttribute (MockJSElement n _ (MockAttributes atts lstns) _ logn) nm attr = + pure + $ ( MockAttributes (insert nm attr atts) lstns + , logn <> [AttributeReceived nm attr] + ) +_setAttribute _ _ _ = error "Can only add event listener to element" + +_appendChild + :: MockJSVal -> MockJSVal -> IO ([MockJSVal], [LogEvent], [LogEvent]) +_appendChild (MockJSElement n _ _ kids logn) kid@(MockJSElement m _ _ _ logm) = + pure $ (kids <> [kid], logn <> [ChildReceived m], logm <> [AddedAsChildTo n]) +_appendChild (MockJSElement n _ _ kids logn) kid@(MockJSTextNode m _ logm) = + pure $ (kids <> [kid], logn <> [ChildReceived m], logm <> [AddedAsChildTo n]) +_appendChild _ _ = error "Can only append element to element" + +__removeChild + :: Int + -> [MockJSVal] + -> [LogEvent] + -> MockJSVal + -> Int + -> [LogEvent] + -> IO ([MockJSVal], [LogEvent], [LogEvent]) +__removeChild n kids logn kid m logm = maybe + (error ("Existing item " <> show m <> " not child of " <> show n)) + (\x -> + pure + $ ( take x kids <> drop (x + 1) kids + , logn <> [RemovedNode m] + , logm <> [RemovedAsNodeFrom n] + ) + ) + (elemIndex (_ptr kid) (fmap _ptr kids)) + +_removeChild + :: MockJSVal -> MockJSVal -> IO ([MockJSVal], [LogEvent], [LogEvent]) +_removeChild (MockJSElement n _ _ kids logn) kid@(MockJSElement m _ _ _ logm) = + __removeChild n kids logn kid m logm +_removeChild (MockJSElement n _ _ kids logn) kid@(MockJSTextNode m _ logm) = + __removeChild n kids logn kid m logm +_removeChild _ _ = error "Can only remove element from element" + +_removeEventListener + :: MockJSVal + -> String + -> MockJSVal + -> IO (MockAttributes, [LogEvent], [LogEvent]) +_removeEventListener (MockJSElement n _ (MockAttributes atts lstns) _ logn) evt fn@(MockJSFunction m _ logm) + = maybe + (error ("Listener " <> show m <> " not child of " <> show n)) + (\x -> + pure + $ ( MockAttributes atts $ delete evt lstns + , logn <> [RemovedListener evt m] + , logm <> [RemovedAsListenerFrom n] + ) + ) + (lookup evt lstns) +_removeEventListener _ _ _ = error "Can only add event listener to element" + +_insertBeforeInternal + :: Int + -> [MockJSVal] + -> [LogEvent] + -> MockJSVal + -> Int + -> [LogEvent] + -> MockJSVal + -> Int + -> [LogEvent] + -> IO + ( [MockJSVal] + , [LogEvent] + , [LogEvent] + , [LogEvent] + ) +_insertBeforeInternal n kids logn newI m logm existingI l logl = maybe + (error ("Existing item " <> show l <> " not child of " <> show n)) + (\x -> + pure + $ ( take x kids <> [newI] <> drop x kids + , logn <> [InsertedChildBefore m l] + , logm <> [InsertedAsChildBefore n l] + , logl <> [ElementAddedBefore m] + ) + ) + (elemIndex (_ptr existingI) (fmap _ptr kids)) + + +_insertBefore + :: MockJSVal + -> MockJSVal + -> MockJSVal + -> IO ([MockJSVal], [LogEvent], [LogEvent], [LogEvent]) +_insertBefore (MockJSElement n _ _ kids logn) newI@(MockJSElement m _ _ _ logm) existingI@(MockJSElement l _ _ _ logl) + = _insertBeforeInternal n kids logn newI m logm existingI l logl +_insertBefore (MockJSElement n _ _ kids logn) newI@(MockJSTextNode m _ logm) existingI@(MockJSElement l _ _ _ logl) + = _insertBeforeInternal n kids logn newI m logm existingI l logl +_insertBefore (MockJSElement n _ _ kids logn) newI@(MockJSElement m _ _ _ logm) existingI@(MockJSTextNode l _ logl) + = _insertBeforeInternal n kids logn newI m logm existingI l logl +_insertBefore (MockJSElement n _ _ kids logn) newI@(MockJSTextNode m _ logm) existingI@(MockJSTextNode l _ logl) + = _insertBeforeInternal n kids logn newI m logm existingI l logl +_insertBefore _ _ _ = error "Can only append element to element" + +_getTag :: MockJSVal -> IO String +_getTag (MockJSElement _ tag _ _ _) = return tag +_getTag _ = error "Can only get tag of element" + +_textContent :: MockJSVal -> IO String +_textContent (MockJSTextNode _ txt _) = return txt +_textContent _ = error "Can only get text content of text node" + + +_getChildren :: MockJSVal -> IO [Int] +_getChildren (MockJSElement _ _ _ kids _) = return $ fmap _ptr kids +_getChildren _ = error "Can only get children of element" + +_freeCallback :: MockJSVal -> IO [LogEvent] +_freeCallback (MockJSFunction n _ log) = pure (log <> [FreeCallback n]) +_freeCallback _ = error "Can only free function" + +dummyClick :: MockJSVal -> IO () +-- todo give real number + +dummyClick (MockJSFunction _ f _) = f $ MockMouseEvent (-1) + + +_click :: MockJSVal -> IO () +_click (MockJSElement _ _ (MockAttributes _ evts) _ _) = do + let oc = lookup "click" evts + maybe (pure ()) (\x -> dummyClick x) oc + +_click _ = error "Can only free function" + + +-------------- + + +data MockBrowserInternal = MockBrowserInternal + { unBrowser :: HashMap Int MockJSVal + , unCtr :: Int + } + deriving Show + +look :: IORef MockBrowserInternal -> Int -> IO MockJSVal +look env elt = do + r <- readIORef env + let bz = unBrowser r + maybe (error $ "Cannot find object pointer in env: " <> (show elt)) + (\x -> return x) + (lookup elt bz) + +incr :: IORef MockBrowserInternal -> IO Int +incr env = do + r <- readIORef env + let ctr = unCtr r + writeIORef env $ r { unCtr = ctr + 1 } + return ctr + + +wrt :: IORef MockBrowserInternal -> Int -> MockJSVal -> IO () +wrt env elt v = do + r <- readIORef env + let bz = unBrowser r + writeIORef env $ r { unBrowser = insert elt v bz } + +_'addEventListener :: IORef MockBrowserInternal -> Int -> String -> Int -> IO () +_'addEventListener env elt evt fn = do + _elt <- look env elt + _fn <- look env fn + (newAttrs, newLogElt, newLogFn) <- _addEventListener _elt evt _fn + wrt env elt $ _withNewLog (_withNewAttrs _elt newAttrs) newLogElt + wrt env fn $ _withNewLog _fn newLogFn + +_'appendChild :: IORef MockBrowserInternal -> Int -> Int -> IO () +_'appendChild env parent kid = do + _parent <- look env parent + _kid <- look env kid + (newKids, newLogParent, newLogKid) <- _appendChild _parent _kid + wrt env parent $ _withNewLog (_withNewKids _parent newKids) newLogParent + wrt env kid $ _withNewLog _kid newLogKid + +_'createElement :: IORef MockBrowserInternal -> String -> IO Int +_'createElement env tg = do + i <- incr env + let elt = + MockJSElement i tg (MockAttributes empty empty) [] [CreatedElement i] + wrt env i elt + return i + +_'random01 :: IORef MockBrowserInternal -> IO Double +_'random01 _ = pure 0.5 + +_'consoleLog :: IORef MockBrowserInternal -> String -> IO () +_'consoleLog _ txt = print txt + +_'consoleLog' :: IORef MockBrowserInternal -> Int -> IO () +_'consoleLog' _ v = print (show v) + + +_'createTextNode :: IORef MockBrowserInternal -> String -> IO Int +_'createTextNode env txt = do + i <- incr env + let elt = MockJSTextNode i txt [CreatedTextNode i] + wrt env i elt + return i + +_'getString :: IORef MockBrowserInternal -> Int -> String -> IO (Maybe String) +_'getString env _ _ = pure Nothing -- not implemented yet + +_'getBool :: IORef MockBrowserInternal -> Int -> String -> IO (Maybe Bool) +_'getBool env _ _ = pure Nothing -- not implemented yet + +_'getInt :: IORef MockBrowserInternal -> Int -> String -> IO (Maybe Int) +_'getInt env _ _ = pure Nothing -- not implemented yet + +_'getDouble :: IORef MockBrowserInternal -> Int -> String -> IO (Maybe Double) +_'getDouble env _ _ = pure Nothing -- not implemented yet + +_'getOpaque :: IORef MockBrowserInternal -> Int -> String -> IO (Maybe Int) +_'getOpaque env _ _ = pure Nothing -- not implemented yet + + +_'invokeOn :: IORef MockBrowserInternal -> Int -> String -> IO () +_'invokeOn env _ _ = pure () -- not implemented yet + + +_'getTag :: IORef MockBrowserInternal -> Int -> IO String +_'getTag env elt = do + _elt <- look env elt + _getTag _elt + +_'getChildren :: IORef MockBrowserInternal -> Int -> IO [Int] +_'getChildren env elt = do + _elt <- look env elt + _getChildren _elt + +_'textContent :: IORef MockBrowserInternal -> Int -> IO String +_'textContent env elt = do + _elt <- look env elt + _textContent _elt + +_'freeCallback :: IORef MockBrowserInternal -> Int -> IO () +_'freeCallback env fn = do + _fn <- look env fn + newLog <- _freeCallback _fn + wrt env fn $ _withNewLog _fn newLog + +_'click :: IORef MockBrowserInternal -> Int -> IO () +_'click env elt = do + _elt <- look env elt + _click _elt + +idEq :: String -> MockJSVal -> Bool +idEq txt (MockJSElement _ _ (MockAttributes atts _) _ _) = + Just txt == (lookup "id" atts) +idEq _ _ = False + +_'getBody :: IORef MockBrowserInternal -> IO Int +_'getBody ref = do + mb <- readIORef ref + let browser = unBrowser mb + pt <- maybe (error "No body.") (\x -> pure $ _ptr x) $ lookup 0 browser + return pt + +_'getHead :: IORef MockBrowserInternal -> IO Int +_'getHead ref = pure (-1) -- need to implement in mock? + +_getElementByIdInternal :: MockJSVal -> String -> [Int] +_getElementByIdInternal jsv@(MockJSElement _ _ _ ch _) txt = if (idEq txt jsv) + then [_ptr jsv] + else (foldr (++) [] $ fmap (\x -> _getElementByIdInternal x txt) ch) +_getElementByIdInternal _ _ = [] + +_'getElementById :: IORef MockBrowserInternal -> String -> IO (Maybe Int) +_'getElementById env txt = do + body <- _'getBody env + _body <- look env body + let elts = _getElementByIdInternal _body txt + return $ if (null elts) then (Nothing) else (Just $ head elts) + +_'insertBefore :: IORef MockBrowserInternal -> Int -> Int -> Int -> IO () +_'insertBefore env parent newItem existingItem = do + _parent <- look env parent + _newItem <- look env newItem + _existingItem <- look env existingItem + (newKids, newLogParent, newLogNewItem, newLogExistingItem) <- _insertBefore + _parent + _newItem + _existingItem + wrt env parent $ _withNewLog (_withNewKids _parent newKids) newLogParent + wrt env newItem $ _withNewLog _newItem newLogNewItem + wrt env existingItem $ _withNewLog _existingItem newLogExistingItem + +_'makeHaskellCallback :: IORef MockBrowserInternal -> (Int -> IO ()) -> IO Int +_'makeHaskellCallback env cb = do + i <- incr env + let elt = MockJSFunction i (\x -> cb $ _ptr x) [MadeCallback i] + wrt env i elt + return i + +_'removeChild :: IORef MockBrowserInternal -> Int -> Int -> IO () +_'removeChild env parent kid = do + _parent <- look env parent + _kid <- look env kid + (newKids, newLogParent, newLogKid) <- _removeChild _parent _kid + wrt env parent $ _withNewLog (_withNewKids _parent newKids) newLogParent + wrt env kid $ _withNewLog _kid newLogKid + +_'removeEventListener + :: IORef MockBrowserInternal -> Int -> String -> Int -> IO () +_'removeEventListener env elt evt fn = do + _elt <- look env elt + _fn <- look env fn + (newAttrs, newLogElt, newLogFn) <- _removeEventListener _elt evt _fn + wrt env elt $ _withNewLog (_withNewAttrs _elt newAttrs) newLogElt + wrt env fn $ _withNewLog _fn newLogFn + +_'setAttribute :: IORef MockBrowserInternal -> Int -> String -> String -> IO () +_'setAttribute env elt nm attr = do + _elt <- look env elt + (newAttrs, newLog) <- _setAttribute _elt nm attr + wrt env elt $ _withNewLog (_withNewAttrs _elt newAttrs) newLog + +makeMockBrowserWithContext :: IORef MockBrowserInternal -> IO (Browserful Int) +makeMockBrowserWithContext r = return Browserful + { addEventListener = _'addEventListener r + , appendChild = _'appendChild r + , consoleLog = _'consoleLog r + , consoleLog' = _'consoleLog' r + , click = _'click r + , createElement = _'createElement r + , createTextNode = _'createTextNode r + , freeCallback = _'freeCallback r + , getBody = _'getBody r + , getBool = _'getBool r + , getChildren = _'getChildren r + , getDouble = _'getDouble r + , getElementById = _'getElementById r + , getHead = _'getHead r + , getInt = _'getInt r + , getOpaque = _'getOpaque r + , getString = _'getString r + , getTag = _'getTag r + , insertBefore = _'insertBefore r + , invokeOn = _'invokeOn r + , makeHaskellCallback = _'makeHaskellCallback r + , random01 = _'random01 r + , removeChild = _'removeChild r + , removeEventListener = _'removeEventListener r + , setAttribute = _'setAttribute r + , textContent = _'textContent r + } + +defaultInternalBrowser :: IO (IORef MockBrowserInternal) +defaultInternalBrowser = do + let body = MockJSElement 0 + "body" + (MockAttributes empty empty) + [] + [CreatedElement 0] + newIORef MockBrowserInternal { unBrowser = singleton 0 body, unCtr = 1 } + +makeMockBrowser :: IO (Browserful Int) +makeMockBrowser = do + rf <- defaultInternalBrowser + makeMockBrowserWithContext rf
+ src/Web/Framework/Plzwrk/Tag.hs view
@@ -0,0 +1,3051 @@+{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE OverloadedStrings #-} + +{-| +Module : Web.Framework.Plzwrk.Tag +Description : Base functions for plzwrk +Copyright : (c) Mike Solomon 2020 +License : GPL-3 +Maintainer : mike@meeshkan.com +Stability : experimental +Portability : POSIX, Windows + +This module contains tags for web development. It has stuff like +@img@, @div@, @br@, @span@, etc. Because the module is huge, we +recommend doing selective import of the tags you need. + +There are three conventions for tag naming: + +* tags that accept children, like @div@ and @p@ +* tags that do not have children but could have attributes, like @img@ +* tags that have no attributes and no children, like @br@ + +For tags that can have children, the following six tags are exported +(we'll use @div@ as an example, but the same works for @span@, @section@ etc): + +* @div@ : A div that does not need to be hydrated with a state. +* @div'@ : A div that is hydrated with a state. +* @div_@ : A div with no attributes that does not need to be hydrated with a state. +* @div'_@ : A div with no attributes that is hydrated with a state. +* @div__@ : A div that only contains text that does not need to be hydrated with a state. +* @div'__@ : A div that only contains text that is hydrated with a state. + +For tags that do not have children, the following six tags are exported +(we'll use @img@ as an example): + +* @img@ : A div that does not need to be hydrated with a state. +* @img'@ : A div that is hydrated with a state. +* @img_@ : A div with no attributes that does not need to be hydrated with a state. +* @img'_@ : A div with no attributes that is hydrated with a state. + +For tags like br, there is only one export, namely @br@. + +Here are some gotchyas to bear in mind: + +* The HTML @data@ tag is renamed to @_data@ here. +* Due to the volume of tags in this module, some of + them follow an incorrect convention, ie accepting children + when they shouldn't be able to. If you spot one, please + make a PR. +-} +module Web.Framework.Plzwrk.Tag( +a +, a' +, a_ +, a'_ +, a__ +, a'__ +, abbr +, abbr' +, abbr_ +, abbr'_ +, abbr__ +, abbr'__ +, acronym +, acronym' +, acronym_ +, acronym'_ +, acronym__ +, acronym'__ +, address +, address' +, address_ +, address'_ +, address__ +, address'__ +, applet +, applet' +, applet_ +, applet'_ +, applet__ +, applet'__ +, area +, area' +, area_ +, area'_ +, area__ +, area'__ +, article +, article' +, article_ +, article'_ +, article__ +, article'__ +, aside +, aside' +, aside_ +, aside'_ +, aside__ +, aside'__ +, audio +, audio' +, audio_ +, audio'_ +, audio__ +, audio'__ +, b +, b' +, b_ +, b'_ +, b__ +, b'__ +, base +, base' +, base_ +, base'_ +, base__ +, base'__ +, basefont +, basefont' +, basefont_ +, basefont'_ +, basefont__ +, basefont'__ +, bdi +, bdi' +, bdi_ +, bdi'_ +, bdi__ +, bdi'__ +, bdo +, bdo' +, bdo_ +, bdo'_ +, bdo__ +, bdo'__ +, big +, big' +, big_ +, big'_ +, big__ +, big'__ +, blockquote +, blockquote' +, blockquote_ +, blockquote'_ +, blockquote__ +, blockquote'__ +, body +, body' +, body_ +, body'_ +, body__ +, body'__ +, br +, button +, button' +, button_ +, button'_ +, button__ +, button'__ +, canvas +, canvas' +, canvas_ +, canvas'_ +, canvas__ +, canvas'__ +, caption +, caption' +, caption_ +, caption'_ +, caption__ +, caption'__ +, center +, center' +, center_ +, center'_ +, center__ +, center'__ +, cite +, cite' +, cite_ +, cite'_ +, cite__ +, cite'__ +, code +, code' +, code_ +, code'_ +, code__ +, code'__ +, col +, col' +, col_ +, col'_ +, col__ +, col'__ +, colgroup +, colgroup' +, colgroup_ +, colgroup'_ +, colgroup__ +, colgroup'__ +, _data +, _data' +, _data_ +, _data'_ +, _data__ +, _data'__ +, _datalist +, _datalist' +, _datalist_ +, _datalist'_ +, _datalist__ +, _datalist'__ +, dd +, dd' +, dd_ +, dd'_ +, dd__ +, dd'__ +, del +, del' +, del_ +, del'_ +, del__ +, del'__ +, details +, details' +, details_ +, details'_ +, details__ +, details'__ +, dfn +, dfn' +, dfn_ +, dfn'_ +, dfn__ +, dfn'__ +, dialog +, dialog' +, dialog_ +, dialog'_ +, dialog__ +, dialog'__ +, dir +, dir' +, dir_ +, dir'_ +, dir__ +, dir'__ +, div +, div' +, div_ +, div'_ +, div__ +, div'__ +, dl +, dl' +, dl_ +, dl'_ +, dl__ +, dl'__ +, dt +, dt' +, dt_ +, dt'_ +, dt__ +, dt'__ +, em +, em' +, em_ +, em'_ +, em__ +, em'__ +, embed +, embed' +, embed_ +, embed'_ +, embed__ +, embed'__ +, fieldset +, fieldset' +, fieldset_ +, fieldset'_ +, fieldset__ +, fieldset'__ +, figcaption +, figcaption' +, figcaption_ +, figcaption'_ +, figcaption__ +, figcaption'__ +, figure +, figure' +, figure_ +, figure'_ +, figure__ +, figure'__ +, font +, font' +, font_ +, font'_ +, font__ +, font'__ +, footer +, footer' +, footer_ +, footer'_ +, footer__ +, footer'__ +, form +, form' +, form_ +, form'_ +, form__ +, form'__ +, frame +, frame' +, frame_ +, frame'_ +, frame__ +, frame'__ +, frameset +, frameset' +, frameset_ +, frameset'_ +, frameset__ +, frameset'__ +, h1 +, h1' +, h1_ +, h1'_ +, h1__ +, h1'__ +, h2 +, h2' +, h2_ +, h2'_ +, h2__ +, h2'__ +, h3 +, h3' +, h3_ +, h3'_ +, h3__ +, h3'__ +, h4 +, h4' +, h4_ +, h4'_ +, h4__ +, h4'__ +, h5 +, h5' +, h5_ +, h5'_ +, h5__ +, h5'__ +, h6 +, h6' +, h6_ +, h6'_ +, h6__ +, h6'__ +, head +, head' +, head_ +, head'_ +, head__ +, head'__ +, header +, header' +, header_ +, header'_ +, header__ +, header'__ +, hr +, html +, html' +, html_ +, html'_ +, html__ +, html'__ +, i +, i' +, i_ +, i'_ +, i__ +, i'__ +, iframe +, iframe' +, iframe_ +, iframe'_ +, iframe__ +, iframe'__ +, img +, img' +, img_ +, img'_ +, input +, input' +, input_ +, input'_ +, input__ +, input'__ +, ins +, ins' +, ins_ +, ins'_ +, ins__ +, ins'__ +, kbd +, kbd' +, kbd_ +, kbd'_ +, kbd__ +, kbd'__ +, label +, label' +, label_ +, label'_ +, label__ +, label'__ +, legend +, legend' +, legend_ +, legend'_ +, legend__ +, legend'__ +, li +, li' +, li_ +, li'_ +, li__ +, li'__ +, link +, link' +, link_ +, link'_ +, link__ +, link'__ +, main +, main' +, main_ +, main'_ +, main__ +, main'__ +, map +, map' +, map_ +, map'_ +, map__ +, map'__ +, mark +, mark' +, mark_ +, mark'_ +, mark__ +, mark'__ +, meta +, meta' +, meta_ +, meta'_ +, meta__ +, meta'__ +, meter +, meter' +, meter_ +, meter'_ +, meter__ +, meter'__ +, nav +, nav' +, nav_ +, nav'_ +, nav__ +, nav'__ +, noframes +, noframes' +, noframes_ +, noframes'_ +, noframes__ +, noframes'__ +, noscript +, noscript' +, noscript_ +, noscript'_ +, noscript__ +, noscript'__ +, object +, object' +, object_ +, object'_ +, object__ +, object'__ +, ol +, ol' +, ol_ +, ol'_ +, ol__ +, ol'__ +, optgroup +, optgroup' +, optgroup_ +, optgroup'_ +, optgroup__ +, optgroup'__ +, option +, option' +, option_ +, option'_ +, option__ +, option'__ +, output +, output' +, output_ +, output'_ +, output__ +, output'__ +, p +, p' +, p_ +, p'_ +, p__ +, p'__ +, param +, param' +, param_ +, param'_ +, param__ +, param'__ +, picture +, picture' +, picture_ +, picture'_ +, picture__ +, picture'__ +, pre +, pre' +, pre_ +, pre'_ +, pre__ +, pre'__ +, progress +, progress' +, progress_ +, progress'_ +, progress__ +, progress'__ +, q +, q' +, q_ +, q'_ +, q__ +, q'__ +, rp +, rp' +, rp_ +, rp'_ +, rp__ +, rp'__ +, rt +, rt' +, rt_ +, rt'_ +, rt__ +, rt'__ +, ruby +, ruby' +, ruby_ +, ruby'_ +, ruby__ +, ruby'__ +, s +, s' +, s_ +, s'_ +, s__ +, s'__ +, samp +, samp' +, samp_ +, samp'_ +, samp__ +, samp'__ +, script +, script' +, script_ +, script'_ +, script__ +, script'__ +, section +, section' +, section_ +, section'_ +, section__ +, section'__ +, select +, select' +, select_ +, select'_ +, select__ +, select'__ +, small +, small' +, small_ +, small'_ +, small__ +, small'__ +, source +, source' +, source_ +, source'_ +, source__ +, source'__ +, span +, span' +, span_ +, span'_ +, span__ +, span'__ +, strike +, strike' +, strike_ +, strike'_ +, strike__ +, strike'__ +, strong +, strong' +, strong_ +, strong'_ +, strong__ +, strong'__ +, style +, style' +, style_ +, style'_ +, style__ +, style'__ +, sub +, sub' +, sub_ +, sub'_ +, sub__ +, sub'__ +, summary +, summary' +, summary_ +, summary'_ +, summary__ +, summary'__ +, sup +, sup' +, sup_ +, sup'_ +, sup__ +, sup'__ +, svg +, svg' +, svg_ +, svg'_ +, svg__ +, svg'__ +, table +, table' +, table_ +, table'_ +, table__ +, table'__ +, tbody +, tbody' +, tbody_ +, tbody'_ +, tbody__ +, tbody'__ +, td +, td' +, td_ +, td'_ +, td__ +, td'__ +, template +, template' +, template_ +, template'_ +, template__ +, template'__ +, textarea +, textarea' +, textarea_ +, textarea'_ +, textarea__ +, textarea'__ +, tfoot +, tfoot' +, tfoot_ +, tfoot'_ +, tfoot__ +, tfoot'__ +, th +, th' +, th_ +, th'_ +, th__ +, th'__ +, thead +, thead' +, thead_ +, thead'_ +, thead__ +, thead'__ +, time +, time' +, time_ +, time'_ +, time__ +, time'__ +, title +, title' +, title_ +, title'_ +, title__ +, title'__ +, tr +, tr' +, tr_ +, tr'_ +, tr__ +, tr'__ +, track +, track' +, track_ +, track'_ +, track__ +, track'__ +, tt +, tt' +, tt_ +, tt'_ +, tt__ +, tt'__ +, u +, u' +, u_ +, u'_ +, u__ +, u'__ +, ul +, ul' +, ul_ +, ul'_ +, ul__ +, ul'__ +, var +, var' +, var_ +, var'_ +, var__ +, var'__ +, video +, video' +, video_ +, video'_ +, video__ +, video'__ +, wbr +, txt +, txt' +) where + +import Prelude(String) +import Web.Framework.Plzwrk.Base + +type AFSig s opq + = (s -> Attributes s opq) -> [s -> Node s opq] -> (s -> Node s opq) +type Sig s opq = (s -> Attributes s opq) -> [s -> Node s opq] -> Node s opq + +type AFSig_ s opq = [s -> Node s opq] -> (s -> Node s opq) +type Sig_ s opq = [s -> Node s opq] -> Node s opq + +type AFSig__ s opq = String -> (s -> Node s opq) +type Sig__ s opq = String -> Node s opq + + +a :: AFSig s opq +a x y = (\_ -> Element "a" x y) + +a' :: Sig s opq +a' = Element "a" + +a_ :: AFSig_ s opq +a_ x = (\_ -> Element "a" dats x) + +a'_ :: Sig_ s opq +a'_ x = Element "a" dats x + +a__ :: AFSig__ s opq +a__ x = (\_ -> Element "a" dats [txt x]) + +a'__ :: Sig__ s opq +a'__ x = Element "a" dats [txt x] + + +abbr :: AFSig s opq +abbr x y = (\_ -> Element "abbr" x y) + +abbr' :: Sig s opq +abbr' = Element "abbr" + +abbr_ :: AFSig_ s opq +abbr_ x = (\_ -> Element "abbr" dats x) + +abbr'_ :: Sig_ s opq +abbr'_ x = Element "abbr" dats x + +abbr__ :: AFSig__ s opq +abbr__ x = (\_ -> Element "abbr" dats [txt x]) + +abbr'__ :: Sig__ s opq +abbr'__ x = Element "abbr" dats [txt x] + + +acronym :: AFSig s opq +acronym x y = (\_ -> Element "acronym" x y) + +acronym' :: Sig s opq +acronym' = Element "acronym" + +acronym_ :: AFSig_ s opq +acronym_ x = (\_ -> Element "acronym" dats x) + +acronym'_ :: Sig_ s opq +acronym'_ x = Element "acronym" dats x + +acronym__ :: AFSig__ s opq +acronym__ x = (\_ -> Element "acronym" dats [txt x]) + +acronym'__ :: Sig__ s opq +acronym'__ x = Element "acronym" dats [txt x] + + +address :: AFSig s opq +address x y = (\_ -> Element "address" x y) + +address' :: Sig s opq +address' = Element "address" + +address_ :: AFSig_ s opq +address_ x = (\_ -> Element "address" dats x) + +address'_ :: Sig_ s opq +address'_ x = Element "address" dats x + +address__ :: AFSig__ s opq +address__ x = (\_ -> Element "address" dats [txt x]) + +address'__ :: Sig__ s opq +address'__ x = Element "address" dats [txt x] + + +applet :: AFSig s opq +applet x y = (\_ -> Element "applet" x y) + +applet' :: Sig s opq +applet' = Element "applet" + +applet_ :: AFSig_ s opq +applet_ x = (\_ -> Element "applet" dats x) + +applet'_ :: Sig_ s opq +applet'_ x = Element "applet" dats x + +applet__ :: AFSig__ s opq +applet__ x = (\_ -> Element "applet" dats [txt x]) + +applet'__ :: Sig__ s opq +applet'__ x = Element "applet" dats [txt x] + + +area :: AFSig s opq +area x y = (\_ -> Element "area" x y) + +area' :: Sig s opq +area' = Element "area" + +area_ :: AFSig_ s opq +area_ x = (\_ -> Element "area" dats x) + +area'_ :: Sig_ s opq +area'_ x = Element "area" dats x + +area__ :: AFSig__ s opq +area__ x = (\_ -> Element "area" dats [txt x]) + +area'__ :: Sig__ s opq +area'__ x = Element "area" dats [txt x] + + +article :: AFSig s opq +article x y = (\_ -> Element "article" x y) + +article' :: Sig s opq +article' = Element "article" + +article_ :: AFSig_ s opq +article_ x = (\_ -> Element "article" dats x) + +article'_ :: Sig_ s opq +article'_ x = Element "article" dats x + +article__ :: AFSig__ s opq +article__ x = (\_ -> Element "article" dats [txt x]) + +article'__ :: Sig__ s opq +article'__ x = Element "article" dats [txt x] + + +aside :: AFSig s opq +aside x y = (\_ -> Element "aside" x y) + +aside' :: Sig s opq +aside' = Element "aside" + +aside_ :: AFSig_ s opq +aside_ x = (\_ -> Element "aside" dats x) + +aside'_ :: Sig_ s opq +aside'_ x = Element "aside" dats x + +aside__ :: AFSig__ s opq +aside__ x = (\_ -> Element "aside" dats [txt x]) + +aside'__ :: Sig__ s opq +aside'__ x = Element "aside" dats [txt x] + + +audio :: AFSig s opq +audio x y = (\_ -> Element "audio" x y) + +audio' :: Sig s opq +audio' = Element "audio" + +audio_ :: AFSig_ s opq +audio_ x = (\_ -> Element "audio" dats x) + +audio'_ :: Sig_ s opq +audio'_ x = Element "audio" dats x + +audio__ :: AFSig__ s opq +audio__ x = (\_ -> Element "audio" dats [txt x]) + +audio'__ :: Sig__ s opq +audio'__ x = Element "audio" dats [txt x] + + +b :: AFSig s opq +b x y = (\_ -> Element "b" x y) + +b' :: Sig s opq +b' = Element "b" + +b_ :: AFSig_ s opq +b_ x = (\_ -> Element "b" dats x) + +b'_ :: Sig_ s opq +b'_ x = Element "b" dats x + +b__ :: AFSig__ s opq +b__ x = (\_ -> Element "b" dats [txt x]) + +b'__ :: Sig__ s opq +b'__ x = Element "b" dats [txt x] + + +base :: AFSig s opq +base x y = (\_ -> Element "base" x y) + +base' :: Sig s opq +base' = Element "base" + +base_ :: AFSig_ s opq +base_ x = (\_ -> Element "base" dats x) + +base'_ :: Sig_ s opq +base'_ x = Element "base" dats x + +base__ :: AFSig__ s opq +base__ x = (\_ -> Element "base" dats [txt x]) + +base'__ :: Sig__ s opq +base'__ x = Element "base" dats [txt x] + + +basefont :: AFSig s opq +basefont x y = (\_ -> Element "basefont" x y) + +basefont' :: Sig s opq +basefont' = Element "basefont" + +basefont_ :: AFSig_ s opq +basefont_ x = (\_ -> Element "basefont" dats x) + +basefont'_ :: Sig_ s opq +basefont'_ x = Element "basefont" dats x + +basefont__ :: AFSig__ s opq +basefont__ x = (\_ -> Element "basefont" dats [txt x]) + +basefont'__ :: Sig__ s opq +basefont'__ x = Element "basefont" dats [txt x] + + +bdi :: AFSig s opq +bdi x y = (\_ -> Element "bdi" x y) + +bdi' :: Sig s opq +bdi' = Element "bdi" + +bdi_ :: AFSig_ s opq +bdi_ x = (\_ -> Element "bdi" dats x) + +bdi'_ :: Sig_ s opq +bdi'_ x = Element "bdi" dats x + +bdi__ :: AFSig__ s opq +bdi__ x = (\_ -> Element "bdi" dats [txt x]) + +bdi'__ :: Sig__ s opq +bdi'__ x = Element "bdi" dats [txt x] + + +bdo :: AFSig s opq +bdo x y = (\_ -> Element "bdo" x y) + +bdo' :: Sig s opq +bdo' = Element "bdo" + +bdo_ :: AFSig_ s opq +bdo_ x = (\_ -> Element "bdo" dats x) + +bdo'_ :: Sig_ s opq +bdo'_ x = Element "bdo" dats x + +bdo__ :: AFSig__ s opq +bdo__ x = (\_ -> Element "bdo" dats [txt x]) + +bdo'__ :: Sig__ s opq +bdo'__ x = Element "bdo" dats [txt x] + + +big :: AFSig s opq +big x y = (\_ -> Element "big" x y) + +big' :: Sig s opq +big' = Element "big" + +big_ :: AFSig_ s opq +big_ x = (\_ -> Element "big" dats x) + +big'_ :: Sig_ s opq +big'_ x = Element "big" dats x + +big__ :: AFSig__ s opq +big__ x = (\_ -> Element "big" dats [txt x]) + +big'__ :: Sig__ s opq +big'__ x = Element "big" dats [txt x] + + +blockquote :: AFSig s opq +blockquote x y = (\_ -> Element "blockquote" x y) + +blockquote' :: Sig s opq +blockquote' = Element "blockquote" + +blockquote_ :: AFSig_ s opq +blockquote_ x = (\_ -> Element "blockquote" dats x) + +blockquote'_ :: Sig_ s opq +blockquote'_ x = Element "blockquote" dats x + +blockquote__ :: AFSig__ s opq +blockquote__ x = (\_ -> Element "blockquote" dats [txt x]) + +blockquote'__ :: Sig__ s opq +blockquote'__ x = Element "blockquote" dats [txt x] + + +body :: AFSig s opq +body x y = (\_ -> Element "body" x y) + +body' :: Sig s opq +body' = Element "body" + +body_ :: AFSig_ s opq +body_ x = (\_ -> Element "body" dats x) + +body'_ :: Sig_ s opq +body'_ x = Element "body" dats x + +body__ :: AFSig__ s opq +body__ x = (\_ -> Element "body" dats [txt x]) + +body'__ :: Sig__ s opq +body'__ x = Element "body" dats [txt x] + + +br :: (s -> Node s opq) +br = (\_ -> Element "br" dats []) + +button :: AFSig s opq +button x y = (\_ -> Element "button" x y) + +button' :: Sig s opq +button' = Element "button" + +button_ :: AFSig_ s opq +button_ x = (\_ -> Element "button" dats x) + +button'_ :: Sig_ s opq +button'_ x = Element "button" dats x + +button__ :: AFSig__ s opq +button__ x = (\_ -> Element "button" dats [txt x]) + +button'__ :: Sig__ s opq +button'__ x = Element "button" dats [txt x] + + +canvas :: AFSig s opq +canvas x y = (\_ -> Element "canvas" x y) + +canvas' :: Sig s opq +canvas' = Element "canvas" + +canvas_ :: AFSig_ s opq +canvas_ x = (\_ -> Element "canvas" dats x) + +canvas'_ :: Sig_ s opq +canvas'_ x = Element "canvas" dats x + +canvas__ :: AFSig__ s opq +canvas__ x = (\_ -> Element "canvas" dats [txt x]) + +canvas'__ :: Sig__ s opq +canvas'__ x = Element "canvas" dats [txt x] + + +caption :: AFSig s opq +caption x y = (\_ -> Element "caption" x y) + +caption' :: Sig s opq +caption' = Element "caption" + +caption_ :: AFSig_ s opq +caption_ x = (\_ -> Element "caption" dats x) + +caption'_ :: Sig_ s opq +caption'_ x = Element "caption" dats x + +caption__ :: AFSig__ s opq +caption__ x = (\_ -> Element "caption" dats [txt x]) + +caption'__ :: Sig__ s opq +caption'__ x = Element "caption" dats [txt x] + + +center :: AFSig s opq +center x y = (\_ -> Element "center" x y) + +center' :: Sig s opq +center' = Element "center" + +center_ :: AFSig_ s opq +center_ x = (\_ -> Element "center" dats x) + +center'_ :: Sig_ s opq +center'_ x = Element "center" dats x + +center__ :: AFSig__ s opq +center__ x = (\_ -> Element "center" dats [txt x]) + +center'__ :: Sig__ s opq +center'__ x = Element "center" dats [txt x] + + +cite :: AFSig s opq +cite x y = (\_ -> Element "cite" x y) + +cite' :: Sig s opq +cite' = Element "cite" + +cite_ :: AFSig_ s opq +cite_ x = (\_ -> Element "cite" dats x) + +cite'_ :: Sig_ s opq +cite'_ x = Element "cite" dats x + +cite__ :: AFSig__ s opq +cite__ x = (\_ -> Element "cite" dats [txt x]) + +cite'__ :: Sig__ s opq +cite'__ x = Element "cite" dats [txt x] + + +code :: AFSig s opq +code x y = (\_ -> Element "code" x y) + +code' :: Sig s opq +code' = Element "code" + +code_ :: AFSig_ s opq +code_ x = (\_ -> Element "code" dats x) + +code'_ :: Sig_ s opq +code'_ x = Element "code" dats x + +code__ :: AFSig__ s opq +code__ x = (\_ -> Element "code" dats [txt x]) + +code'__ :: Sig__ s opq +code'__ x = Element "code" dats [txt x] + + +col :: AFSig s opq +col x y = (\_ -> Element "col" x y) + +col' :: Sig s opq +col' = Element "col" + +col_ :: AFSig_ s opq +col_ x = (\_ -> Element "col" dats x) + +col'_ :: Sig_ s opq +col'_ x = Element "col" dats x + +col__ :: AFSig__ s opq +col__ x = (\_ -> Element "col" dats [txt x]) + +col'__ :: Sig__ s opq +col'__ x = Element "col" dats [txt x] + + +colgroup :: AFSig s opq +colgroup x y = (\_ -> Element "colgroup" x y) + +colgroup' :: Sig s opq +colgroup' = Element "colgroup" + +colgroup_ :: AFSig_ s opq +colgroup_ x = (\_ -> Element "colgroup" dats x) + +colgroup'_ :: Sig_ s opq +colgroup'_ x = Element "colgroup" dats x + +colgroup__ :: AFSig__ s opq +colgroup__ x = (\_ -> Element "colgroup" dats [txt x]) + +colgroup'__ :: Sig__ s opq +colgroup'__ x = Element "colgroup" dats [txt x] + + +_data :: AFSig s opq +_data x y = (\_ -> Element "_data" x y) + +_data' :: Sig s opq +_data' = Element "_data" + +_data_ :: AFSig_ s opq +_data_ x = (\_ -> Element "_data" dats x) + +_data'_ :: Sig_ s opq +_data'_ x = Element "_data" dats x + +_data__ :: AFSig__ s opq +_data__ x = (\_ -> Element "_data" dats [txt x]) + +_data'__ :: Sig__ s opq +_data'__ x = Element "_data" dats [txt x] + + +_datalist :: AFSig s opq +_datalist x y = (\_ -> Element "_datalist" x y) + +_datalist' :: Sig s opq +_datalist' = Element "_datalist" + +_datalist_ :: AFSig_ s opq +_datalist_ x = (\_ -> Element "_datalist" dats x) + +_datalist'_ :: Sig_ s opq +_datalist'_ x = Element "_datalist" dats x + +_datalist__ :: AFSig__ s opq +_datalist__ x = (\_ -> Element "_datalist" dats [txt x]) + +_datalist'__ :: Sig__ s opq +_datalist'__ x = Element "_datalist" dats [txt x] + + +dd :: AFSig s opq +dd x y = (\_ -> Element "dd" x y) + +dd' :: Sig s opq +dd' = Element "dd" + +dd_ :: AFSig_ s opq +dd_ x = (\_ -> Element "dd" dats x) + +dd'_ :: Sig_ s opq +dd'_ x = Element "dd" dats x + +dd__ :: AFSig__ s opq +dd__ x = (\_ -> Element "dd" dats [txt x]) + +dd'__ :: Sig__ s opq +dd'__ x = Element "dd" dats [txt x] + + +del :: AFSig s opq +del x y = (\_ -> Element "del" x y) + +del' :: Sig s opq +del' = Element "del" + +del_ :: AFSig_ s opq +del_ x = (\_ -> Element "del" dats x) + +del'_ :: Sig_ s opq +del'_ x = Element "del" dats x + +del__ :: AFSig__ s opq +del__ x = (\_ -> Element "del" dats [txt x]) + +del'__ :: Sig__ s opq +del'__ x = Element "del" dats [txt x] + + +details :: AFSig s opq +details x y = (\_ -> Element "details" x y) + +details' :: Sig s opq +details' = Element "details" + +details_ :: AFSig_ s opq +details_ x = (\_ -> Element "details" dats x) + +details'_ :: Sig_ s opq +details'_ x = Element "details" dats x + +details__ :: AFSig__ s opq +details__ x = (\_ -> Element "details" dats [txt x]) + +details'__ :: Sig__ s opq +details'__ x = Element "details" dats [txt x] + + +dfn :: AFSig s opq +dfn x y = (\_ -> Element "dfn" x y) + +dfn' :: Sig s opq +dfn' = Element "dfn" + +dfn_ :: AFSig_ s opq +dfn_ x = (\_ -> Element "dfn" dats x) + +dfn'_ :: Sig_ s opq +dfn'_ x = Element "dfn" dats x + +dfn__ :: AFSig__ s opq +dfn__ x = (\_ -> Element "dfn" dats [txt x]) + +dfn'__ :: Sig__ s opq +dfn'__ x = Element "dfn" dats [txt x] + + +dialog :: AFSig s opq +dialog x y = (\_ -> Element "dialog" x y) + +dialog' :: Sig s opq +dialog' = Element "dialog" + +dialog_ :: AFSig_ s opq +dialog_ x = (\_ -> Element "dialog" dats x) + +dialog'_ :: Sig_ s opq +dialog'_ x = Element "dialog" dats x + +dialog__ :: AFSig__ s opq +dialog__ x = (\_ -> Element "dialog" dats [txt x]) + +dialog'__ :: Sig__ s opq +dialog'__ x = Element "dialog" dats [txt x] + + +dir :: AFSig s opq +dir x y = (\_ -> Element "dir" x y) + +dir' :: Sig s opq +dir' = Element "dir" + +dir_ :: AFSig_ s opq +dir_ x = (\_ -> Element "dir" dats x) + +dir'_ :: Sig_ s opq +dir'_ x = Element "dir" dats x + +dir__ :: AFSig__ s opq +dir__ x = (\_ -> Element "dir" dats [txt x]) + +dir'__ :: Sig__ s opq +dir'__ x = Element "dir" dats [txt x] + + +div :: AFSig s opq +div x y = (\_ -> Element "div" x y) + +div' :: Sig s opq +div' = Element "div" + +div_ :: AFSig_ s opq +div_ x = (\_ -> Element "div" dats x) + +div'_ :: Sig_ s opq +div'_ x = Element "div" dats x + +div__ :: AFSig__ s opq +div__ x = (\_ -> Element "div" dats [txt x]) + +div'__ :: Sig__ s opq +div'__ x = Element "div" dats [txt x] + + +dl :: AFSig s opq +dl x y = (\_ -> Element "dl" x y) + +dl' :: Sig s opq +dl' = Element "dl" + +dl_ :: AFSig_ s opq +dl_ x = (\_ -> Element "dl" dats x) + +dl'_ :: Sig_ s opq +dl'_ x = Element "dl" dats x + +dl__ :: AFSig__ s opq +dl__ x = (\_ -> Element "dl" dats [txt x]) + +dl'__ :: Sig__ s opq +dl'__ x = Element "dl" dats [txt x] + + +dt :: AFSig s opq +dt x y = (\_ -> Element "dt" x y) + +dt' :: Sig s opq +dt' = Element "dt" + +dt_ :: AFSig_ s opq +dt_ x = (\_ -> Element "dt" dats x) + +dt'_ :: Sig_ s opq +dt'_ x = Element "dt" dats x + +dt__ :: AFSig__ s opq +dt__ x = (\_ -> Element "dt" dats [txt x]) + +dt'__ :: Sig__ s opq +dt'__ x = Element "dt" dats [txt x] + + +em :: AFSig s opq +em x y = (\_ -> Element "em" x y) + +em' :: Sig s opq +em' = Element "em" + +em_ :: AFSig_ s opq +em_ x = (\_ -> Element "em" dats x) + +em'_ :: Sig_ s opq +em'_ x = Element "em" dats x + +em__ :: AFSig__ s opq +em__ x = (\_ -> Element "em" dats [txt x]) + +em'__ :: Sig__ s opq +em'__ x = Element "em" dats [txt x] + + +embed :: AFSig s opq +embed x y = (\_ -> Element "embed" x y) + +embed' :: Sig s opq +embed' = Element "embed" + +embed_ :: AFSig_ s opq +embed_ x = (\_ -> Element "embed" dats x) + +embed'_ :: Sig_ s opq +embed'_ x = Element "embed" dats x + +embed__ :: AFSig__ s opq +embed__ x = (\_ -> Element "embed" dats [txt x]) + +embed'__ :: Sig__ s opq +embed'__ x = Element "embed" dats [txt x] + + +fieldset :: AFSig s opq +fieldset x y = (\_ -> Element "fieldset" x y) + +fieldset' :: Sig s opq +fieldset' = Element "fieldset" + +fieldset_ :: AFSig_ s opq +fieldset_ x = (\_ -> Element "fieldset" dats x) + +fieldset'_ :: Sig_ s opq +fieldset'_ x = Element "fieldset" dats x + +fieldset__ :: AFSig__ s opq +fieldset__ x = (\_ -> Element "fieldset" dats [txt x]) + +fieldset'__ :: Sig__ s opq +fieldset'__ x = Element "fieldset" dats [txt x] + + +figcaption :: AFSig s opq +figcaption x y = (\_ -> Element "figcaption" x y) + +figcaption' :: Sig s opq +figcaption' = Element "figcaption" + +figcaption_ :: AFSig_ s opq +figcaption_ x = (\_ -> Element "figcaption" dats x) + +figcaption'_ :: Sig_ s opq +figcaption'_ x = Element "figcaption" dats x + +figcaption__ :: AFSig__ s opq +figcaption__ x = (\_ -> Element "figcaption" dats [txt x]) + +figcaption'__ :: Sig__ s opq +figcaption'__ x = Element "figcaption" dats [txt x] + + +figure :: AFSig s opq +figure x y = (\_ -> Element "figure" x y) + +figure' :: Sig s opq +figure' = Element "figure" + +figure_ :: AFSig_ s opq +figure_ x = (\_ -> Element "figure" dats x) + +figure'_ :: Sig_ s opq +figure'_ x = Element "figure" dats x + +figure__ :: AFSig__ s opq +figure__ x = (\_ -> Element "figure" dats [txt x]) + +figure'__ :: Sig__ s opq +figure'__ x = Element "figure" dats [txt x] + + +font :: AFSig s opq +font x y = (\_ -> Element "font" x y) + +font' :: Sig s opq +font' = Element "font" + +font_ :: AFSig_ s opq +font_ x = (\_ -> Element "font" dats x) + +font'_ :: Sig_ s opq +font'_ x = Element "font" dats x + +font__ :: AFSig__ s opq +font__ x = (\_ -> Element "font" dats [txt x]) + +font'__ :: Sig__ s opq +font'__ x = Element "font" dats [txt x] + + +footer :: AFSig s opq +footer x y = (\_ -> Element "footer" x y) + +footer' :: Sig s opq +footer' = Element "footer" + +footer_ :: AFSig_ s opq +footer_ x = (\_ -> Element "footer" dats x) + +footer'_ :: Sig_ s opq +footer'_ x = Element "footer" dats x + +footer__ :: AFSig__ s opq +footer__ x = (\_ -> Element "footer" dats [txt x]) + +footer'__ :: Sig__ s opq +footer'__ x = Element "footer" dats [txt x] + + +form :: AFSig s opq +form x y = (\_ -> Element "form" x y) + +form' :: Sig s opq +form' = Element "form" + +form_ :: AFSig_ s opq +form_ x = (\_ -> Element "form" dats x) + +form'_ :: Sig_ s opq +form'_ x = Element "form" dats x + +form__ :: AFSig__ s opq +form__ x = (\_ -> Element "form" dats [txt x]) + +form'__ :: Sig__ s opq +form'__ x = Element "form" dats [txt x] + + +frame :: AFSig s opq +frame x y = (\_ -> Element "frame" x y) + +frame' :: Sig s opq +frame' = Element "frame" + +frame_ :: AFSig_ s opq +frame_ x = (\_ -> Element "frame" dats x) + +frame'_ :: Sig_ s opq +frame'_ x = Element "frame" dats x + +frame__ :: AFSig__ s opq +frame__ x = (\_ -> Element "frame" dats [txt x]) + +frame'__ :: Sig__ s opq +frame'__ x = Element "frame" dats [txt x] + + +frameset :: AFSig s opq +frameset x y = (\_ -> Element "frameset" x y) + +frameset' :: Sig s opq +frameset' = Element "frameset" + +frameset_ :: AFSig_ s opq +frameset_ x = (\_ -> Element "frameset" dats x) + +frameset'_ :: Sig_ s opq +frameset'_ x = Element "frameset" dats x + +frameset__ :: AFSig__ s opq +frameset__ x = (\_ -> Element "frameset" dats [txt x]) + +frameset'__ :: Sig__ s opq +frameset'__ x = Element "frameset" dats [txt x] + +head :: AFSig s opq +head x y = (\_ -> Element "head" x y) + +head' :: Sig s opq +head' = Element "head" + +head_ :: AFSig_ s opq +head_ x = (\_ -> Element "head" dats x) + +head'_ :: Sig_ s opq +head'_ x = Element "head" dats x + +head__ :: AFSig__ s opq +head__ x = (\_ -> Element "head" dats [txt x]) + +head'__ :: Sig__ s opq +head'__ x = Element "head" dats [txt x] + + +header :: AFSig s opq +header x y = (\_ -> Element "header" x y) + +header' :: Sig s opq +header' = Element "header" + +header_ :: AFSig_ s opq +header_ x = (\_ -> Element "header" dats x) + +header'_ :: Sig_ s opq +header'_ x = Element "header" dats x + +header__ :: AFSig__ s opq +header__ x = (\_ -> Element "header" dats [txt x]) + +header'__ :: Sig__ s opq +header'__ x = Element "header" dats [txt x] + + +hr :: (s -> Node s opq) +hr = (\_ -> Element "br" dats []) + +html :: AFSig s opq +html x y = (\_ -> Element "html" x y) + +html' :: Sig s opq +html' = Element "html" + +html_ :: AFSig_ s opq +html_ x = (\_ -> Element "html" dats x) + +html'_ :: Sig_ s opq +html'_ x = Element "html" dats x + +html__ :: AFSig__ s opq +html__ x = (\_ -> Element "html" dats [txt x]) + +html'__ :: Sig__ s opq +html'__ x = Element "html" dats [txt x] + + +i :: AFSig s opq +i x y = (\_ -> Element "i" x y) + +i' :: Sig s opq +i' = Element "i" + +i_ :: AFSig_ s opq +i_ x = (\_ -> Element "i" dats x) + +i'_ :: Sig_ s opq +i'_ x = Element "i" dats x + +i__ :: AFSig__ s opq +i__ x = (\_ -> Element "i" dats [txt x]) + +i'__ :: Sig__ s opq +i'__ x = Element "i" dats [txt x] + + +iframe :: AFSig s opq +iframe x y = (\_ -> Element "iframe" x y) + +iframe' :: Sig s opq +iframe' = Element "iframe" + +iframe_ :: AFSig_ s opq +iframe_ x = (\_ -> Element "iframe" dats x) + +iframe'_ :: Sig_ s opq +iframe'_ x = Element "iframe" dats x + +iframe__ :: AFSig__ s opq +iframe__ x = (\_ -> Element "iframe" dats [txt x]) + +iframe'__ :: Sig__ s opq +iframe'__ x = Element "iframe" dats [txt x] + + +img :: (s -> Attributes s opq) -> (s -> Node s opq) +img x = (\_ -> Element "img" x []) + +img' :: (s -> Attributes s opq) -> Node s opq +img' x = Element "img" x [] + +img_ :: (s -> Node s opq) +img_ = (\_ -> Element "img" dats []) + +img'_ :: Node s opq +img'_ = Element "img" dats [] + +input :: AFSig s opq +input x y = (\_ -> Element "input" x y) + +input' :: Sig s opq +input' = Element "input" + +input_ :: AFSig_ s opq +input_ x = (\_ -> Element "input" dats x) + +input'_ :: Sig_ s opq +input'_ x = Element "input" dats x + +input__ :: AFSig__ s opq +input__ x = (\_ -> Element "input" dats [txt x]) + +input'__ :: Sig__ s opq +input'__ x = Element "input" dats [txt x] + + +ins :: AFSig s opq +ins x y = (\_ -> Element "ins" x y) + +ins' :: Sig s opq +ins' = Element "ins" + +ins_ :: AFSig_ s opq +ins_ x = (\_ -> Element "ins" dats x) + +ins'_ :: Sig_ s opq +ins'_ x = Element "ins" dats x + +ins__ :: AFSig__ s opq +ins__ x = (\_ -> Element "ins" dats [txt x]) + +ins'__ :: Sig__ s opq +ins'__ x = Element "ins" dats [txt x] + + +kbd :: AFSig s opq +kbd x y = (\_ -> Element "kbd" x y) + +kbd' :: Sig s opq +kbd' = Element "kbd" + +kbd_ :: AFSig_ s opq +kbd_ x = (\_ -> Element "kbd" dats x) + +kbd'_ :: Sig_ s opq +kbd'_ x = Element "kbd" dats x + +kbd__ :: AFSig__ s opq +kbd__ x = (\_ -> Element "kbd" dats [txt x]) + +kbd'__ :: Sig__ s opq +kbd'__ x = Element "kbd" dats [txt x] + + +label :: AFSig s opq +label x y = (\_ -> Element "label" x y) + +label' :: Sig s opq +label' = Element "label" + +label_ :: AFSig_ s opq +label_ x = (\_ -> Element "label" dats x) + +label'_ :: Sig_ s opq +label'_ x = Element "label" dats x + +label__ :: AFSig__ s opq +label__ x = (\_ -> Element "label" dats [txt x]) + +label'__ :: Sig__ s opq +label'__ x = Element "label" dats [txt x] + + +legend :: AFSig s opq +legend x y = (\_ -> Element "legend" x y) + +legend' :: Sig s opq +legend' = Element "legend" + +legend_ :: AFSig_ s opq +legend_ x = (\_ -> Element "legend" dats x) + +legend'_ :: Sig_ s opq +legend'_ x = Element "legend" dats x + +legend__ :: AFSig__ s opq +legend__ x = (\_ -> Element "legend" dats [txt x]) + +legend'__ :: Sig__ s opq +legend'__ x = Element "legend" dats [txt x] + + +li :: AFSig s opq +li x y = (\_ -> Element "li" x y) + +li' :: Sig s opq +li' = Element "li" + +li_ :: AFSig_ s opq +li_ x = (\_ -> Element "li" dats x) + +li'_ :: Sig_ s opq +li'_ x = Element "li" dats x + +li__ :: AFSig__ s opq +li__ x = (\_ -> Element "li" dats [txt x]) + +li'__ :: Sig__ s opq +li'__ x = Element "li" dats [txt x] + + +link :: AFSig s opq +link x y = (\_ -> Element "link" x y) + +link' :: Sig s opq +link' = Element "link" + +link_ :: AFSig_ s opq +link_ x = (\_ -> Element "link" dats x) + +link'_ :: Sig_ s opq +link'_ x = Element "link" dats x + +link__ :: AFSig__ s opq +link__ x = (\_ -> Element "link" dats [txt x]) + +link'__ :: Sig__ s opq +link'__ x = Element "link" dats [txt x] + + +main :: AFSig s opq +main x y = (\_ -> Element "main" x y) + +main' :: Sig s opq +main' = Element "main" + +main_ :: AFSig_ s opq +main_ x = (\_ -> Element "main" dats x) + +main'_ :: Sig_ s opq +main'_ x = Element "main" dats x + +main__ :: AFSig__ s opq +main__ x = (\_ -> Element "main" dats [txt x]) + +main'__ :: Sig__ s opq +main'__ x = Element "main" dats [txt x] + + +map :: AFSig s opq +map x y = (\_ -> Element "map" x y) + +map' :: Sig s opq +map' = Element "map" + +map_ :: AFSig_ s opq +map_ x = (\_ -> Element "map" dats x) + +map'_ :: Sig_ s opq +map'_ x = Element "map" dats x + +map__ :: AFSig__ s opq +map__ x = (\_ -> Element "map" dats [txt x]) + +map'__ :: Sig__ s opq +map'__ x = Element "map" dats [txt x] + + +mark :: AFSig s opq +mark x y = (\_ -> Element "mark" x y) + +mark' :: Sig s opq +mark' = Element "mark" + +mark_ :: AFSig_ s opq +mark_ x = (\_ -> Element "mark" dats x) + +mark'_ :: Sig_ s opq +mark'_ x = Element "mark" dats x + +mark__ :: AFSig__ s opq +mark__ x = (\_ -> Element "mark" dats [txt x]) + +mark'__ :: Sig__ s opq +mark'__ x = Element "mark" dats [txt x] + + +meta :: AFSig s opq +meta x y = (\_ -> Element "meta" x y) + +meta' :: Sig s opq +meta' = Element "meta" + +meta_ :: AFSig_ s opq +meta_ x = (\_ -> Element "meta" dats x) + +meta'_ :: Sig_ s opq +meta'_ x = Element "meta" dats x + +meta__ :: AFSig__ s opq +meta__ x = (\_ -> Element "meta" dats [txt x]) + +meta'__ :: Sig__ s opq +meta'__ x = Element "meta" dats [txt x] + + +meter :: AFSig s opq +meter x y = (\_ -> Element "meter" x y) + +meter' :: Sig s opq +meter' = Element "meter" + +meter_ :: AFSig_ s opq +meter_ x = (\_ -> Element "meter" dats x) + +meter'_ :: Sig_ s opq +meter'_ x = Element "meter" dats x + +meter__ :: AFSig__ s opq +meter__ x = (\_ -> Element "meter" dats [txt x]) + +meter'__ :: Sig__ s opq +meter'__ x = Element "meter" dats [txt x] + + +nav :: AFSig s opq +nav x y = (\_ -> Element "nav" x y) + +nav' :: Sig s opq +nav' = Element "nav" + +nav_ :: AFSig_ s opq +nav_ x = (\_ -> Element "nav" dats x) + +nav'_ :: Sig_ s opq +nav'_ x = Element "nav" dats x + +nav__ :: AFSig__ s opq +nav__ x = (\_ -> Element "nav" dats [txt x]) + +nav'__ :: Sig__ s opq +nav'__ x = Element "nav" dats [txt x] + + +noframes :: AFSig s opq +noframes x y = (\_ -> Element "noframes" x y) + +noframes' :: Sig s opq +noframes' = Element "noframes" + +noframes_ :: AFSig_ s opq +noframes_ x = (\_ -> Element "noframes" dats x) + +noframes'_ :: Sig_ s opq +noframes'_ x = Element "noframes" dats x + +noframes__ :: AFSig__ s opq +noframes__ x = (\_ -> Element "noframes" dats [txt x]) + +noframes'__ :: Sig__ s opq +noframes'__ x = Element "noframes" dats [txt x] + + +noscript :: AFSig s opq +noscript x y = (\_ -> Element "noscript" x y) + +noscript' :: Sig s opq +noscript' = Element "noscript" + +noscript_ :: AFSig_ s opq +noscript_ x = (\_ -> Element "noscript" dats x) + +noscript'_ :: Sig_ s opq +noscript'_ x = Element "noscript" dats x + +noscript__ :: AFSig__ s opq +noscript__ x = (\_ -> Element "noscript" dats [txt x]) + +noscript'__ :: Sig__ s opq +noscript'__ x = Element "noscript" dats [txt x] + + +object :: AFSig s opq +object x y = (\_ -> Element "object" x y) + +object' :: Sig s opq +object' = Element "object" + +object_ :: AFSig_ s opq +object_ x = (\_ -> Element "object" dats x) + +object'_ :: Sig_ s opq +object'_ x = Element "object" dats x + +object__ :: AFSig__ s opq +object__ x = (\_ -> Element "object" dats [txt x]) + +object'__ :: Sig__ s opq +object'__ x = Element "object" dats [txt x] + + +ol :: AFSig s opq +ol x y = (\_ -> Element "ol" x y) + +ol' :: Sig s opq +ol' = Element "ol" + +ol_ :: AFSig_ s opq +ol_ x = (\_ -> Element "ol" dats x) + +ol'_ :: Sig_ s opq +ol'_ x = Element "ol" dats x + +ol__ :: AFSig__ s opq +ol__ x = (\_ -> Element "ol" dats [txt x]) + +ol'__ :: Sig__ s opq +ol'__ x = Element "ol" dats [txt x] + + +optgroup :: AFSig s opq +optgroup x y = (\_ -> Element "optgroup" x y) + +optgroup' :: Sig s opq +optgroup' = Element "optgroup" + +optgroup_ :: AFSig_ s opq +optgroup_ x = (\_ -> Element "optgroup" dats x) + +optgroup'_ :: Sig_ s opq +optgroup'_ x = Element "optgroup" dats x + +optgroup__ :: AFSig__ s opq +optgroup__ x = (\_ -> Element "optgroup" dats [txt x]) + +optgroup'__ :: Sig__ s opq +optgroup'__ x = Element "optgroup" dats [txt x] + + +option :: AFSig s opq +option x y = (\_ -> Element "option" x y) + +option' :: Sig s opq +option' = Element "option" + +option_ :: AFSig_ s opq +option_ x = (\_ -> Element "option" dats x) + +option'_ :: Sig_ s opq +option'_ x = Element "option" dats x + +option__ :: AFSig__ s opq +option__ x = (\_ -> Element "option" dats [txt x]) + +option'__ :: Sig__ s opq +option'__ x = Element "option" dats [txt x] + + +output :: AFSig s opq +output x y = (\_ -> Element "output" x y) + +output' :: Sig s opq +output' = Element "output" + +output_ :: AFSig_ s opq +output_ x = (\_ -> Element "output" dats x) + +output'_ :: Sig_ s opq +output'_ x = Element "output" dats x + +output__ :: AFSig__ s opq +output__ x = (\_ -> Element "output" dats [txt x]) + +output'__ :: Sig__ s opq +output'__ x = Element "output" dats [txt x] + + +p :: AFSig s opq +p x y = (\_ -> Element "p" x y) + +p' :: Sig s opq +p' = Element "p" + +p_ :: AFSig_ s opq +p_ x = (\_ -> Element "p" dats x) + +p'_ :: Sig_ s opq +p'_ x = Element "p" dats x + +p__ :: AFSig__ s opq +p__ x = (\_ -> Element "p" dats [txt x]) + +p'__ :: Sig__ s opq +p'__ x = Element "p" dats [txt x] + + +param :: AFSig s opq +param x y = (\_ -> Element "param" x y) + +param' :: Sig s opq +param' = Element "param" + +param_ :: AFSig_ s opq +param_ x = (\_ -> Element "param" dats x) + +param'_ :: Sig_ s opq +param'_ x = Element "param" dats x + +param__ :: AFSig__ s opq +param__ x = (\_ -> Element "param" dats [txt x]) + +param'__ :: Sig__ s opq +param'__ x = Element "param" dats [txt x] + + +picture :: AFSig s opq +picture x y = (\_ -> Element "picture" x y) + +picture' :: Sig s opq +picture' = Element "picture" + +picture_ :: AFSig_ s opq +picture_ x = (\_ -> Element "picture" dats x) + +picture'_ :: Sig_ s opq +picture'_ x = Element "picture" dats x + +picture__ :: AFSig__ s opq +picture__ x = (\_ -> Element "picture" dats [txt x]) + +picture'__ :: Sig__ s opq +picture'__ x = Element "picture" dats [txt x] + + +pre :: AFSig s opq +pre x y = (\_ -> Element "pre" x y) + +pre' :: Sig s opq +pre' = Element "pre" + +pre_ :: AFSig_ s opq +pre_ x = (\_ -> Element "pre" dats x) + +pre'_ :: Sig_ s opq +pre'_ x = Element "pre" dats x + +pre__ :: AFSig__ s opq +pre__ x = (\_ -> Element "pre" dats [txt x]) + +pre'__ :: Sig__ s opq +pre'__ x = Element "pre" dats [txt x] + + +progress :: AFSig s opq +progress x y = (\_ -> Element "progress" x y) + +progress' :: Sig s opq +progress' = Element "progress" + +progress_ :: AFSig_ s opq +progress_ x = (\_ -> Element "progress" dats x) + +progress'_ :: Sig_ s opq +progress'_ x = Element "progress" dats x + +progress__ :: AFSig__ s opq +progress__ x = (\_ -> Element "progress" dats [txt x]) + +progress'__ :: Sig__ s opq +progress'__ x = Element "progress" dats [txt x] + + +q :: AFSig s opq +q x y = (\_ -> Element "q" x y) + +q' :: Sig s opq +q' = Element "q" + +q_ :: AFSig_ s opq +q_ x = (\_ -> Element "q" dats x) + +q'_ :: Sig_ s opq +q'_ x = Element "q" dats x + +q__ :: AFSig__ s opq +q__ x = (\_ -> Element "q" dats [txt x]) + +q'__ :: Sig__ s opq +q'__ x = Element "q" dats [txt x] + + +rp :: AFSig s opq +rp x y = (\_ -> Element "rp" x y) + +rp' :: Sig s opq +rp' = Element "rp" + +rp_ :: AFSig_ s opq +rp_ x = (\_ -> Element "rp" dats x) + +rp'_ :: Sig_ s opq +rp'_ x = Element "rp" dats x + +rp__ :: AFSig__ s opq +rp__ x = (\_ -> Element "rp" dats [txt x]) + +rp'__ :: Sig__ s opq +rp'__ x = Element "rp" dats [txt x] + + +rt :: AFSig s opq +rt x y = (\_ -> Element "rt" x y) + +rt' :: Sig s opq +rt' = Element "rt" + +rt_ :: AFSig_ s opq +rt_ x = (\_ -> Element "rt" dats x) + +rt'_ :: Sig_ s opq +rt'_ x = Element "rt" dats x + +rt__ :: AFSig__ s opq +rt__ x = (\_ -> Element "rt" dats [txt x]) + +rt'__ :: Sig__ s opq +rt'__ x = Element "rt" dats [txt x] + + +ruby :: AFSig s opq +ruby x y = (\_ -> Element "ruby" x y) + +ruby' :: Sig s opq +ruby' = Element "ruby" + +ruby_ :: AFSig_ s opq +ruby_ x = (\_ -> Element "ruby" dats x) + +ruby'_ :: Sig_ s opq +ruby'_ x = Element "ruby" dats x + +ruby__ :: AFSig__ s opq +ruby__ x = (\_ -> Element "ruby" dats [txt x]) + +ruby'__ :: Sig__ s opq +ruby'__ x = Element "ruby" dats [txt x] + + +s :: AFSig s opq +s x y = (\_ -> Element "s" x y) + +s' :: Sig s opq +s' = Element "s" + +s_ :: AFSig_ s opq +s_ x = (\_ -> Element "s" dats x) + +s'_ :: Sig_ s opq +s'_ x = Element "s" dats x + +s__ :: AFSig__ s opq +s__ x = (\_ -> Element "s" dats [txt x]) + +s'__ :: Sig__ s opq +s'__ x = Element "s" dats [txt x] + + +samp :: AFSig s opq +samp x y = (\_ -> Element "samp" x y) + +samp' :: Sig s opq +samp' = Element "samp" + +samp_ :: AFSig_ s opq +samp_ x = (\_ -> Element "samp" dats x) + +samp'_ :: Sig_ s opq +samp'_ x = Element "samp" dats x + +samp__ :: AFSig__ s opq +samp__ x = (\_ -> Element "samp" dats [txt x]) + +samp'__ :: Sig__ s opq +samp'__ x = Element "samp" dats [txt x] + + +script :: AFSig s opq +script x y = (\_ -> Element "script" x y) + +script' :: Sig s opq +script' = Element "script" + +script_ :: AFSig_ s opq +script_ x = (\_ -> Element "script" dats x) + +script'_ :: Sig_ s opq +script'_ x = Element "script" dats x + +script__ :: AFSig__ s opq +script__ x = (\_ -> Element "script" dats [txt x]) + +script'__ :: Sig__ s opq +script'__ x = Element "script" dats [txt x] + + +section :: AFSig s opq +section x y = (\_ -> Element "section" x y) + +section' :: Sig s opq +section' = Element "section" + +section_ :: AFSig_ s opq +section_ x = (\_ -> Element "section" dats x) + +section'_ :: Sig_ s opq +section'_ x = Element "section" dats x + +section__ :: AFSig__ s opq +section__ x = (\_ -> Element "section" dats [txt x]) + +section'__ :: Sig__ s opq +section'__ x = Element "section" dats [txt x] + + +select :: AFSig s opq +select x y = (\_ -> Element "select" x y) + +select' :: Sig s opq +select' = Element "select" + +select_ :: AFSig_ s opq +select_ x = (\_ -> Element "select" dats x) + +select'_ :: Sig_ s opq +select'_ x = Element "select" dats x + +select__ :: AFSig__ s opq +select__ x = (\_ -> Element "select" dats [txt x]) + +select'__ :: Sig__ s opq +select'__ x = Element "select" dats [txt x] + + +small :: AFSig s opq +small x y = (\_ -> Element "small" x y) + +small' :: Sig s opq +small' = Element "small" + +small_ :: AFSig_ s opq +small_ x = (\_ -> Element "small" dats x) + +small'_ :: Sig_ s opq +small'_ x = Element "small" dats x + +small__ :: AFSig__ s opq +small__ x = (\_ -> Element "small" dats [txt x]) + +small'__ :: Sig__ s opq +small'__ x = Element "small" dats [txt x] + + +source :: AFSig s opq +source x y = (\_ -> Element "source" x y) + +source' :: Sig s opq +source' = Element "source" + +source_ :: AFSig_ s opq +source_ x = (\_ -> Element "source" dats x) + +source'_ :: Sig_ s opq +source'_ x = Element "source" dats x + +source__ :: AFSig__ s opq +source__ x = (\_ -> Element "source" dats [txt x]) + +source'__ :: Sig__ s opq +source'__ x = Element "source" dats [txt x] + + +span :: AFSig s opq +span x y = (\_ -> Element "span" x y) + +span' :: Sig s opq +span' = Element "span" + +span_ :: AFSig_ s opq +span_ x = (\_ -> Element "span" dats x) + +span'_ :: Sig_ s opq +span'_ x = Element "span" dats x + +span__ :: AFSig__ s opq +span__ x = (\_ -> Element "span" dats [txt x]) + +span'__ :: Sig__ s opq +span'__ x = Element "span" dats [txt x] + + +strike :: AFSig s opq +strike x y = (\_ -> Element "strike" x y) + +strike' :: Sig s opq +strike' = Element "strike" + +strike_ :: AFSig_ s opq +strike_ x = (\_ -> Element "strike" dats x) + +strike'_ :: Sig_ s opq +strike'_ x = Element "strike" dats x + +strike__ :: AFSig__ s opq +strike__ x = (\_ -> Element "strike" dats [txt x]) + +strike'__ :: Sig__ s opq +strike'__ x = Element "strike" dats [txt x] + + +strong :: AFSig s opq +strong x y = (\_ -> Element "strong" x y) + +strong' :: Sig s opq +strong' = Element "strong" + +strong_ :: AFSig_ s opq +strong_ x = (\_ -> Element "strong" dats x) + +strong'_ :: Sig_ s opq +strong'_ x = Element "strong" dats x + +strong__ :: AFSig__ s opq +strong__ x = (\_ -> Element "strong" dats [txt x]) + +strong'__ :: Sig__ s opq +strong'__ x = Element "strong" dats [txt x] + + +style :: AFSig s opq +style x y = (\_ -> Element "style" x y) + +style' :: Sig s opq +style' = Element "style" + +style_ :: AFSig_ s opq +style_ x = (\_ -> Element "style" dats x) + +style'_ :: Sig_ s opq +style'_ x = Element "style" dats x + +style__ :: AFSig__ s opq +style__ x = (\_ -> Element "style" dats [txt x]) + +style'__ :: Sig__ s opq +style'__ x = Element "style" dats [txt x] + + +sub :: AFSig s opq +sub x y = (\_ -> Element "sub" x y) + +sub' :: Sig s opq +sub' = Element "sub" + +sub_ :: AFSig_ s opq +sub_ x = (\_ -> Element "sub" dats x) + +sub'_ :: Sig_ s opq +sub'_ x = Element "sub" dats x + +sub__ :: AFSig__ s opq +sub__ x = (\_ -> Element "sub" dats [txt x]) + +sub'__ :: Sig__ s opq +sub'__ x = Element "sub" dats [txt x] + + +summary :: AFSig s opq +summary x y = (\_ -> Element "summary" x y) + +summary' :: Sig s opq +summary' = Element "summary" + +summary_ :: AFSig_ s opq +summary_ x = (\_ -> Element "summary" dats x) + +summary'_ :: Sig_ s opq +summary'_ x = Element "summary" dats x + +summary__ :: AFSig__ s opq +summary__ x = (\_ -> Element "summary" dats [txt x]) + +summary'__ :: Sig__ s opq +summary'__ x = Element "summary" dats [txt x] + + +sup :: AFSig s opq +sup x y = (\_ -> Element "sup" x y) + +sup' :: Sig s opq +sup' = Element "sup" + +sup_ :: AFSig_ s opq +sup_ x = (\_ -> Element "sup" dats x) + +sup'_ :: Sig_ s opq +sup'_ x = Element "sup" dats x + +sup__ :: AFSig__ s opq +sup__ x = (\_ -> Element "sup" dats [txt x]) + +sup'__ :: Sig__ s opq +sup'__ x = Element "sup" dats [txt x] + + +svg :: AFSig s opq +svg x y = (\_ -> Element "svg" x y) + +svg' :: Sig s opq +svg' = Element "svg" + +svg_ :: AFSig_ s opq +svg_ x = (\_ -> Element "svg" dats x) + +svg'_ :: Sig_ s opq +svg'_ x = Element "svg" dats x + +svg__ :: AFSig__ s opq +svg__ x = (\_ -> Element "svg" dats [txt x]) + +svg'__ :: Sig__ s opq +svg'__ x = Element "svg" dats [txt x] + + +table :: AFSig s opq +table x y = (\_ -> Element "table" x y) + +table' :: Sig s opq +table' = Element "table" + +table_ :: AFSig_ s opq +table_ x = (\_ -> Element "table" dats x) + +table'_ :: Sig_ s opq +table'_ x = Element "table" dats x + +table__ :: AFSig__ s opq +table__ x = (\_ -> Element "table" dats [txt x]) + +table'__ :: Sig__ s opq +table'__ x = Element "table" dats [txt x] + + +tbody :: AFSig s opq +tbody x y = (\_ -> Element "tbody" x y) + +tbody' :: Sig s opq +tbody' = Element "tbody" + +tbody_ :: AFSig_ s opq +tbody_ x = (\_ -> Element "tbody" dats x) + +tbody'_ :: Sig_ s opq +tbody'_ x = Element "tbody" dats x + +tbody__ :: AFSig__ s opq +tbody__ x = (\_ -> Element "tbody" dats [txt x]) + +tbody'__ :: Sig__ s opq +tbody'__ x = Element "tbody" dats [txt x] + + +td :: AFSig s opq +td x y = (\_ -> Element "td" x y) + +td' :: Sig s opq +td' = Element "td" + +td_ :: AFSig_ s opq +td_ x = (\_ -> Element "td" dats x) + +td'_ :: Sig_ s opq +td'_ x = Element "td" dats x + +td__ :: AFSig__ s opq +td__ x = (\_ -> Element "td" dats [txt x]) + +td'__ :: Sig__ s opq +td'__ x = Element "td" dats [txt x] + + +template :: AFSig s opq +template x y = (\_ -> Element "template" x y) + +template' :: Sig s opq +template' = Element "template" + +template_ :: AFSig_ s opq +template_ x = (\_ -> Element "template" dats x) + +template'_ :: Sig_ s opq +template'_ x = Element "template" dats x + +template__ :: AFSig__ s opq +template__ x = (\_ -> Element "template" dats [txt x]) + +template'__ :: Sig__ s opq +template'__ x = Element "template" dats [txt x] + + +textarea :: AFSig s opq +textarea x y = (\_ -> Element "textarea" x y) + +textarea' :: Sig s opq +textarea' = Element "textarea" + +textarea_ :: AFSig_ s opq +textarea_ x = (\_ -> Element "textarea" dats x) + +textarea'_ :: Sig_ s opq +textarea'_ x = Element "textarea" dats x + +textarea__ :: AFSig__ s opq +textarea__ x = (\_ -> Element "textarea" dats [txt x]) + +textarea'__ :: Sig__ s opq +textarea'__ x = Element "textarea" dats [txt x] + + +tfoot :: AFSig s opq +tfoot x y = (\_ -> Element "tfoot" x y) + +tfoot' :: Sig s opq +tfoot' = Element "tfoot" + +tfoot_ :: AFSig_ s opq +tfoot_ x = (\_ -> Element "tfoot" dats x) + +tfoot'_ :: Sig_ s opq +tfoot'_ x = Element "tfoot" dats x + +tfoot__ :: AFSig__ s opq +tfoot__ x = (\_ -> Element "tfoot" dats [txt x]) + +tfoot'__ :: Sig__ s opq +tfoot'__ x = Element "tfoot" dats [txt x] + + +th :: AFSig s opq +th x y = (\_ -> Element "th" x y) + +th' :: Sig s opq +th' = Element "th" + +th_ :: AFSig_ s opq +th_ x = (\_ -> Element "th" dats x) + +th'_ :: Sig_ s opq +th'_ x = Element "th" dats x + +th__ :: AFSig__ s opq +th__ x = (\_ -> Element "th" dats [txt x]) + +th'__ :: Sig__ s opq +th'__ x = Element "th" dats [txt x] + + +thead :: AFSig s opq +thead x y = (\_ -> Element "thead" x y) + +thead' :: Sig s opq +thead' = Element "thead" + +thead_ :: AFSig_ s opq +thead_ x = (\_ -> Element "thead" dats x) + +thead'_ :: Sig_ s opq +thead'_ x = Element "thead" dats x + +thead__ :: AFSig__ s opq +thead__ x = (\_ -> Element "thead" dats [txt x]) + +thead'__ :: Sig__ s opq +thead'__ x = Element "thead" dats [txt x] + + +time :: AFSig s opq +time x y = (\_ -> Element "time" x y) + +time' :: Sig s opq +time' = Element "time" + +time_ :: AFSig_ s opq +time_ x = (\_ -> Element "time" dats x) + +time'_ :: Sig_ s opq +time'_ x = Element "time" dats x + +time__ :: AFSig__ s opq +time__ x = (\_ -> Element "time" dats [txt x]) + +time'__ :: Sig__ s opq +time'__ x = Element "time" dats [txt x] + + +title :: AFSig s opq +title x y = (\_ -> Element "title" x y) + +title' :: Sig s opq +title' = Element "title" + +title_ :: AFSig_ s opq +title_ x = (\_ -> Element "title" dats x) + +title'_ :: Sig_ s opq +title'_ x = Element "title" dats x + +title__ :: AFSig__ s opq +title__ x = (\_ -> Element "title" dats [txt x]) + +title'__ :: Sig__ s opq +title'__ x = Element "title" dats [txt x] + + +tr :: AFSig s opq +tr x y = (\_ -> Element "tr" x y) + +tr' :: Sig s opq +tr' = Element "tr" + +tr_ :: AFSig_ s opq +tr_ x = (\_ -> Element "tr" dats x) + +tr'_ :: Sig_ s opq +tr'_ x = Element "tr" dats x + +tr__ :: AFSig__ s opq +tr__ x = (\_ -> Element "tr" dats [txt x]) + +tr'__ :: Sig__ s opq +tr'__ x = Element "tr" dats [txt x] + + +track :: AFSig s opq +track x y = (\_ -> Element "track" x y) + +track' :: Sig s opq +track' = Element "track" + +track_ :: AFSig_ s opq +track_ x = (\_ -> Element "track" dats x) + +track'_ :: Sig_ s opq +track'_ x = Element "track" dats x + +track__ :: AFSig__ s opq +track__ x = (\_ -> Element "track" dats [txt x]) + +track'__ :: Sig__ s opq +track'__ x = Element "track" dats [txt x] + + +tt :: AFSig s opq +tt x y = (\_ -> Element "tt" x y) + +tt' :: Sig s opq +tt' = Element "tt" + +tt_ :: AFSig_ s opq +tt_ x = (\_ -> Element "tt" dats x) + +tt'_ :: Sig_ s opq +tt'_ x = Element "tt" dats x + +tt__ :: AFSig__ s opq +tt__ x = (\_ -> Element "tt" dats [txt x]) + +tt'__ :: Sig__ s opq +tt'__ x = Element "tt" dats [txt x] + + +u :: AFSig s opq +u x y = (\_ -> Element "u" x y) + +u' :: Sig s opq +u' = Element "u" + +u_ :: AFSig_ s opq +u_ x = (\_ -> Element "u" dats x) + +u'_ :: Sig_ s opq +u'_ x = Element "u" dats x + +u__ :: AFSig__ s opq +u__ x = (\_ -> Element "u" dats [txt x]) + +u'__ :: Sig__ s opq +u'__ x = Element "u" dats [txt x] + + +ul :: AFSig s opq +ul x y = (\_ -> Element "ul" x y) + +ul' :: Sig s opq +ul' = Element "ul" + +ul_ :: AFSig_ s opq +ul_ x = (\_ -> Element "ul" dats x) + +ul'_ :: Sig_ s opq +ul'_ x = Element "ul" dats x + +ul__ :: AFSig__ s opq +ul__ x = (\_ -> Element "ul" dats [txt x]) + +ul'__ :: Sig__ s opq +ul'__ x = Element "ul" dats [txt x] + + +var :: AFSig s opq +var x y = (\_ -> Element "var" x y) + +var' :: Sig s opq +var' = Element "var" + +var_ :: AFSig_ s opq +var_ x = (\_ -> Element "var" dats x) + +var'_ :: Sig_ s opq +var'_ x = Element "var" dats x + +var__ :: AFSig__ s opq +var__ x = (\_ -> Element "var" dats [txt x]) + +var'__ :: Sig__ s opq +var'__ x = Element "var" dats [txt x] + + +video :: AFSig s opq +video x y = (\_ -> Element "video" x y) + +video' :: Sig s opq +video' = Element "video" + +video_ :: AFSig_ s opq +video_ x = (\_ -> Element "video" dats x) + +video'_ :: Sig_ s opq +video'_ x = Element "video" dats x + +video__ :: AFSig__ s opq +video__ x = (\_ -> Element "video" dats [txt x]) + +video'__ :: Sig__ s opq +video'__ x = Element "video" dats [txt x] + + +wbr :: (s -> Node s opq) +wbr = (\_ -> Element "br" dats []) + +txt :: String -> (s -> Node s opq) +txt t = (\_ -> TextNode t) + +txt' :: String -> Node s opq +txt' = TextNode + + +h1 :: AFSig s opq +h1 x y = (\_ -> Element "h1" x y) + +h1' :: Sig s opq +h1' = Element "h1" + +h1_ :: AFSig_ s opq +h1_ x = (\_ -> Element "h1" dats x) + +h1'_ :: Sig_ s opq +h1'_ x = Element "h1" dats x + +h1__ :: AFSig__ s opq +h1__ x = (\_ -> Element "h1" dats [txt x]) + +h1'__ :: Sig__ s opq +h1'__ x = Element "h1" dats [txt x] + + +h2 :: AFSig s opq +h2 x y = (\_ -> Element "h2" x y) + +h2' :: Sig s opq +h2' = Element "h2" + +h2_ :: AFSig_ s opq +h2_ x = (\_ -> Element "h2" dats x) + +h2'_ :: Sig_ s opq +h2'_ x = Element "h2" dats x + +h2__ :: AFSig__ s opq +h2__ x = (\_ -> Element "h2" dats [txt x]) + +h2'__ :: Sig__ s opq +h2'__ x = Element "h2" dats [txt x] + + +h3 :: AFSig s opq +h3 x y = (\_ -> Element "h3" x y) + +h3' :: Sig s opq +h3' = Element "h3" + +h3_ :: AFSig_ s opq +h3_ x = (\_ -> Element "h3" dats x) + +h3'_ :: Sig_ s opq +h3'_ x = Element "h3" dats x + +h3__ :: AFSig__ s opq +h3__ x = (\_ -> Element "h3" dats [txt x]) + +h3'__ :: Sig__ s opq +h3'__ x = Element "h3" dats [txt x] + + +h4 :: AFSig s opq +h4 x y = (\_ -> Element "h4" x y) + +h4' :: Sig s opq +h4' = Element "h4" + +h4_ :: AFSig_ s opq +h4_ x = (\_ -> Element "h4" dats x) + +h4'_ :: Sig_ s opq +h4'_ x = Element "h4" dats x + +h4__ :: AFSig__ s opq +h4__ x = (\_ -> Element "h4" dats [txt x]) + +h4'__ :: Sig__ s opq +h4'__ x = Element "h4" dats [txt x] + + +h5 :: AFSig s opq +h5 x y = (\_ -> Element "h5" x y) + +h5' :: Sig s opq +h5' = Element "h5" + +h5_ :: AFSig_ s opq +h5_ x = (\_ -> Element "h5" dats x) + +h5'_ :: Sig_ s opq +h5'_ x = Element "h5" dats x + +h5__ :: AFSig__ s opq +h5__ x = (\_ -> Element "h5" dats [txt x]) + +h5'__ :: Sig__ s opq +h5'__ x = Element "h5" dats [txt x] + + +h6 :: AFSig s opq +h6 x y = (\_ -> Element "h6" x y) + +h6' :: Sig s opq +h6' = Element "h6" + +h6_ :: AFSig_ s opq +h6_ x = (\_ -> Element "h6" dats x) + +h6'_ :: Sig_ s opq +h6'_ x = Element "h6" dats x + +h6__ :: AFSig__ s opq +h6__ x = (\_ -> Element "h6" dats [txt x]) + +h6'__ :: Sig__ s opq +h6'__ x = Element "h6" dats [txt x]
+ test/Spec.hs view
@@ -0,0 +1,102 @@+import Control.Monad +import Control.Monad.Reader +import Data.IORef +import Prelude hiding ( div ) +import Test.Hspec +import Web.Framework.Plzwrk +import Web.Framework.Plzwrk.MockJSVal +import Data.HashMap.Strict +import Web.Framework.Plzwrk.Tag(p_, txt, button, div'_) + +data MyState = MyState + { _name :: String + , _ctr :: Int + } + +main :: IO () +main = hspec $ do + describe "Element with basic state" $ do + let domF = + (\x y -> div'_ + [ p_ (take y $ repeat (txt (concat [x, show y]))) + , button + (pure dats' + { _simple = singleton "id" "incr" + , _handlers = singleton "click" + (\_ s -> pure $ s { _ctr = y + 1 }) + } + ) + [txt "Increase counter"] + , button + (pure dats' + { _simple = singleton "id" "decr" + , _handlers = singleton "click" + (\_ s -> pure $ s { _ctr = y - 1 }) + } + ) + [txt "Decrease counter"] + ] + ) + <$> _name + <*> _ctr + let state = MyState "Mike" 0 + it "Creates the correct DOM from the state" $ do + rf <- defaultInternalBrowser + mock <- makeMockBrowserWithContext rf + refToOldDom <- newIORef (OldStuff state Nothing) + parentNode <- getBody mock + newDom <- runReaderT + (reconcile refToOldDom + domF + parentNode + parentNode + Nothing + (Just $ hydrate state domF) + ) + mock + writeIORef refToOldDom (OldStuff state newDom) + childrenLevel0 <- (getChildren mock) parentNode + length childrenLevel0 `shouldBe` 1 + divtag <- (getTag mock) (head childrenLevel0) + divtag `shouldBe` "div" + childrenLevel1 <- (getChildren mock) (head childrenLevel0) + length childrenLevel1 `shouldBe` 3 + ptag <- (getTag mock) (head childrenLevel1) + ptag `shouldBe` "p" + childrenLevel2 <- (getChildren mock) (head childrenLevel1) + length childrenLevel2 `shouldBe` 0 + -- increment 4 times + (getElementById mock) "incr" + >>= maybe (error "Incr node does not exist") (click mock) + (getElementById mock) "incr" + >>= maybe (error "Incr node does not exist") (click mock) + (getElementById mock) "incr" + >>= maybe (error "Incr node does not exist") (click mock) + (getElementById mock) "incr" + >>= maybe (error "Incr node does not exist") (click mock) + parentNode' <- getBody mock + childrenLevel0' <- (getChildren mock) parentNode' + length childrenLevel0' `shouldBe` 1 + divtag' <- (getTag mock) (head childrenLevel0') + divtag' `shouldBe` "div" + childrenLevel1' <- (getChildren mock) (head childrenLevel0') + length childrenLevel1' `shouldBe` 3 + childrenLevel2' <- (getChildren mock) (head childrenLevel1') + length childrenLevel2' `shouldBe` 4 + content' <- mapM (textContent mock) childrenLevel2' + content' `shouldBe` (take 4 $ repeat "Mike4") + (getElementById mock) "decr" + >>= maybe (error "Incr node does not exist") (click mock) + (getElementById mock) "decr" + >>= maybe (error "Incr node does not exist") (click mock) + parentNode'' <- getBody mock + childrenLevel0'' <- (getChildren mock) parentNode'' + length childrenLevel0'' `shouldBe` 1 + divtag'' <- (getTag mock) (head childrenLevel0'') + divtag'' `shouldBe` "div" + childrenLevel1'' <- (getChildren mock) (head childrenLevel0'') + length childrenLevel1'' `shouldBe` 3 + childrenLevel2'' <- (getChildren mock) (head childrenLevel1'') + length childrenLevel2'' `shouldBe` 2 + content'' <- mapM (textContent mock) childrenLevel2'' + content'' `shouldBe` (take 2 $ repeat "Mike2")