Image captions in TinyMCE

I need to add captions to images with TinyMCE in Plone 5. Apparently, there is no way to do so at the moment. I only found this question on SO from Nov 25, and it appears support for captions was simply left out in Plone 5. I have not yet tried the suggestions in the answer, but I was wondering if there is any consensus on the current and future state of this feature.

3 Likes

Has someone already done this in a theme? (With diazo.)

I came across the need to have image captions and I'm currently investigating.

Current status: Looks like, we're not using the TinyMCE "image" Plugin but our own "ploneimage" plugin. The first has caption support build in, the latter not.

interesting that it got through all the accessibility testing that happened :frowning: @polyester?

<alt> tags are an accessibility requirement, image captions are not.

Wasn't the "Plone way" to read image caption from Image object's description? (Or was it title?) It could be done with Diazo, but it not sure about the performance hit (by making a plone.subrequest call via xslt document() for each image).

plone.outputfilters takes care of adding the caption (from the image's description field) to any img tag with class="captioned". So all that the tinymce plugin needs to do is provide a checkbox to toggle that class and a text input to edit the image's description field.

2 Likes

@davisagli Would you have sophisticated guess, would it be worth in performance to refactor plone.outputfilters from PortalTransforms into plone.transformchain (and reuse diazo lxmltree in UID and image captions transform)?

1 Like

I'm not sure that'd be a good thing performance-wise. The result of a PortalTransforms conversion is cached on a volatile attribute of the context for up to an hour, whereas the transform chain runs on the entire response each time it's served.

1 Like

This Diazo snippet does the trick:

    <replace css:content="section#content-core img:not([title=''])">
      <figure class="image-inline captioned">
        <xsl:copy-of select="." />
        <figcaption>
          <div class="captiontitle">
            <xsl:value-of select="./@title" />
          </div>
          <div class="captiondescription">
            <xsl:value-of select="./@alt" />
          </div>
        </figcaption>
      </figure>
      <xsl:apply-templates />
    </replace>

It only applies to images that have a title attribute set. It is good accessibility practice not to set title , so this attribute is a good candidate for an implicit toggle switch. You can still set alt (as you should) without triggering this rule. I'm using both title and alt just so I can have a caption with two independently stylable elements.
The not([title='']) is necessary because if a title is not set in TinyMCE, the title attribute is still added to the img, it just has an empty value.
Now you just have to apply your own CSS.

4 Likes

If anybody will ever need this.

Starting from the great @fulv example I used a slightly different version because the snippet above will always apply image-inline CSS class to the figure tag, while I want to copy CSS classes from the image (to be compatible with left/right alignment).

  <xsl:template css:match="section#content-core img:not([title=''])">
    <figure class="captioned">
      <xsl:attribute name="class">
        <xsl:value-of select="concat(@class,' captioned')"/>
      </xsl:attribute>
      <xsl:copy>
          <xsl:copy-of select="@*" />
          <xsl:apply-templates />
      </xsl:copy>
      <div class="image-caption">
        <xsl:value-of select="./@title" />
      </div>
    </figure>
  </xsl:template>

That might be a nice addition to (I'll make a PR):

More importantly, I suggest we move the following recipes into the above link:

A final note. On both solutions the resulting HTML can be invalid.

The figure tag is a block level element and can't be inside p created by TinyMCE. I still think that features like these must be solved by the WYSIWYG editor, not hacked through Diazo.

2 Likes

My hands will be full until possibly July 15. In the meantime you can get all the recipes here:

1 Like

Indeed, there is a problem when the <img> that the rule tries to wrap with <figure> is inside <p> or other block-level elements. Part of the problem is that you have no control over which parent element TinyMCE will choose for an image when you insert it through the UI.

In any case, after some real-world use, this is the version I am currently using:

<replace css:content="div#parent-fieldname-text img:not([alt=''])">
  <xsl:variable name="parenttd" select="ancestor::td" />
  <xsl:variable name="parentth" select="ancestor::th" />
  <xsl:choose>
    <xsl:when test="$parenttd or $parentth">
      <xsl:copy-of select="." />
    </xsl:when>
    <xsl:otherwise>
      <figure>
        <xsl:attribute name="class"><xsl:value-of select="concat(./@class, ' caption')" /></xsl:attribute>
        <xsl:copy-of select="." />
        <figcaption>
          <div class="captiontitle">
            <xsl:value-of select="./@title" />
          </div>
          <div class="captiondescription">
            <xsl:value-of select="./@alt" />
          </div>
        </figcaption>
      </figure>
    </xsl:otherwise>
  </xsl:choose>
  <xsl:apply-templates />
</replace>

I made a couple of changes:

  1. the class on figure is now the same as the class on the img, plus ' caption'
  2. The alt attribute is the one deciding whether to use a caption or not, instead of the title. This is because image content items often have their title field automatically set to the filename of the image, and TinyMCE will use that, if present. If that's the case, and you don't want to use the title field, just put a space character in the title field in TinyMCE's insert/edit image dialog.
  3. Users of the site previously tried to "imitate" captions wrapping images in html tables, so I'm leaving those alone. That's what the variables parenttd and parentth are doing.
3 Likes

Just following up ... did you end up making the PR to move that to http://docs.diazo.org/en/latest/recipes/ ?

@davilima6 added it, but @lrowe then reverted it:

Although the version that @davilima6 added was not the latest one in this thread. I can't remember if there was any discussion about it outside of this.

See the discussion on the original commit: https://github.com/plone/diazo/commit/cb4bfe640e6e016419423659e30064a2e391c970

davilima6 commented on cb4bfe6 on 30 Jun 2016
I made this commit in master by accident, it was meant to be in a feature branch. I already see two small typos I need to fix. Should I revert on master and create a proper PR or just make a PR with the typos?

lrowe commented on cb4bfe6 on 11 Oct 2016
I've reverted this on master since it broke the tests. Recipes are tested to ensure they continue to work.

Ah, thanks! I thought there had been something, but I couldn't find it.

some brainstorming and totally unrelated:

It can sometimes be a bit 'fiddly' to change an image in a page ( yes, right click and changing the url is not sooo much work).

A diazo rule that added 'edit' link to the image could be useful (?)

Plone Foundation Code of Conduct