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 но, опять же, это внутренний тип и конструктор.

Другие вопросы по тегам