Blaze-html атрибуты цепочки / добавления / объединения?
Я работал над некоторыми быстро растущими веб-приложениями на основе Haskell, и я столкнулся с проблемой этой проблемы. Предположим, у меня есть шаблон, который я определил в начале своего кода:
{-# 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>"
В конце концов, это монада! Есть ли способ интегрировать такую логику в Blaze-HTML? Или это выходит за рамки шаблонов? Существуют ли какие-либо методы выделения (например, jQuery), чтобы я мог что-то сделать по аналогии с...
bar' = do
classes <- classesOf foo
H.div ! class_ (classes ++ " bar")
Кто-нибудь нашел способ обойти это? Есть ли в Haskell инструменты Html с поддержкой типов? Это действительно заставляет меня чесать голову и придумывать ужасные идеи...
1 ответ
TL; DR: текущая версия Blaze не поддерживает манипулирование моноидальными атрибутами.
Технические детали
проблема
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)
где AddAttribute
один из MarkupM
конструкторы:
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 ! foo
такой же как foo $ 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
если вы хотите создать свой собственный рендерер.
ответы
В конце концов, это монада!
Нет, это не так, это не следует законам монады.
Есть ли способ интегрировать такую логику в Blaze-HTML?
Смотрите выше, но имейте в виду, что внутренний API может измениться.
Или это выходит за рамки шаблонов?
По-видимому, это, по крайней мере, выходит за рамки пламени. Кроме того, я не буду ли дополнительный Map
представит проблемы с производительностью, которые могут отменить "невероятно быструю" часть пламени.
Существуют ли какие-либо методы выделения (например, jQuery), чтобы я мог что-то сделать по аналогии с...
Смотри выше, MarkupM
не настоящая монада. Вы можете распутать конструкторы, чтобы добраться до правильных AddAttributes
но, опять же, это внутренний тип и конструктор.