Grails layoutResources equivalent for asset transfers

I am trying to customize the SiteMesh layout in grails v2.3.1 using the resource plugin (v1.0.4), but I do not how to handle the inclusion of JavaScript resources in a specific place in my template (for example, you would use r: layoutResources if you use the resource plugin )

Layout example (grails-app / views / layouts / test.gsp):

<html> <head> <title><g:layoutTitle/></title> <g:layoutHead/> </head> <body> <div class="thecontent"> <g:layoutBody/> </div> <asset:javascript src="application.js"/> <!-- WANT DECORATED PAGE RESOURCES TO BE INCLUDED HERE --> </body> </html> 

Gsp example (grails-app / views / test.gsp):

 <html> <head> <meta name="layout" content="test"/> <title>The Title</title> <asset:stylesheet src="thispageonly.css"/> </head> <body> <div id="helloworld"> Hello World </div> <asset:javascript src="thispageonly.js"/> </body> </html> 

The resulting styled page (ignoring the union of / etc components) works for the stylesheet (since it is in the head), but does not work for javascript:

 <html> <head> <meta name="layout" content="test"/> <title>The Title</title> <link rel="stylesheet" href="/assets/thispageonly.css?compile=false"/> </head> <body> <div class="thecontent"> <div id="helloworld"> Hello World </div> <!-- *** NOT WHERE I WANT THIS *** --> <script src="/assets/thispageonly.js?compile=false" type="text/javascript"></script> </div> <script src="/assets/application.js?compile=false" type="text/javascript"></script> </body> </html> 

Currently, the only way to get this to work is to use g: applyLayout and g: pageProperty:

 <!-- grails-app/views/layouts/test2.gsp --> <html> <head> <title><g:layoutTitle/></title> <g:layoutHead/> </head> <body> <div class="thecontent"> <g:layoutBody/> </div> <asset:javascript src="application.js"/> <g:pageProperty name="page.javascript"/> </body> </html> <!-- grails-app/views/test2.gsp --> <g:applyLayout name="test2"> <html> <head> <title>The Title</title> <asset:stylesheet src="thispageonly.css"/> </head> <body> <div id="helloworld"> Hello World </div> <content tag="javascript"> <asset:javascript src="thispageonly.js"/> </content> </body> </html> </g:applyLayout> 

But this deviation from the meta tag seems too complicated (plus I don’t understand if the poorly documented g: pageProperty will be supported as it is in future updates). What is the best long-term way to do this?

+6
source share
4 answers

Using sitemesh to control the placement of objects is a legitimate use case. Sitemesh is not going anywhere, and I actually use this to control the subcontainer and layout overlay. There was no point duplicating this built-in flow control in the resource pipeline plugin.

Another trick that is quite useful is the use of the <g:layoutHead/> and <g:layoutBody/> , which are also quite useful.

If this turns out to be a problem, in the future we may consider providing a regime that has this behavior. Let me know how things are going with the conveyor, and if such problems arise, please feel free to open a ticket on github. Apparently I also need to keep track of the stack overflow :)

+1
source

FYI: This works well for me, although it's a little ugly.

 <!-- grails-app/views/layouts/test2.gsp --> <html> <head> <title><g:layoutTitle/></title> <g:layoutHead/> </head> <body> <div class="thecontent"> <g:layoutBody/> </div> <asset:javascript src="application.js"/> <asset:deferredScripts/> </body> </html> <!-- grails-app/views/test2.gsp --> <g:applyLayout name="test2"> <html> <head> <title>The Title</title> <asset:stylesheet src="thispageonly.css"/> </head> <body> <div id="helloworld"> Hello World </div> <asset:script src="${assetPath(src: 'thispageonly.js')}" type="text/javascript" /> </body> </html> </g:applyLayout> 
+3
source

IGNORE THIS ANSWER, see the comment below by the asset-pipeline creator about how this already exists in the resource pipeline plugin as <asset:script> .

OLD RESPONSE:

Sitemesh makes my head hurt, and as far as I can tell, a solution using the g:layoutHead and g:layoutBody not something that would allow you to put together a bunch of different javascript fragments and emit them all in a single block.

An application that I recently started working on the rather heavily used r:script tag, and will use it several times on the same gsp page (on various included templates).

As I plan to solve this in my application, this is taglib, which just does what the r:script tag did. Collect all the javascript pending snippets and emit them when the user asks them to be emitted.

Here is an example taglib that can do this:

 class DeferTagLib { static namespace = 'defer' static defaultEncodeAs = [emitScript: 'raw'] // we actually want to inject javascript :) private static JAVASCRIPT_DEFER_PROPERTY = "__defer__javascript" protected String removeJavascript() { try { return getJavascript() } finally { getRequest().removeAttribute(JAVASCRIPT_DEFER_PROPERTY) } } protected String getJavascript() { return getRequest().getAttribute(JAVASCRIPT_DEFER_PROPERTY) } protected void appendJavascript(String javascript) { String currentValue = getJavascript() ?: "" getRequest().setAttribute(JAVASCRIPT_DEFER_PROPERTY, currentValue + javascript) } // For gathering script tags in your gsp files and emitting them in the footer of the layout // A replacement for the r:script tag that came with Resources, but is not in the asset-pipeline plugin def script = { attrs, body -> appendJavascript(body()) } // Used in the layout to emit all the script that has been deferred so far in the footer of the page // A replacement for the <r:layoutResources/> tag that emitted javascript in the footer // (the 2nd time it was called, kind of confusing...) def emitScript = { attrs -> out << "<script>${removeJavascript()}</script>" } } 

Then on my gsp pages / snippets, I can simply replace any previous calls with r:script with defer:script :

 <defer:script> // this is before </defer:script> ... maybe another template that included ... <defer:script> alert("foo!"); </defer:script> ... later <defer:script> // after </defer:script> 

And in my layout below, I can just do it

 <html> <head> .... shared head stuff .... <g:layoutHead/> </head> <body> .... body stuff before layout <g:layoutBody/> .... other body stuff after layout <defer:emitScript/> </body> </html> 

This will create a partition after the body, which looks like

  ... the actual body from the gsp <script> // this is before ... alert("foo!"); // after </script> </body> </html> 
+1
source

Not sure about your requirements. In my project, I needed to move all the JavaScript files to Footer. I moved the "Layout Resources" tag from the header to the footer and it worked great.

 <footer class="clear"> <r:layoutResources> </footer> 
0
source

Source: https://habr.com/ru/post/957441/


All Articles