Per-page custom links and scripts?

classic Classic list List threaded Threaded
21 messages Options
12
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Per-page custom links and scripts?

Jimmie Fulton
Hi,

Since Dandelion Core writes
<link/>
 tags right before the
</head>
 and
<script/>
 tags right before the
</body>
 tag, I'm trying to figure out how to allow for per-page customizations.

For instance, if I define a simple function that's only pertinent to the page, and I don't want to create yet another bundle, how would I achieve this?

    <script>
        $("#helloButton").onclick(function () {
            alert("Hello World!");
        });
    </script>

Since jquery gets added at the end, this fails.

Same thing if I wanted to add a style section.

Ideally, this type of stuff would be placed in bundles, but ideals and practicality often conflict, especially on large legacy sites.

Thanks,

Jimmie
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Per-page custom links and scripts?

Thibault Duchateau
Administrator
Hi Jimmie,

For now, you have several ways, but all of them require to prepare an asset bundle.

1) Simply use the dependency mechanism of the bundle graph

Assuming that all assets of the page1 are managed by Dandelion, you could simply write a bundle like:

{
   "dependencies" : ["jquery"],
   "assets" : [{
      "location" : {
         "webapp" : "/assets/js/page1.js"
      }
   ]
}

It assumes that the JavaScript contained in page1.js needs jQuery. Declaring the bundle like the above will tell Dandelion to insert the page1.js asset after jQuery.

2) Configure the dom location

You can configure the asset to be inserted in a particular position in the DOM. Use the dom attribute for that. (See http://dandelion.github.io/components/core/1.0.1/docs/html/#4-1-1-definitions)

For example:

{
   "assets" : [{
      "dom" : "head",
      "location" : {
         "webapp" : "/assets/js/page1.js"
      }
   ]
}

This way, the page1.js asset will be inserted in the HEAD section, as late as possible i.e. after all CSS.

I'm wondering if in this kind of scenarios, the dom attribute couldn't be extended to any CSS selector. Would this help you?

Regards,
Thibault
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Per-page custom links and scripts?

Jimmie Fulton
My concern would be around the number of bundles that might need to be created, from both a bundle management perspective, as well as a potential performance perspective (in the case of hundreds of pages).

Just brainstorming here:
1) The expansion of the dom capabilities may be helpful. It would probably be ideal to allow for specifying this outside of bundles, though, such as globally in properties files and perhaps overridable in the page.  This way, the user can customize where some of the out-of-the-box assets go without having to define their own bundles.

2) Another option may be to allow to turn off the default placement of assets and require the user to provide dialect-specific tags within the template.  I guess this would be similar to the dom idea.  Something like:
<div ddl:assets="js"/>
, which would replace the div with script tags.  Whether dom or special tags, the user can turn off the default and put these directly in the page, or ideally in a layout with a special section that allows for plugging in customization.

Either of these equivalent options could be employed to gracefully upgrade large legacy codebases.  The user could specify just a few dandelion-managed assets to start with, and plug those assets into legacy pages anywhere necessary to get the job done, while at the same time incorporating new stuff into layout pages with the latest and greatest frameworks.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Per-page custom links and scripts?

Jimmie Fulton
Expanding on the idea of dialect tags, could the presence of one of these tags automatically turn off the default behavior?  Essentially, the simple act of including an asset tag is all that would be required to allow for precise placement.  No extra config necessary.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Per-page custom links and scripts?

Thibault Duchateau
Administrator
In reply to this post by Jimmie Fulton
Wow! Lots of great ideas!

Let me try to sum it up to ensure understanding.

The expansion of the dom capabilities would be used to target a specific DOM location, using a CSS selector. But this would require to be specified per asset, in each bundle. Nice feature if you have a small amount of bundles to manage.

Now with a larger amount of bundles, you would like to do the same, but since you don't want to rewrite an existing vendor bundle just to override the dom attribute. You would like to be able to define the DOM location where these vendor assets would be inserted, either globally (properties) or locally (pages) using some kind of marker in templates. So the DOM location would concern an asset type, not a particular asset. Same idea than the first, but from another angle and with a larger scope.

How would you target a specific DOM location using properties?
Actually, you'd like to do the same with all kind of assets, vendor and regular ones, right?

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Per-page custom links and scripts?

Jimmie Fulton
Something like this?  This is a hypothetical layout...

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/web/thymeleaf/layout"
      xmlns:ddl="http://www.thymeleaf.org/dandelion"
      ddl:bundle-includes="bootstrap2,bootstrap-datepicker2">
<head>
    <title layout:title-pattern="$DECORATOR_TITLE - $CONTENT_TITLE">App</title>
    <link rel="shortcut icon" href="../../../../favicon.ico" th:href="@{/favicon.ico}" />

    <style ddl:assets="css"/>
    
    <div layout:fragments="styles">
        <p>optional style and link tags</p>
    </div>
</head>
<body>

    <div th:include="common/fragments/main-menu :: top-menu">Top Menu</div>

    <div layout:fragment="content" class="container">
        <p>Page content goes here</p>
    </div>
    
    <script ddl:assets="js"/>

    <div layout:fragment="scripts">
        <p>optional script tags</p>
    </div>
</body>
</html>
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Per-page custom links and scripts?

Thibault Duchateau
Administrator
In reply to this post by Jimmie Fulton
Sure. Let's take an example. Your current page require 2 JS and 3 CSS files.

The default behaviour of Dandelion-Core is to insert these assets like:

<html>
  <head>
    ...
    CSS1
    CSS2
    CSS3
  </head>
  <body>
    <div>...</div>
    <div>...</div>
    JS1
    JS1
  </body>
<html>

Now using the dialect:

<html>
  <head>
    ...
    CSS1
    CSS2
    CSS3
  </head>
  <body>
    <div ddl:assets="js">...</div>
    <div>...</div>
  </body>
<html>

would lead to:

<html>
  <head>
    ...
    CSS1
    CSS2
    CSS3
  </head>
  <body>
    JS1
    JS2
    <div>...</div>
  </body>
<html>

Did I understand correctly? :-)
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Per-page custom links and scripts?

Jimmie Fulton
Exactly.  Just a mechanism for providing precise control over asset placement.  I updated my post of the example.  It could potentially be any tag, as long as the ddl:foo="bar" is specified.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Per-page custom links and scripts?

Jimmie Fulton
And to expand further on the automatic turning off of the default behavior...

If you specified ddl:bundle-assets="js", but didn't specify dd:bundle-assets="css", the css assets would continue to use the default placement?  Are we getting too fancy, here?

BTW, do you sleep? ;-P
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Per-page custom links and scripts?

Thibault Duchateau
Administrator
Jimmie Fulton wrote
And to expand further on the automatic turning off of the default behavior...

If you specified ddl:bundle-assets="js", but didn't specify dd:bundle-assets="css", the css assets would continue to use the default placement?  Are we getting too fancy, here?
Never fancy enough! Sure, the default behaviour applies, until you use one of these tags(JSP)/attributes(Thymeleaf) in a page. That's the best strategy in my opinion.

Jimmie Fulton wrote
BTW, do you sleep? ;-P
Ahah! Much less since the beginning of this project! :-)

A HUGE thank you for these ideas. New issues in progress. I'll update this topic once created.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Per-page custom links and scripts?

Jimmie Fulton
Thank you, sir!  Looking forward to it.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Per-page custom links and scripts?

Thibault Duchateau
Administrator
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Per-page custom links and scripts?

Jimmie Fulton
Hi Thibault,

I'm incorporating the latest Dandelion Core (1.1.1) in order to make use of the new placeholders within Thymeleaf.  Unfortunately, the new code doesn't seem to work within a LayoutDialect when using the placeholder-replace attribute.  It acts just like the placeholder-include functionality, which I think is more of a fringe tag vs the placeholder-replace.

I changed PlaceholderAttrProcessor code to look like this in order to fix the problem:
      // Replace the current element by the placeholder
      case PLACEHOLDER_REPLACE:
         final NestableNode parent = element.getParent();
         parent.insertAfter(element, new Text(placeholder));
         parent.removeChild(element);
         break;
      }

but then that breaks the functionality for including in a standard Thymeleaf template without a layout.

            <nz.net.ultraq.thymeleaf.version>1.2.9</nz.net.ultraq.thymeleaf.version>

            ....

            <dependency>
                <groupId>nz.net.ultraq.thymeleaf</groupId>
                <artifactId>thymeleaf-layout-dialect</artifactId>
                <version>${nz.net.ultraq.thymeleaf.version}</version>
            </dependency>
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Per-page custom links and scripts?

Thibault Duchateau
Administrator
Hi Jimmie,

I've just looked at the code (with fresh eyes) and...
Thanks for raising this.

Jimmie Fulton wrote
I changed PlaceholderAttrProcessor code to look like this in order to fix the problem:
      // Replace the current element by the placeholder
      case PLACEHOLDER_REPLACE:
         final NestableNode parent = element.getParent();
         parent.insertAfter(element, new Text(placeholder));
         parent.removeChild(element);
         break;
      }
I think I would have done the same.


Jimmie Fulton wrote
but then that breaks the functionality for including in a standard Thymeleaf template without a layout.
What do you mean? Can you please post an usage example?
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Per-page custom links and scripts?

Jimmie Fulton
Yes,  I'll throw together a simple project that illustrates the behavior.  If I can figure out a fix that works consistently, I may send a PR.  Otherwise, perhaps I could post the project so you can take a peek.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Per-page custom links and scripts?

Jimmie Fulton
I built up a sample application, and that fix indeed seems to work fine in standard templates and layout templates.

As a side note, I realized that the placeholder-replace functionality works well for Javascript.  I can always put in a
<div style="display:blank" layout:fragment="js"/>
 as a something that allows a developer to hook into the layout to supply their own additional per-page javascripts.  Essentially, their
<script>
 tags will just be included within the DIV as a list.

For CSS, it's a little different, though.  The new dandelion functionality does indeed allow for the CSS links to but put in place, but providing a layout:fragment for developers to hook into doesn't seem to work so well.  The HEAD doesn't allow for container-like tags, such as DIV, and using a STYLE or LINK results in LINK tags embedded as a list within the STYLE or LINK, which results in invalid HTML.  Perhaps this is more of a shortcoming of the Layout dialect (or a shortcoming of my understanding of how it works) that one with the Dandelion Dialect.  I think there is potential to expand the Dandelion Dialect to allow for overriding and inclusion of custom per-page styles, but is that really a concern of Dandelion, and what would it mean for natural templates?  It would be interesting to hear your thoughts.

Thanks!

Jimmie
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Per-page custom links and scripts?

Thibault Duchateau
Administrator
Hi Jimmie,

Jimmie Fulton wrote
I built up a sample application, and that fix indeed seems to work fine in standard templates and layout templates.
Great. Ready to submit a PR? :-)

Jimmie Fulton wrote
I built up a sample application, and that fix indeed seems to work fine in standard templates and layout templates.

As a side note, I realized that the placeholder-replace functionality works well for Javascript.  I can always put in a
<div style="display:blank" layout:fragment="js"/>
 as a something that allows a developer to hook into the layout to supply their own additional per-page javascripts.  Essentially, their
<script>
 tags will just be included within the DIV as a list.
Still great. But why use style="display:blank" if the purpose of this div is to contain script tags only? Am I missing something?

Jimmie Fulton wrote
For CSS, it's a little different, though.  The new dandelion functionality does indeed allow for the CSS links to but put in place, but providing a layout:fragment for developers to hook into doesn't seem to work so well.  The HEAD doesn't allow for container-like tags, such as DIV, and using a STYLE or LINK results in LINK tags embedded as a list within the STYLE or LINK, which results in invalid HTML.
Indeed, because of the HTML non-compliance, you should better split links and styles tags into multiple fragments, so that you could end up with something like:
<head>
  <title layout:title-pattern="$DECORATOR_TITLE - $CONTENT_TITLE">App</title>
  <link layout:replace="links" />
  <style layout:replace="styles" />
</head>
This remains valid HTML. Of course the above means that you've defined the correct fragments in the decorator page.

To go a step further, nothing prevents you from using both Layout and Dandelion dialects together:
<head>
  <title layout:title-pattern="$DECORATOR_TITLE - $CONTENT_TITLE">App</title>
  <style ddl:placeholder-replace="css" />
  <link layout:replace="links" />
  <style layout:replace="styles" />
</head>
It's still valid HTML.

Regarding the natural templating argument, well... To be frank, it has never been something really determining to me, as much in my work as regular Thymeleaf user (mainly because I have never needed it in my missions) as in my work as a Dandelion author. See this interesting answer from Daniel Fernandez about natural templating. Thymol may help (note that I've never used it).
On your part, do you use/need static prototyping?

Regards,
Thibault.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Per-page custom links and scripts?

Jimmie Fulton
;-)

I think what I'm missing is the layout:replace.  Let me give that a try.  If that works, all my problems are solved.  I've been using layout:fragment, which doesn't replace, hence the need for a container tag capable of having lists of sub-components.

Let me get that PR up for you.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Per-page custom links and scripts?

Thibault Duchateau
Administrator
Great. Please submit it against the wip/1.1.2 branch which I've just created.
And to move ahead, please read and sign the ICLA so that I can merge your PR :-)

Thanks!
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Per-page custom links and scripts?

Jimmie Fulton
Hi Thibault,

I've signed the ICLA.  I've got several use cases that I'm exploring.  I want to get these use cases satisfied in production code before submitting a PR.  I've created a sample application that explores each of these use cases, and I'll make that available to you so that you may use it when you evaluate my PR.  I'll also provide some explanations for each case.  Give me a day or so...

Thanks,

Jimmie
12
Loading...