Blaze-html类属性链接/追加/连接?

时间:2014-09-15 07:51:46

标签: html haskell blaze-html

我一直在研究一些快速增长的基于Haskell的Web应用程序,并且发现自己在这个问题上陷入困境。假设我有一些我在代码中早期定义的模板:

{-# LANGUAGE OverloadedStrings #-}
import Text.Blaze.Html5
import Text.Blaze.Html5.Attributes
import qualified Text.Blaze.Html5 as H
import qualified Text.Blaze.Html5.Attributes as A

foo = H.div ! class_ "foo"

以后,我决定使用foo,但稍加非破坏性修正案:

bar = foo ! class_ "bar" -- this should add bar to the classes available, imo

但是,当我渲染html时,这是我得到的结果:

import Text.Blaze.Html.Renderer.String

λ: renderHtml $ bar "baz"


↪ "<div class=\"foo\" class=\"bar\"></div>"

毕竟这是 monad !有没有什么办法可以将这种逻辑整合到blaze-html中?或者这超出了模板框架的范围?有没有任何选择方法(比如jQuery),这样我就可以做一些......

bar' = do
  classes <- classesOf foo
  H.div ! class_ (classes ++ " bar")

有没有人找到解决方法? Haskell有没有任何类型辅助的Html工具?这真让我摸不着头脑,想出了可怕的想法......

1 个答案:

答案 0 :(得分:1)

TL; DR :当前版本的blaze不支持monoidal属性操作。

技术细节

问题

Attribute是一个新类型的包装器:

newtype Attribute = Attribute (forall a. MarkupM a -> MarkupM a)

大多数(X)HTML属性都是使用Text.Blaze.Internal.attribute

创建的
attribute :: Tag             -- ^ Raw key
      -> Tag             -- ^ Shared key string for the HTML attribute.
      -> AttributeValue  -- ^ Value for the HTML attribute.
      -> Attribute       -- ^ Resulting HTML attribute.
attribute rawKey key value = Attribute $
    AddAttribute (unTag rawKey) (unTag key) (unAttributeValue value)

其中AddAttributeMarkupM's个构造函数之一:

data MarkupM a
    = {- ... -}
    -- | Add an attribute to the inner HTML. Raw key, key, value, HTML to
    -- receive the attribute.
    | AddAttribute StaticString StaticString ChoiceString (MarkupM a)
      {- ... -}

现在,来自Attributable(!)基本上会应用Attribute。因此,如果属性foo和属性bar,则tag ! bar ! foofoo $ bar $ tag相同。渲染器稍后展开AddAttribute构造函数:

go attrs (AddAttribute _ key value h) =
    go (B.copyByteString (getUtf8ByteString key)
        `mappend` fromChoiceString value
        `mappend` B.fromChar '"'
        `mappend` attrs) h

解决方案

为了实现所需的行为,您需要进一步推迟属性渲染并在中间数据结构中收集属性,例如Map ChoiceString AttributeValue

但是,请注意,如果您要创建自己的渲染器,此帖子中的所有类型都在Text.Blaze.Internal

的答案

  

毕竟这是一个单子!

不,不是,它不符合monad法律。

  

我们有什么方法可以将这种逻辑整合到blaze-html中吗?

见上文,但请记住,内部API可能会发生变化。

  

或者超出了模板框架的范围?

显然,它至少超出了大火的范围。此外,我不知道额外的Map是否会引入性能问题,这可能会消除大火的“快速”部分。

  

有没有任何选择方法(比如jQuery),这样我就可以做一些......

见上文,MarkupM不是真正的monad。您可以解开构造函数以获取正确的AddAttributes,但同样,这是一个内部类型和构造函数。