I am using grails for almost a year. Since now when I wanna link a css or js file in a gsp. I did the following:
I created a new file (eg the resources file) under web-app folder and I put there all my files of folders (eg when importing bootstrap I had a parent folder bootstrap under resources and under bootstrap there were css, img and js folders with their files).
Then, to import a css file I did the following (here is documentation for this):
<link rel="stylesheet" href="${resource(dir:
'resources/bootstrap/css', file: 'bootstrap.min.css')}"
type="text/css">
<script src="${resource(dir: 'resources/bootstrap/js', file:
'bootstrap.min.js')}"></script>
This worked great, but when I tried to create a new Project in grails 2.2.4 I had a Resource not found Error (404 to browser and the following to console).
ERROR resource.ResourceMeta - Resource not found: /resources/bootstrap/css/bootstrap.min.css
ERROR resource.ResourceMeta - Resource not found: /resources/bootstrap/js/bootstrap.min.js
ERROR resource.ResourceMeta - Resource not found: /resources/bootstrap/css/bootstrap.min.css
ERROR resource.ResourceMeta - Resource not found: /resources/bootstrap/js/bootstrap.min.js
As I realized these Errors in console were once from the resources function and once from the GET that client(browser) requested.
When looking at resources plugin I see that they suggest using the js and css folders. Is that meaningful to split a tool (eg twitter bootstrap) in these two directories?
ok I believe I have a (semi) working solution:
Suppose we need to include both Twitter Bootstrap 3 and TinyMce
Under webapp directory I create the following directories:
resources/bootstrap/
resources/bootstrap/css/
resources/bootstrap/css/bootstrap.min.css
resources/bootstrap/fonts/
resources/bootstrap/fonts/glyphicons-halflings-regular.eot
resources/bootstrap/fonts/glyphicons-halflings-regular.svg
resources/bootstrap/fonts/glyphicons-halflings-regular.ttf
resources/bootstrap/fonts/glyphicons-halflings-regular.woff
resources/bootstrap/js/
resources/bootstrap/js/bootstrap.min.js
resources/jquery/
resources/jquery/jquery-2.0.3.min.js
resources/tiny_mce/
resources/tiny_mce/langs/ /*many files here*/
resources/tiny_mce/plugins/ /*many files here*/
resources/tiny_mce/themes/ /*many files here*/
resources/tiny_mce/utils/ /*many files here*/
resources/tiny_mce/tiny_mce_popup.js
resources/tiny_mce/tiny_mce_src.js
resources/tiny_mce/tiny_mce.js
Then I declare my resources in ApplicationResources.groovy
modules = {
application {
resource url:'js/application.js'
}
jquery {
resource url:'resources/jquery/jquery-2.0.3.min.js'
}
bootstrap {
dependsOn 'jquery'
resource url:'resources/bootstrap/css/bootstrap.min.css'
resource url:'resources/bootstrap/js/bootstrap.min.js'
}
tinymce {
resource url:'resources/tiny_mce/tiny_mce.js'
}
}
And in Config.groovy
grails.resources.adhoc.patterns = ['/images/*', '/css/*', '/js/*', '/plugins/*'] /*no changes here*/
grails.resources.adhoc.excludes = ['/**/langs/**/*.*', '/**/themes/**/*.*'] /*to permit some Ajax calls from tiny_mce.js to relevant resources*/
grails.resources.debug=true
/*
this is why I call my solution SEMI working.
If set grails.resources.debug to false, TinyMce is NOT working because the above excludes are not active, and I receive 404 errors
*/
Then, in main.gsp
<!DOCTYPE html>
<head>
<g:javascript library="application"/>
<g:javascript library="bootstrap"/>
<g:javascript library="tinymce"/>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title><g:layoutTitle default="Grails"/></title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="${resource(dir: 'images', file: 'favicon.ico')}" type="image/x-icon">
<link rel="apple-touch-icon" href="${resource(dir: 'images', file: 'apple-touch-icon.png')}">
<link rel="apple-touch-icon" sizes="114x114" href="${resource(dir: 'images', file: 'apple-touch-icon-retina.png')}">
<link rel="stylesheet" href="${resource(dir: 'css', file: 'main.css')}" type="text/css">
<link rel="stylesheet" href="${resource(dir: 'css', file: 'mobile.css')}" type="text/css">
<r:layoutResources />
<g:layoutHead/>
</head>
<body>
<div id="grailsLogo" role="banner"><img src="${resource(dir: 'images', file: 'grails_logo.png')}" alt="Grails"/></div>
<g:layoutBody/>
<div class="footer" role="contentinfo"></div>
<div id="spinner" class="spinner" style="display:none;"><g:message code="spinner.alt" default="Loading…"/></div>
<r:layoutResources />
</body>
</html>
And in index.gsp
<head>
...
<script type="text/javascript">
$(function() {
tinymce.init({selector:'textarea'});
});
</script>
</head>
<body>
...
<h1>Welcome to Grails</h1>
check bootstrap - start
<span class="glyphicon glyphicon-search"></span>
<button type="button" class="btn btn-default btn-lg">
<span class="glyphicon glyphicon-star"></span> Star
</button>
check bootstrap - stop
<textarea>Your content here.</textarea>
...
</body>
Using the above, I have fully operational JQuery, Bootstrap3 and TinyMCE
But if a I set in Config.groovy
grails.resources.debug=true
I am receiving 404-errors related to the grails.resources.adhoc.excludes resources that TinyMce dynamically fetches after page load.
Any clues? I am really close to find the solution so I will glad to get your input
This test project can be downloaded from here: https://docs.google.com/file/d/0B8epX7R4j7jeaVh5OTFiQlV4V0U/edit?usp=sharing
Another answer to the question is the following:
Clean your project
Change 'BuildConfig.groovy' and use a newer version of resources plugin
Do a refresh dependencies to your project
and everything is working great now
I had the same issue, I don't know exactly what setup you have but I have this at the top of my mail.gsp-page:
<link rel="stylesheet" href="${resource(dir: 'css', file: 'bootstrap.css')}" type="text/css">
(Inside the -tag)
If you need to import .js-files this is what works for me:
<script src="${resource(dir: 'js', file: 'bootstrap.js')}"></script>
This is at the very bottom om the page inside the -tag.
I'm using Grails 2.1.1.
The /css and /js directories are part of the default "adhoc resources" patterns that the resources plugin adds to Config.groovy. If you want a different structure for your static resources, you'll either have to create a resource definition file (eg. BootstrapResources.groovy) or add your directory structure to the adhoc patterns:
// What URL patterns should be processed by the resources plugin
grails.resources.adhoc.patterns = ['/images/*', '/css/*', '/js/*', '/plugins/*', '/resources/*']
This would make everything in the /web-app/resources an adhoc resource and subject to the resource plugin's processing.
I am beginning to think that the most flexible way is to serve static content by using a proxy in front of Tomcat / Grails such as Nginx (for all the 'resources/*' URIs)and letting Grails to handle all the dynamic stuff (for the rest URIs).
After all it should be more efficient to use Nginx for serving static files than letting Tomcat / Grails do this.
But, as an afterthought, it should be pity for Resources Plugin to force you splitting the resources in three directories - and driving Grails cumbersome for simple scenarios like using Ext.js, WYSIWIG editors etc which have myriads of files to be included...
Related
I have an Electron (1.7.10) application that is reporting it can't find 5 of 7 PNG files in my ASAR. All 7 PNGs are in the same folder, and 2 of them are displayed on screen fine. The other 5 report net::ERR_FILE_NOT_FOUND.
All src attributes for the img tags are dynamically generated and use relative paths (assets/images/MyImage.png). If I extract the ASAR, I can see the files in there, in the correct folder (as referenced by the src attribute).
If I use the console to set the location of my browser to one of the images (document.location.href = "file:///path/to/app.asar/dist/assets/images/MyImage.png") I get the same results - 2 of 7 show OK.
Before packaging my application (with electron-builder), all images show correctly.
Let me guess, you are building a react SPA using react-router, and BrowserRouter?
If so, use HashRouter instead. Electron does not work with SPA's route by default, because a SPA route changes, but the resource path is always relative to index.html.
I haven't evaluated the other answers, but for my particular case, an extremely solution worked. I don't believe this is well documented, so it might be fairly common for people to still encounter this issue. For my particulars, the relevant problem and solution were identified here.
To address, add <base href='./' /> to the index.html (or whatever your starting html file is that hosts your SPA). This is a complete example of mine:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<base href="./" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<meta
http-equiv="Content-Security-Policy"
content="script-src 'Self' 'unsafe-inline';"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
const path = require('path');
path.join(__dirname, 'assets/images/MyImage.png');
To working my static file (CSS, JS) I have to write absolute path like /AppName/templates/style/main.css. Is there any solution, that I could write relative path like style/main.css?
If your actual concern is the dynamicness of the webapp context (the "AppName" part), then just retrieve it dynamically by HttpServletRequest#getContextPath().
<head>
<link rel="stylesheet" href="${pageContext.request.contextPath}/templates/style/main.css" />
<script src="${pageContext.request.contextPath}/templates/js/main.js"></script>
<script>var base = "${pageContext.request.contextPath}";</script>
</head>
<body>
link
</body>
If you want to set a base path for all relative links so that you don't need to repeat ${pageContext.request.contextPath} in every relative link, use the <base> tag. Here's an example with help of JSTL functions.
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%# taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
...
<head>
<c:set var="url">${pageContext.request.requestURL}</c:set>
<base href="${fn:substring(url, 0, fn:length(url) - fn:length(pageContext.request.requestURI))}${pageContext.request.contextPath}/" />
<link rel="stylesheet" href="templates/style/main.css" />
<script src="templates/js/main.js"></script>
<script>var base = document.getElementsByTagName("base")[0].href;</script>
</head>
<body>
link
</body>
This way every relative link (i.e. not starting with / or a scheme) will become relative to the <base>.
This is by the way not specifically related to Tomcat in any way. It's just related to HTTP/HTML basics. You would have the same problem in every other webserver.
See also:
Browser can't access/find relative resources like CSS, images and links when calling a Servlet which forwards to a JSP
Is it recommended to use the <base> html tag?
Just use <c:url>-tag with an application context relative path.
When the value parameter starts with an /, then the tag will treat it as an application relative url, and will add the application-name to the url.
Example:
jsp:
<c:url value="/templates/style/main.css" var="mainCssUrl" />`
<link rel="stylesheet" href="${mainCssUrl}" />
...
<c:url value="/home" var="homeUrl" />`
home link
will become this html, with an domain relative url:
<link rel="stylesheet" href="/AppName/templates/style/main.css" />
...
home link
You start tomcat from some directory - which is the $cwd for tomcat. You can specify any path relative to this $cwd.
suppose you have
home
- tomcat
|_bin
- cssStore
|_file.css
And suppose you start tomcat from ~/tomcat, using the command "bin/startup.sh".
~/tomcat becomes the home directory ($cwd) for tomcat
You can access "../cssStore/file.css" from class files in your servlet now
Hope that helps, - M.S.
Instead using entire link we can make as below (solution concerns jsp files)
With JSTL we can make it like:
To link resource like css, js:
<link rel="stylesheet" href="${pageContext.request.contextPath}/style/sample.css" />
<script src="${pageContext.request.contextPath}/js/sample.js"></script>
To simply make a link:
<a id=".." class=".." href="${pageContext.request.contextPath}/jsp/sample.jsp">....</a>
It's worth to get familiar with tags
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
There is also jsp method to do it like below, but better way like above:
<link rel="stylesheet" href="<%=request.getContextPath()%>/style/sample.css" />
<script type="text/javascript" src="<%=request.getContextPath()%>/js/sample.js"></script>
To simply make a link:
<a id=".." class=".." href="<%=request.getContextPath()%>/jsp/sample.jsp">....</a>
This could be done simpler:
<base href="${pageContext.request.contextPath}/"/>
All URL will be formed without unnecessary domain:port but with application context.
This is a derivative of #Ralph suggestion that I've been using. Add the c:url to the top of your JSP.
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:url value="/" var="root" />
Then just reference the root variable in your page:
<link rel="stylesheet" href="${root}templates/style/main.css">
I've been trying to install the angularjs/restangular js libraries in my Grails app based on a chapter in Grails In Action. The problem is that the code in this book uses the resources plugin which has been replaced in the version of Grails I'm using (2.4) by the asset-pipeline plugin.
I've tried to implementing the book code using the official documentation as a guide, but the required javascript is not getting included in my gsp files. Also, references to <r:layoutResources/> and <r:require module="core"/> in my gsp files, are being highlighted as "unknown tags" in the GGTS editor.
Can anyone advise on where I've gone wrong migrating from the resources plugin to the asset-pipeline? Specifically I have copied the following js libraries into my web-app/js folder:
And I want to define dependencies between those modules and so I have created the following conf\ApplicationResources.groovy:
modules = {
angularjs {
resource url:'js/angular-1.3.15.js', disposition: 'head'
}
restangular {
dependsOn 'angularjs'
resource url:'js/restangular-1.4.0.js'
}
lodashjs {
resource url:'js/lodash-3.6.0.js'
}
core {
dependsOn 'restangular, lodashjs'
resource url:'/js/custom.js'
}
}
And views\layout\main.gsp contains:
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title><g:layoutTitle default="Grails"/></title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="${assetPath(src: 'favicon.ico')}" type="image/x-icon">
<link rel="apple-touch-icon" href="${assetPath(src: 'apple-touch-icon.png')}">
<link rel="apple-touch-icon" sizes="114x114" href="${assetPath(src: 'apple-touch-icon-retina.png')}">
<asset:stylesheet src="application.css"/>
<asset:javascript src="application.js"/>
<g:layoutHead/>
<r:layoutResources/> <-- why is this highlighted as 'unknown'?
</head>
And views\post\singlepage.gsp:
<head>
<title>Timeline for ${ user.userid }</title>
<meta name="layout" content="main"/>
<content tag="htmlAttrs">ng-app="testsparestang"</content>
<r:require module="core"/> <-- again, this is unknown!
</head>
If you want to use resource plugin please comment the asset-pipeline plugin code from your BuildConfig.groovy file.
And if you want to use asset-pipeline then just comment the resources plugin from the BuildConfig.groovy.
Now see to it that you remove the tag from your layout as this will work only with resources plugin and is not required with asset-pipeline.
Also the tag is from resources plugin. So change it as per the asset-pipeline
I have a simple web-app that I'm throwing together.
By & large, the default grails main.css is fine for all the scaffolded pages.
However, I want to supress this and use different, in-line css for the landing page.
How do I configure grails not to link main.css on a specific page?
The html is extremely simple, and contains no grails specific markup:
<!doctype html>
<html>
<head>
<meta name="layout" content="main" />
<title>My landing page</title>
<style type="text/css" media="screen">
body
{
background-color: #fff;
}
img {
display: block;
margin: auto;
}
</style>
</head>
<body>
<img alt="Welcome!"
src="${resource(dir:'images',file:'Landing.png') }">
</body>
</html>
Also -- is main.css linked purely out of convention, or is there some configuration lurking somewhere I haven't spotted? (I've done a search but couldn't find it anywhere).
Can someone please reference where in the docs it talks about these conventions?
main.css is included in your landing page because you have specified that your landing page is based on the main layout
<meta name="layout" content="main" />
this layout is defined by grails-app/views/layouts/main.gsp and includes the main.css, most likely with a tag like this in the <head> of the page:
<link rel="stylesheet" href="${resource(dir: 'css', file: 'main.css')}" type="text/css">
If you remove:
<meta name="layout" content="main" />
your landing page will no longer be based on the main layout, so it will not include anything defined therein (e.g. main.css).
However, rather than removing the layout completely just to prevent main.css from being included, it may be simpler to just override the CSS rules that you want to cusomise on the layout page by including custom rules in a <style> block in the <head> of the landing page
<style type="text/css">
body {
/* styles in here override styles from main.css */
}
</style>
Take a look at the resources plugin in grails 2.0.x. You can define Modules comprising of specific javascript and CSS files which will be compressed, optimized for the web. In the page of your choice, you can include the module you want. In your case, you could add a case like this in your main.gsp
<g:if test="${controllerName == "landing"}">
<link rel="stylesheet" href="${resource(dir: 'css', file: 'custom.css')}"/>
</g:if>
<g:else>
<link rel="stylesheet" href="${resource(dir: 'css', file: 'main.css')}"/>
</g:else>
Setting up a simple grails app with Dojo, i used the
grails install-plugin dojo
to setup the dojo js files. In my main.gsp i have this
<html>
<head>
<title><g:layoutTitle default="Grails" /></title>
<link rel="stylesheet" href="${resource(dir:'css',file:'main.css')}" />
<link rel="shortcut icon" href="${resource(dir:'images',file:'favicon.ico')}" type="image/x-icon" />
<g:layoutHead />
<g:javascript library="application"/>
<g:javascript library="dojo"/>
<dojo:header modules="['dojo.data.ItemFileReadStore','dijit.form.ComboBox']"/>
<g:javascript>
//dojo.addOnLoad(function(){alert("dojo loaded.");});
</g:javascript>
</head>
On my index.gsp page, i setup the following elements
<div>
<div jsId="search" dojoType="dojo.data.ItemFileReadStore"
url="<g:createLink controller="runner" action="findrunner"/>"></div>
<input dojoType="dojo.data.FilteringSelect"
id="chooser"
name="feed"
store="search"
searchAttr="url"
autocomplete="true"
pageSize="5"/>
</div>
Start the app but keep getting this error from firebug
GET http://localhost:8080/xxx/js/dojo/1.4.3/dojo/data/ItemFileReadStore.js
404 Not Found
5ms
dojo.js (line 16)
ParamsHeadersPostPutResponseCacheHTML
..</head><body><h1>HTTP Status 404 - /xxx/js/dojo/1.4.3/dojo/data/ItemFileReadStore.js</h1>
<HR size="1" noshade="noshade"><p><b>type</b> Status report</p><p><b>message</b>
<u>/xxx/js/dojo/1.4.3/dojo/data/ItemFileReadStore.js</u></p><p><b>description</b>
<u>The requested resource (/xxx/js/dojo/1.4.3/dojo/data/ItemFileReadStore.js) is not available.</u>
</p><HR size="1" noshade="noshade"><h3>Apache Tomcat/6.0-snapshot</h3></body></html>
Any ideas?
Seems the 'dojo plugin' didn't seems to install all the required dojo files. I manually installed dojo 1.5 and extract the zip to /webapps/js/dojo/1.5.0 and enabled the version in my main.gsp like this
<script src="js/dojo/1.5.0/dojo/dojo.js"></script>
The new plugin version makes things a lot easier now. There is even a script to launch your custom builds in a breeze... and it's updated to dojo 1.6. Give it a try ;-)