Text inlining in HTML, CSS, JAVASCRIPT

 

12.2 Text inlining

Text inlining is very similar to the expression inlining capability we have just seen, but it actually adds more power. It has to be enabled explicitly with th:inline="text".

Text inlining not only allows us to use the same inlined expressions we just saw, but in fact processes tag bodies as if they were templates processed in the TEXT template mode, which allows us to perform text-based template logic (not only output expressions).

We will see more about this in the next chapter about the textual template modes.

12.3 JavaScript inlining

JavaScript inlining allows for a better integration of JavaScript <script> blocks in templates being processed in the HTML template mode.

As with text inlining, this is actually equivalent to processing the scripts contents as if they were templates in the JAVASCRIPT template mode, and therefore all the power of the textual template modes (see next chapter) will be at hand. However, in this section we will focus on how we can use it for adding the output of our Thymeleaf expressions into our JavaScript blocks.

This mode has to be explicitly enabled using th:inline="javascript":

<script th:inline="javascript">
    ...
    var username = [[${session.user.name}]];
    ...
</script>

This will result in:

<script th:inline="javascript">
    ...
    var username = "Sebastian \"Fruity\" Applejuice";
    ...
</script>

Two important things to note in the code above:

First, that JavaScript inlining will not only output the required text, but also enclose it with quotes and JavaScript-escape its contents, so that the expression results are output as a well-formed JavaScript literal.

Second, that this is happening because we are outputting the ${session.user.name} expression as escaped, i.e. using a double-bracket expression: [[${session.user.name}]]. If instead we used unescaped like:

<script th:inline="javascript">
    ...
    var username = [(${session.user.name})];
    ...
</script>

The result would look like:

<script th:inline="javascript">
    ...
    var username = Sebastian "Fruity" Applejuice;
    ...
</script>

…which is malformed JavaScript code. But outputting something unescaped might be what we need if we are building parts of our script by means of appending inlined expressions, so it’s good to have this tool at hand.

JavaScript natural templates

The mentioned intelligence of the JavaScript inlining mechanism goes much further than just applying JavaScript-specific escaping and outputting expression results as valid literals.

For example, we can wrap our (escaped) inlined expressions in JavaScript comments like:

<script th:inline="javascript">
    ...
    var username = /*[[${session.user.name}]]*/ "Gertrud Kiwifruit";
    ...
</script>

And Thymeleaf will ignore everything we have written after the comment and before the semicolon (in this case 'Gertrud Kiwifruit'), so the result of executing this will look exactly like when we were not using the wrapping comments:

<script th:inline="javascript">
    ...
    var username = "Sebastian \"Fruity\" Applejuice";
    ...
</script>

But have another careful look at the original template code:

<script th:inline="javascript">
    ...
    var username = /*[[${session.user.name}]]*/ "Gertrud Kiwifruit";
    ...
</script>

Note how this is valid JavaScript code. And it will perfectly execute when you open your template file in a static manner (without executing it at a server).

So what we have here is a way to do JavaScript natural templates!

Advanced inlined evaluation and JavaScript serialization

An important thing to note regarding JavaScript inlining is that this expression evaluation is intelligent and not limited to Strings. Thymeleaf will correctly write in JavaScript syntax the following kinds of objects:

  • Strings
  • Numbers
  • Booleans
  • Arrays
  • Collections
  • Maps
  • Beans (objects with getter and setter methods)

For example, if we had the following code:

<script th:inline="javascript">
    ...
    var user = /*[[${session.user}]]*/ null;
    ...
</script>

That ${session.user} expression will evaluate to a User object, and Thymeleaf will correctly convert it to Javascript syntax:

<script th:inline="javascript">
    ...
    var user = {"age":null,"firstName":"John","lastName":"Apricot",
                "name":"John Apricot","nationality":"Antarctica"};
    ...
</script>

The way this JavaScript serialization is done is by means of an implementation of the org.thymeleaf.standard.serializer.IStandardJavaScriptSerializer interface, which can be configured at the instance of the StandardDialect being used at the template engine.

The default implementation of this JS serialization mechanism will look for the Jackson library in the classpath and, if present, will use it. If not, it will apply a built-in serialization mechanism that covers the needs of most scenarios and produces similar results (but is less flexible).

12.4 CSS inlining

Thymeleaf also allows the use of inlining in CSS <style> tags, such as:

<style th:inline="css">
  ...
</style>

For example, say we have two variables set to two different String values:

classname = 'main elems'
align = 'center'

We could use them just like:

<style th:inline="css">
    .[[${classname}]] {
      text-align: [[${align}]];
    }
</style>

And the result would be:

<style th:inline="css">
    .main\ elems {
      text-align: center;
    }
</style>

Note how CSS inlining also bears some intelligence, just like JavaScript’s. Specifically, expressions output via escaped expressions like [[${classname}]] will be escaped as CSS identifiers. That is why our classname = 'main elems' has turned into main\ elems in the fragment of code above.

Advanced features: CSS natural templates, etc.

In an equivalent way to what was explained before for JavaScript, CSS inlining also allows for our <style> tags to work both statically and dynamically, i.e. as CSS natural templates by means of wrapping inlined expressions in comments. See:

<style th:inline="css">
    .main\ elems {
      text-align: /*[[${align}]]*/ left;
    }
</style>

Comments