miso 1.6.0.0 → 1.7.0.0
raw patch · 12 files changed
+157/−65 lines, 12 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Miso.Html: [VTextRaw] :: {vText :: Text " Raw TextNode content"} -> VTree action
+ Miso.Html: a_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: abbr_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: address_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: article_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: aside_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: audio_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: b_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: bdi_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: bdo_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: blockquote_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: body_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: br_ :: [Attribute action] -> View action
+ Miso.Html: button_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: canvas_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: caption_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: center_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: cite_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: code_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: col_ :: [Attribute action] -> View action
+ Miso.Html: colgroup_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: datalist_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: dd_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: del_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: details_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: dfn_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: div_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: dl_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: dt_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: em_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: embed_ :: [Attribute action] -> View action
+ Miso.Html: fieldset_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: figcaption_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: figure_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: footer_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: form_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: h1_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: h2_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: h3_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: h4_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: h5_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: h6_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: header_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: hr_ :: [Attribute action] -> View action
+ Miso.Html: i_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: iframe_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: img_ :: [Attribute action] -> View action
+ Miso.Html: input_ :: [Attribute action] -> View action
+ Miso.Html: ins_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: kbd_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: keygen_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: label_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: legend_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: liKeyed_ :: Key -> [Attribute action] -> [View action] -> View action
+ Miso.Html: li_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: link_ :: [Attribute action] -> View action
+ Miso.Html: main_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: mark_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: math_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: menu_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: menuitem_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: meter_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: nav_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: nodeHtml :: MisoString -> [Attribute action] -> [View action] -> View action
+ Miso.Html: nodeHtmlKeyed :: MisoString -> Key -> [Attribute action] -> [View action] -> View action
+ Miso.Html: object_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: ol_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: optgroup_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: option_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: output_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: p_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: param_ :: [Attribute action] -> View action
+ Miso.Html: pre_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: progress_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: q_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: rp_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: rt_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: ruby_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: s_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: samp_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: script_ :: [Attribute action] -> MisoString -> View action
+ Miso.Html: section_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: select_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: small_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: source_ :: [Attribute action] -> View action
+ Miso.Html: span_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: strong_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: sub_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: summary_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: sup_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: table_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: tbody_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: td_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: textarea_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: tfoot_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: th_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: thead_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: time_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: trKeyed_ :: Key -> [Attribute action] -> [View action] -> View action
+ Miso.Html: tr_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: track_ :: [Attribute action] -> View action
+ Miso.Html: u_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: ul_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: var_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: video_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html: wbr_ :: [Attribute action] -> View action
+ Miso.Html.Element: style_ :: [Attribute action] -> MisoString -> View action
- Miso.Html.Element: script_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: script_ :: [Attribute action] -> MisoString -> View action
Files
- README.md +16/−14
- exe/Main.hs +2/−1
- frontend-src/Miso.hs +1/−1
- frontend-src/Miso/Html/Internal.hs +8/−1
- frontend-src/Miso/Types.hs +9/−0
- ghc-src/Miso/Html/Internal.hs +29/−1
- ghcjs-ffi/Miso/FFI.hs +3/−3
- jsaddle-ffi/Miso/FFI.hs +3/−12
- jsbits/isomorphic.js +60/−26
- miso.cabal +1/−1
- src/Miso/Html.hs +2/−2
- src/Miso/Html/Element.hs +23/−3
README.md view
@@ -130,8 +130,8 @@ ```nix with (import (builtins.fetchTarball {- url = "https://github.com/dmjio/miso/archive/561ffad.tar.gz";- sha256 = "1wwzckz2qxb873wdkwqmx9gmh0wshcdxi7gjwkba0q51jnkfdi41";+ url = "https://github.com/dmjio/miso/archive/ea25964565074e73d4052b56b60b6e101fa08bc5.tar.gz";+ sha256 = "1yb9yvc0ln4yn1jk2k5kwwa1s32310abawz40yd8cqqkm1z7w6wg"; }) {}); pkgs.haskell.packages.ghcjs.callCabal2nix "app" ./. {} ```@@ -179,10 +179,10 @@ ## Examples ### TodoMVC- - [Link](https://todo-mvc.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/examples/todo-mvc/Main.hs)+ - [Link](http://todo-mvc.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/examples/todo-mvc/Main.hs) ### Flatris- - [Link](https://flatris.haskell-miso.org/) / [Source](https://github.com/ptigwe/hs-flatris/)+ - [Link](http://flatris.haskell-miso.org/) / [Source](https://github.com/ptigwe/hs-flatris/) ### 2048 - [Link](http://2048.haskell-miso.org/) / [Source](https://github.com/ptigwe/hs2048/)@@ -191,25 +191,25 @@ - [Link](http://snake.haskell-miso.org/) / [Source](https://github.com/lbonn/miso-snake) ### Mario- - [Link](https://mario.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/examples/mario/Main.hs)+ - [Link](http://mario.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/examples/mario/Main.hs) ### Miso Plane (Flappy Birds)- - [Link](https://miso-plane.lermex.net/) / [Source](https://github.com/Lermex/miso-plane)+ - [Link](http://miso-plane.lermex.net/) / [Source](https://github.com/Lermex/miso-plane) ### Websocket- - [Link](https://websocket.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/examples/websocket/Main.hs)+ - [Link](http://websocket.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/examples/websocket/Main.hs) ### SSE- - [Link](https://sse.haskell-miso.org/) / [Client](https://github.com/dmjio/miso/blob/master/examples/sse/client/Main.hs) / [Server](https://github.com/dmjio/miso/blob/master/examples/sse/server/Main.hs)+ - [Link](http://sse.haskell-miso.org/) / [Client](https://github.com/dmjio/miso/blob/master/examples/sse/client/Main.hs) / [Server](https://github.com/dmjio/miso/blob/master/examples/sse/server/Main.hs) ### XHR- - [Link](https://xhr.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/examples/xhr/Main.hs)+ - [Link](http://xhr.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/examples/xhr/Main.hs) ### Router- - [Link](https://router.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/examples/router/Main.hs)+ - [Link](http://router.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/examples/router/Main.hs) ### SVG- - [Link](https://svg.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/examples/svg/Main.hs)+ - [Link](http://svg.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/examples/svg/Main.hs) ### Canvas 2D - [Link](http://canvas.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/examples/canvas2d/Main.hs)@@ -218,13 +218,13 @@ - [Link](http://threejs.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/examples/three/Main.hs) ### Simple- - [Link](https://simple.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/exe/Main.hs)+ - [Link](http://simple.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/exe/Main.hs) ### File Reader- - [Link](https://file-reader.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/examples/file-reader/Main.hs)+ - [Link](http://file-reader.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/examples/file-reader/Main.hs) ### WebVR- - [Link](https://fizruk.github.io/fpconf-2017-talk/miso-aframe-demo/dist/demo.jsexe/index.html) / [Source](https://github.com/fizruk/miso-aframe)+ - [Link](http://fizruk.github.io/fpconf-2017-talk/miso-aframe-demo/dist/demo.jsexe/index.html) / [Source](https://github.com/fizruk/miso-aframe) ## Haddocks @@ -269,6 +269,7 @@ events = defaultEvents -- default delegated events subs = [] -- empty subscription list mountPoint = Nothing -- mount point for application (Nothing defaults to 'body')+ logLevel = Off -- used during prerendering to see if the VDOM and DOM are in sync (only applies to `miso` function) -- | Updates model, optionally introduces side effects updateModel :: Action -> Model -> Effect Action Model@@ -342,6 +343,7 @@ events = defaultEvents -- default delegated events subs = [] -- empty subscription list mountPoint = Nothing -- mount point for application (Nothing defaults to 'body')+ logLevel = Off -- used during prerendering to see if the VDOM and DOM are in sync (only applies to `miso` function) -- | Updates model, optionally introduces side effects updateModel :: Action -> Transition Action Model ()
exe/Main.hs view
@@ -37,7 +37,7 @@ -- | Entry point for a miso application main :: IO ()-main = runApp $ startApp App {..}+main = runApp $ miso $ \_ -> App {..} where initialAction = SayHelloWorld -- initial action to be executed on application load model = 0 -- initial model@@ -46,6 +46,7 @@ events = defaultEvents -- default delegated events subs = [] -- empty subscription list mountPoint = Nothing -- mount point for application (Nothing defaults to 'body')+ logLevel = Off -- Used to copy DOM into VDOM, applies only to `miso` function -- | Updates model, optionally introduces side effects updateModel :: Action -> Model -> Effect Action Model
frontend-src/Miso.hs view
@@ -139,7 +139,7 @@ VTree (OI.Object iv) <- flip runView writeEvent initialView mountEl <- mountElement mountPoint -- Initial diff can be bypassed, just copy DOM into VTree- copyDOMIntoVTree mountEl iv+ copyDOMIntoVTree (logLevel == DebugPrerender) mountEl iv let initialVTree = VTree (OI.Object iv) -- Create virtual dom, perform initial diff liftIO (newIORef initialVTree)
frontend-src/Miso/Html/Internal.hs view
@@ -34,6 +34,7 @@ -- * Smart `View` constructors , node , text+ , textRaw -- * Key patch internals , Key (..) , ToKey (..)@@ -130,7 +131,9 @@ set "tag" tag vnode set "key" key vnode setAttrs vnode sink- flip (set "children") vnode =<< ghcjsPure . jsval =<< setKids sink+ flip (set "children") vnode+ =<< ghcjsPure . jsval+ =<< setKids sink pure $ VTree vnode where setAttrs vnode sink =@@ -162,6 +165,10 @@ set "type" ("vtext" :: JSString) vtree set "text" t vtree pure $ VTree vtree++-- | For parity with server-side rendering. Don't use directly.+textRaw :: MisoString -> View m+textRaw = text -- | `IsString` instance instance IsString (View a) where
frontend-src/Miso/Types.hs view
@@ -9,6 +9,7 @@ ---------------------------------------------------------------------------- module Miso.Types ( App (..)+ , LogLevel (..) , Effect , Sub @@ -53,7 +54,15 @@ -- ^ Initial action that is run after the application has loaded , mountPoint :: Maybe MisoString -- ^ Id of the root element for DOM diff. If 'Nothing' is provided, the entire document body is used as a mount point.+ , logLevel :: LogLevel+ -- ^ Display warning messages when prerendering if the DOM and VDOM are not in sync. }++-- | Optional Logging for debugging miso internals (useful to see if prerendering is successful)+data LogLevel+ = Off+ | DebugPrerender+ deriving (Show, Eq) -- | A monad for succinctly expressing model transitions in the 'update' function. --
ghc-src/Miso/Html/Internal.hs view
@@ -30,6 +30,7 @@ -- * Smart `View` constructors , node , text+ , textRaw -- * Key patch internals , Key (..) , ToKey (..)@@ -74,6 +75,14 @@ } -> VTree action VText :: { vText :: Text -- ^ TextNode content } -> VTree action+ -- Invariant: To avoid complexity with collapsing mixed VText and+ -- VTextRaw nodes, VTextRaw node is always the only child.+ -- That's not a big limitation, since the intended purpose is to be able+ -- to use <style> and <script> tags. That means we can't support HTML+ -- entities like with VTextRaw, but the same can be achieved with+ -- Unicode.+ VTextRaw :: { vText :: Text -- ^ Raw TextNode content+ } -> VTree action deriving Functor instance Show (VTree action) where@@ -84,6 +93,8 @@ toHtmlRaw = L.toHtml toHtml (VText x) | T.null x = L.toHtml (" " :: MisoString) | otherwise = L.toHtml x+ toHtml (VTextRaw x) | T.null x = L.toHtml (" " :: MisoString)+ | otherwise = L.toHtmlRaw x toHtml VNode{..} = let noEnd = ["img", "input", "br", "hr", "meta"]@@ -114,8 +125,21 @@ , "autocomplete" ] toTag = T.toLower- kids = foldMap L.toHtml vChildren+ kids+ = foldMap L.toHtml+ . V.fromList+ . collapseSiblingTextNodes+ . V.toList+ $ vChildren +collapseSiblingTextNodes :: [VTree a] -> [VTree a]+collapseSiblingTextNodes [] = []+collapseSiblingTextNodes (VText x : VText y : xs) =+ collapseSiblingTextNodes (VText (x <> y) : xs)+-- VTextRaw is the only child, so no need to collapse.+collapseSiblingTextNodes (x:xs) =+ x : collapseSiblingTextNodes xs+ -- | Helper for turning JSON into Text -- Object, Array and Null are kind of non-sensical here toHtmlFromJSON :: Value -> Text@@ -170,6 +194,10 @@ -- | `VText` creation text :: MisoString -> View action text = View . VText++-- | `VTextRaw` creation. Don't use directly+textRaw :: MisoString -> View action+textRaw = View . VTextRaw -- | `IsString` instance instance IsString (View a) where
ghcjs-ffi/Miso/FFI.hs view
@@ -121,7 +121,6 @@ foreign import javascript unsafe "$1.preventDefault();" eventPreventDefault :: JSVal -> IO () - -- | Window object foreign import javascript unsafe "$r = window;" getWindow :: IO JSVal@@ -242,9 +241,10 @@ -- | Copies DOM pointers into virtual dom -- entry point into isomorphic javascript-foreign import javascript unsafe "window['copyDOMIntoVTree']($1, $2);"+foreign import javascript unsafe "window['copyDOMIntoVTree']($1, $2, $3);" copyDOMIntoVTree- :: JSVal -- ^ mountPoint element of the isomorphic app+ :: Bool -- ^ Display debugging information when pre-rendering+ -> JSVal -- ^ mountPoint element of the isomorphic app -> JSVal -- ^ VDom object -> IO ()
jsaddle-ffi/Miso/FFI.hs view
@@ -18,16 +18,12 @@ , objectToJSVal , ghcjsPure , syncPoint- , addEventListener , windowAddEventListener- , windowInnerHeight , windowInnerWidth- , eventPreventDefault , eventStopPropagation- , now , consoleLog , consoleLogJSVal@@ -40,19 +36,14 @@ , getDoc , getElementById , diff'- , integralToJSString , realFloatToJSString , jsStringToDouble- , delegateEvent- , copyDOMIntoVTree- , swapCallbacks , releaseCallbacks , registerCallback- , focus , blur , scrollIntoView@@ -220,7 +211,7 @@ delegateEvent :: JSVal -> JSVal -> JSM JSVal -> JSM () delegateEvent mountPoint events getVTree = do- cb' <- function $ \_ _ [continuation] -> do+ cb' <- asyncFunction $ \_ _ [continuation] -> do res <- getVTree _ <- call continuation global res pure ()@@ -231,8 +222,8 @@ -- | Copies DOM pointers into virtual dom -- entry point into isomorphic javascript-copyDOMIntoVTree :: JSVal -> JSVal -> JSM ()-copyDOMIntoVTree mountPoint a = () <$ jsg2 "copyDOMIntoVTree" mountPoint a+copyDOMIntoVTree :: Bool -> JSVal -> JSVal -> JSM ()+copyDOMIntoVTree logLevel mountPoint a = () <$ jsg3 "copyDOMIntoVTree" logLevel mountPoint a -- TODO For now, we do not free callbacks when compiling with JSaddle
jsbits/isomorphic.js view
@@ -1,19 +1,57 @@ window = typeof window === 'undefined' ? {} : window;-window['copyDOMIntoVTree'] = function copyDOMIntoVTree(mountPoint, vtree, doc) {+window['collapseSiblingTextNodes'] = function collapseSiblingTextNodes(vs) {+ if (!vs) { return []; }+ var ax = 0, adjusted = vs.length > 0 ? [vs[0]] : [];+ for (var ix = 1; ix < vs.length; ix++) {+ if (adjusted[ax]['type'] === 'vtext' && vs[ix]['type'] === 'vtext') {+ adjusted[ax]['text'] += vs[ix]['text'];+ continue;+ }+ adjusted[++ax] = vs[ix];+ }+ return adjusted;+}++window['copyDOMIntoVTree'] = function copyDOMIntoVTree(logLevel,mountPoint, vtree, doc) { if (!doc) { doc = window.document; }- var node = mountPoint ? mountPoint.firstChild : doc.body.firstChild;- if (!window['walk'](vtree, node, doc)) {- console.warn('Could not copy DOM into virtual DOM, falling back to diff');+ var mountChildIdx = 0, node;+ // If script tags are rendered first in body, skip them.+ if (!mountPoint) {+ if (doc.body.childNodes.length > 0) {+ node = doc.body.firstChild;+ } else {+ node = doc.body.appendChild (doc.createElement('div'));+ }+ } else if (mountPoint.childNodes.length === 0) {+ node = mountPoint.appendChild (doc.createElement('div'));+ } else {+ while (mountPoint.childNodes[mountChildIdx].localName === 'script' || mountPoint.childNodes[mountChildIdx].nodeType === Node.TEXT_NODE){+ mountChildIdx++;+ }+ node = mountPoint.childNodes[mountChildIdx];+ }++ if (!window['walk'](logLevel,vtree, node, doc)) {+ if (logLevel) {+ console.warn('Could not copy DOM into virtual DOM, falling back to diff');+ } // Remove all children before rebuilding DOM- while (node.firstChild)- node.removeChild(node.lastChild);- window['diff'](null, vtree, node, doc);+ while (node.firstChild) node.removeChild(node.lastChild);+ vtree['domRef'] = node;+ window['populate'](null, vtree, doc); return false; }+ if (logLevel) {+ console.info ('Successfully prendered page');+ } return true; } -window['walk'] = function walk(vtree, node, doc) {+window['diagnoseError'] = function diagnoseError(logLevel, vtree, node) {+ if (logLevel) console.warn('VTree differed from node', vtree, node);+}++window['walk'] = function walk(logLevel, vtree, node, doc) { // This is slightly more complicated than one might expect since // browsers will collapse consecutive text nodes into a single text node. // There can thus be fewer DOM nodes than VDOM nodes.@@ -25,35 +63,31 @@ // Fire onCreated events as though the elements had just been created. window['callCreated'](vtree); + vtree.children = window['collapseSiblingTextNodes'](vtree.children); for (var i = 0; i < vtree.children.length; i++) { vdomChild = vtree['children'][i]; domChild = node.childNodes[i];+ if (!domChild) {+ window['diagnoseError'](logLevel,vdomChild, domChild);+ return false;+ } if (vdomChild.type === 'vtext') {- if (domChild.nodeType !== Node.TEXT_NODE) return false;+ if (domChild.nodeType !== Node.TEXT_NODE) {+ window['diagnoseError'](logLevel, vdomChild, domChild);+ return false;+ } if (vdomChild['text'] === domChild.textContent) { vdomChild['domRef'] = domChild; } else {- var len = vdomChild.text.length,- domNodeText = domChild.textContent.substring(0, len);- if (domNodeText !== vdomChild.text) return false;-- // There are more VDOM nodes than DOM nodes- // Create new DOM node to ensure synchrony between VDom and DOM- var partialTxt = doc.createTextNode(domNodeText);- node.insertBefore(partialTxt, domChild);- vdomChild['domRef'] = partialTxt;- domChild.textContent = domChild.textContent.substring(len);- }+ window['diagnoseError'](logLevel, vdomChild, domChild);+ return false;+ } } else { if (domChild.nodeType !== Node.ELEMENT_NODE) return false;- window['walk'](vdomChild, domChild, doc);+ vdomChild['domRef'] = domChild;+ if(!window['walk'](logLevel, vdomChild, domChild, doc)) return false; }- }- // After walking the sizes of VDom and DOM should be equal- // Otherwise there are DOM nodes unaccounted for- if (vtree.children.length !== node.childNodes.length) return false;- return true; }
miso.cabal view
@@ -1,5 +1,5 @@ name: miso-version: 1.6.0.0+version: 1.7.0.0 category: Web, Miso, Data Structures license: BSD3 license-file: LICENSE
src/Miso/Html.hs view
@@ -34,7 +34,7 @@ , module Miso.Html.Property ) where -import Miso.Html.Element+import Miso.Html.Element hiding (style_) import Miso.Html.Event-import Miso.Html.Internal+import Miso.Html.Internal hiding (textRaw) import Miso.Html.Property hiding (form_)
src/Miso/Html/Element.hs view
@@ -52,6 +52,7 @@ , math_ , script_ , link_+ , Miso.Html.Element.style_ -- * Inputs , select_ , option_@@ -484,9 +485,28 @@ -- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/q q_ :: [Attribute action] -> [View action] -> View action q_ = nodeHtml "q"--- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script-script_ :: [Attribute action] -> [View action] -> View action-script_ = nodeHtml "script" -- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link link_ :: [Attribute action] -> View action link_ = flip (nodeHtml "link") []+-- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/style+-- This takes the raw text to be put in the style tag.+-- That means that if any part of the text is not trusted there's+-- a potential CSS injection. Read more at+-- https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/11-Client_Side_Testing/05-Testing_for_CSS_Injection+--+-- You can also easily shoot yourself in the foot with something like:+--+-- style_ [] "</style>"+style_ :: [Attribute action] -> MisoString -> View action+style_ attrs rawText = node HTML "style" Nothing attrs [textRaw rawText]+-- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script+-- This takes the raw text to be put in the script tag.+-- That means that if any part of the text is not trusted there's+-- a potential JavaScript injection. Read more at+-- https://owasp.org/www-community/attacks/xss/+--+-- You can also easily shoot yourself in the foot with something like:+--+-- script_ [] "</script>"+script_ :: [Attribute action] -> MisoString -> View action+script_ attrs rawText = node HTML "script" Nothing attrs [textRaw rawText]