plone / diazo

Diazo applies a static HTML theme to a dynamic website
http://diazo.org
Other
41 stars 26 forks source link

Modifying content on the fly with after and before rules #43

Closed ebrehault closed 9 years ago

ebrehault commented 9 years ago

Principle

This PR proposes to use after and before rules to modify the content on the fly just like the replace rule allows to do it. Example:

    <before css:content="#content-core">
        <a href="mailto:contact@diazo.org">Ask for help</a>
    </before>

Implementation

It has been implemented as discussed with @lrowe in https://github.com/plone/diazo/pull/42. The resulting XSLT code is a little bit more complex than the example mentioned in this discussion (mainly to apply the rules conditions properly), but the most important thing is we do not add an extra pass over the processed document.

lrowe commented 9 years ago

In https://github.com/lrowe/diazo/tree/after-before-content-tests I've added a test that is current failing ontop of your commit, rebased on top of a python 3 fix for the test class so that test failures display errors better.

This is the failure:

--- /Users/lrowe/scratch/diazo/lib/diazo/tests/v1-before-replace-after-content/output.html
+++ now
@@ -1,10 +1,5 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml">
-  <body>
-    <h1>Title</h1>
-    <span>before</span>
-    <span>replace</span>
-    <span>after</span>
-  </body>
+<body><h1>Title</h1><p id="one" class="after">one</p><span>after</span></body>
 </html>

Which from looking at the compiled xsl you can see is due to the template including only known before-content/replace-content/after-content modes. All of these modes always have to be included so that different ways of selecting the same content node work:

$ .tox/py34/bin/diazocompiler -r lib/diazo/tests/v1-before-replace-after-content/rules.xml 
...
    <xsl:template match="//*[@id = 'one']">
        <xsl:apply-templates select="." mode="before-content"/>
        <xsl:apply-templates select="." mode="replace-content"/>
    </xsl:template>
    <xsl:template match="//*[@id = 'one']" mode="before-content">

        <span xmlns:diazo="http://namespaces.plone.org/diazo">before</span>

    </xsl:template>

    <xsl:template match="//*[@id = 'one']" mode="replace-content">
        <span xmlns:diazo="http://namespaces.plone.org/diazo">replace</span>
    </xsl:template>

    <xsl:template match="//*[@class and contains(concat(' ', normalize-space(@class), ' '), ' after ')]">
            <xsl:copy>
                <xsl:apply-templates select="@*|node()"/>
            </xsl:copy>
        <xsl:apply-templates select="." mode="after-content"/>
    </xsl:template>
    <xsl:template match="//*[@class and contains(concat(' ', normalize-space(@class), ' '), ' after ')]" mode="after-content">

        <span xmlns:diazo="http://namespaces.plone.org/diazo">after</span>

    </xsl:template>
...
lrowe commented 9 years ago

Added another test for before content-children showing it being applied multiple times.

--- /Users/lrowe/scratch/diazo/lib/diazo/tests/v1-before-content-content-children/output.html
+++ now
@@ -1,12 +1,5 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml">
-  <body>
-    <h1>Title</h1>
-    <p id="one">
-        <span>before</span>
-        <span>one</span>
-        <span>1</span>
-    </p>
-  </body>
+<body><h1>Title</h1><p id="one"><span>before</span><span>one</span><span>before</span><span>1</span></p></body>
 </html>

This is because content-children has to compile differently in content rules:

$ .tox/py34/bin/diazocompiler -r lib/diazo/tests/v1-before-content-content-children/rules.xml 
...
    <xsl:template match="//*[@id = 'one']/node()">
        <xsl:apply-templates select="." mode="before-content"/>
            <xsl:copy>
                <xsl:apply-templates select="@*|node()"/>
            </xsl:copy>
    </xsl:template>
    <xsl:template match="//*[@id = 'one']/node()" mode="before-content">

        <span xmlns:diazo="http://namespaces.plone.org/diazo">before</span>

    </xsl:template>
...

for instance in replace content-children:

$ .tox/py34/bin/diazocompiler -r lib/diazo/tests/v1-replace-content-content-children/rules.xml
...
    <!--RULE: <diazo:replace css:content-children="#you-are-here" xml:id="r1" content-children="//*[@id = 'you-are-here']"/>-->
    <xsl:template match="//*[@id = 'you-are-here']"><xsl:copy><xsl:apply-templates select="@*"/>Location:</xsl:copy></xsl:template>
...

Otherwise I think its looking good. Thanks for working on this!

ebrehault commented 9 years ago

@lrowe it was actually very tricky (each time I fixed the code for a given test, another one was failing), but it was fun too! I have succeeded in managing the content children rules in a quite good way, the only downside is we cannot modify a content children and also use the same content children selector in a regular theme rule. For instance:

<before css:content-children="#one">
    <span>Uno</span>
</before>

<before
    css:theme="#alpha"
    css:content-children="#one"
    />

would not work (the first rule would be ignored). But:

<before css:content-children="#one">
    <span>Uno</span>
</before>

<before
    css:theme="#alpha"
    css:content="#one"
    />

would work. That's just for children rules, so I do not think it is too bad.

Note: the Python 3 compliancy broke the tests with Python 2.7, but I guess you are already aware of that, right?

lrowe commented 9 years ago

Great! I will take a close look before I merge which may not be until I am at PLOG next week.

ebrehault commented 9 years ago

Sure, no problem. Meanwhile I will work on the 2nd PR mentioned in our #42 discussion:

 <include css:content="h2" href="extra.html"/>

as a simpler syntax for:

<xsl:apply-templates select="document('extra.html', '/')//h2" mode="raw"/>
ebrehault commented 9 years ago

@lrowe, do you think you will have some time to review this PR (and the #44 too) ? thanks