infotexture / dita-bootstrap

DITA Open Toolkit plug-in for HTML5 output with extensible Bootstrap style
https://infotexture.github.io/dita-bootstrap
Apache License 2.0
16 stars 10 forks source link

Passing HTML data attributes #207

Open lief-erickson opened 2 months ago

lief-erickson commented 2 months ago

Looking for some guidance about best practices.

Within the context of this plugin or any of its related plugins, is there a general mechanism to pass data-attributes, perhaps through @otherprops, similar to what is done with parallax or from the dita-bootstrap.extension plugin?

This is the target HTML we're attempting to get:

<span data-fancy-text='{ "effect": "slide", "direction": "right", "color": "#ffe400", 
"speed": 100, "string": ["some", "fancy", "text"], "duration": 2500 }'>some fancy text</span>

and

<div data-anime='{ "el": "childs", "translateY": [30, 0], "opacity": [0,1], "duration": 600, 
"delay": 0, "staggervalue":200, "easing": "easeOutQuad" }'>
:
:
</div>

Notice that the @data-* values are JSON, which is not possible to put into @otherprops. Instead of @otherprops, what if <data> was used?

<ph otherprops="data-fancy-text">
     <data>'{ "effect": "slide", "direction": "right", "color": "#ffe400", 
     "speed": 100, "string": ["some", "fancy", "text"], "duration": 2500 }'</data>
      some fancy text</ph>

<div otherprops="data-anime">
     <data>'{ "el": "childs", "translateY": [30, 0], "opacity": [0,1], "duration": 600, 
      "delay": 0, "staggervalue":200, "easing": "easeOutQuad" }'</data>
:
:
</div>

Aside: @otherprops is not allowed on <title>.

lief-erickson commented 2 months ago

Here's my current thought. It works for <ph> but not for <div>. It needs to be a a general or generic-enough solution that would work for any element.

~~

<span>
  <xsl:attribute name="{$attributeName}">
    <xsl:value-of select="data"/>
  </xsl:attribute>
  <xsl:value-of select="text()"/>
</span>

</xsl:template>~~

Sometimes posting on the interwebs helps work through the problem.

This appears to work in a variety of situations. Feedback appreciated, especially from @jason-fox and/or @infotexture.

  <xsl:template match="*[@otherprops][data]" mode="commonattributes">
    <xsl:variable name="attributeName" select="@otherprops"/>
    <xsl:attribute name="{$attributeName}">
      <xsl:value-of select="data"/>
    </xsl:attribute>
  </xsl:template>

If this is a good approach, could it be easily extended to additional Bootstrap components or features not yet part of this family of plugins?

My quibble is now the JSON in the HTML is rendered with &#34; rather than ".

{ &#34;effect&#34;: &#34;slide&#34;, &#34;direction&#34;: &#34;right&#34;, &#34;color&#34;: &#34;#ffe400&#34;, &#34;speed&#34;: 100, &#34;duration&#34;: 2500 }
jason-fox commented 2 months ago

My quibble is now the JSON in the HTML is rendered with " rather than ".

Just use disable-output-escaping="yes"

<xsl:template match="*[@otherprops][data]" mode="commonattributes">
    <xsl:variable name="attributeName" select="@otherprops"/>
    <xsl:attribute name="{$attributeName}">
      <xsl:value-of select="data" disable-output-escaping="yes" />
    </xsl:attribute>
</xsl:template>

If you are worrying specifically about &#34; - you can't easily deal with this as you can't place an unescaped quote inside a quoted attribute.

jason-fox commented 2 months ago

In your case I would probably just create a specialism of the <data> element - you could set the name of the attribute to match the attribute you want to create and legitimately use props to define the type of processing to be done.

<ph>
  <data name="data-anime" props="data-attribute">
    { "el": "childs", "translateY": [30, 0], "opacity": [0,1], "duration": 600,
      "delay": 0, "staggervalue":200, "easing": "easeOutQuad" }
   </data>
    Text goes here....
</ph>

Something like this:

<xsl:template match="*[contains(@class, ' topic/data ') and contains(@props, 'data-attribute')]">
    <xsl:attribute name="@name">
      <xsl:value-of select="." disable-output-escaping="yes" />
    </xsl:attribute>
</xsl:template>
jason-fox commented 2 months ago

I tend to use otherprops because my attributes are simple key-values and compared to something like:

<section outputclass="parallax py-6 px-4 text-white">
  <data name="data-img-src" props="data-attribute">...</data>
  <data name="data-speed" props="data-attribute">0.3</data>
  Text goes here ...
</section>  

I think combining all the data-attributes in one place is shorter and easier to read:

<section outputclass="parallax py-6 px-4 text-white" otherprops="data-img-src(...) data-speed(0.3)">
  Text goes here ...
</section>  

I suppose it would be possible to amend existing templates to cover something like this.