8

I have the following mark-up in a rich text field in Tridion:

<a href="#" class="cta-button-secondary">My text</a>

I have filtering XSLT on the field that transforms the mark-up into this (splitting the class and injecting a <span>):

<a href="#" class="cta-button secondary"><span>My text</span></a>

This works as expected and renders correctly. However, if I go back into the rich text editor and add a linebreak after the link in design view, the rich text editor moves the <span> from inside the <a> to outside resulting in the following mark-up:

<span><a href="#" class="cta-button secondary">My Text</a></span>

I assume this is because the rich text editor doesn't like tags within the <a>. How can I override this behaviour so that my mark-up is not broken?

Filtering XSLT:

<stylesheet xmlns="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <output omit-xml-declaration="yes" method="xml" cdata-section-elements="script"></output>
    <template match="/ | node() | @*">
        <copy>
            <apply-templates select="node() | @*"></apply-templates>
        </copy>
    </template>
    <template match="*[      (self::br or self::p or self::div)     and      normalize-space(translate(., &apos; &apos;, &apos;&apos;)) = &apos;&apos;     and      not(@*)     and      not(processing-instruction())     and      not(comment())     and      not(*[not(self::br) or @* or * or node()])     and      not(following::node()[not(         (self::text() or self::br or self::p or self::div)        and         normalize-space(translate(., &apos; &apos;, &apos;&apos;)) = &apos;&apos;        and         not(@*)        and         not(processing-instruction())        and         not(comment())        and         not(*[not(self::br) or @* or * or node()])       )])     ]">
        <!-- ignore all paragraphs and line-breaks at the end that have nothing but (non-breaking) spaces and line breaks -->
    </template>
    <template match="br[parent::div and not(preceding-sibling::node()) and not(following-sibling::node())]">
        <!-- Chrome generates <div><br/></div>. Renders differently in different browsers. Replace it with a non-breaking space -->
        <text> </text>
    </template>
    <template match="*[contains(@class, &apos;cta-button-primary&apos;)]">
        <copy>
            <attribute name="href">
                <value-of select="./@href"></value-of>
            </attribute>
            <attribute name="class">cta-button primary</attribute>
            <element name="span">
                <value-of select="."></value-of>
            </element>
        </copy>
    </template>
    <template match="*[contains(@class, &apos;cta-button-secondary&apos;)]">
        <copy>
            <attribute name="href">
                <value-of select="./@href"></value-of>
            </attribute>
            <attribute name="class">cta-button secondary</attribute>
            <element name="span">
                <value-of select="."></value-of>
            </element>
        </copy>
    </template>
</stylesheet>
  • Here <a> inside <span> or <span> inside <a/>, both are valid represention. It looks like your Filter XSLT is doing some magic to rearrange the html. – Siva Charan May 16 '13 at 15:55
  • 1
    The XSLT is executed whenever the RTF loads. If you edit the RTF source and switch back to the "Design" tab, the XSLT will execute then. – Nuno Linhares May 16 '13 at 18:17
  • 1
    Could we see the XSLT filter, perhaps? The default one has a few matches to clean up empty nodes and replace browser-specific markup that might be moving the span around. – Alvin Reyes May 18 '13 at 17:33
  • 1
    What happens if you remove the XSLT transformation, add the span in manually and then switch to the 'Design' view? Do you get the same behaviour? This may help to identify if it is the XSLT or something else causing this. – Jonathan Williams May 20 '13 at 10:30
  • 1
    I have just tested this after removing my filtering XSLT and the issue remains with the same behaviour ruling out the XSLT as a cause. – John Askew May 20 '13 at 14:04
3

From your comment:

I have just tested this after removing my filtering XSLT and the issue remains with the same behaviour ruling out the XSLT as a cause.

As this is the case, it would suggest that it is the default rich text field behaviour that is the cause of the re-formatting.

To get around this, I would suggest that you have three options:

  1. Modify the default behaviour of the rich text field(s) in the CME (May need to update standard configuration/interface or write a GUI extension)
  2. Update the output using templating code at publish time (this may be appropriate if you are only concerned with the published output and don't need the source of the stored Component to be correct)
  3. Update the source of the rich text field using the Event System [You could do this in the onComponentSave method] (this produces an overhead and additional complexity and changes may revert if a user open the Component (requiring the Events Code to fire again))

There are pros and cons to each of these approaches (briefly outlined in brackets alongside), and it really depends on your requirements which one you choose.

You may also want to check whether the WCAG accessibility setting (set on the RTF field in the Schema) affects this behaviour.

1

Is the problem actually with the XSLT, or with the stylesheet? You haven't explained what the actual undesirable result is.

Are you actually getting an undesirable visual effect as a result of the span wrapping the <a>? in HTML4, the browser treats the span as an inline element, as well as the <a>. Internet Explorer 8, I believe, may treat the as inline-block if there are block level elements inside, but IE7 will just treat this as an inline element inside of another inline element; i.e. by default, you should not have any undesirable effect.

If you're getting an undesirable visual effect, I'd think there's two reasons:

  1. You're applying a class to that interior span, and your stylesheet has an .cta-button span.someClass{} rule
  2. Your CSS was written to only work as .cta-button span

Either way, you can resolve the undesirable visual effect through CSS, just by changing it to something like,

.cta-button, .cta-button > * {}
  • The undesirable is breaking the styling because it is dependant on an <a> with a nested <span>. We cannot change the css and any manipulation of mark-up is undesirable and unwanted behaviour. – John Askew May 23 '13 at 9:46
  • Well, it was worth a shot. I've run into cases like yours before and I found it was a lot easier to solve the problem in the CSS. It seems, then, like Jonathan had the right answer. Out of curiosity, how were the content authors making a link with a nested span with a class on it, using the RTF? – paceaux May 23 '13 at 15:29
  • They weren't. They were just making a link and giving it a class of .cta-button-primary or .cta-button-secondary using FormatAreaStyles. The XSLT transformed the link to inject the <span> element and split the class into .cta-button and .primary / .secondary to match the desired mark-up. – John Askew May 24 '13 at 9:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.