The JSF <h:outputStylesheet>, <h:outputScript> and <h:graphicImage> components have a library attribute. What is this and how should this be used? There are a lot of examples on the web which use it as follows with the common content/file type css, js and img (or image) as library name depending on the tag used:
<h:outputStylesheet library="css" name="style.css" />
<h:outputScript library="js" name="script.js" />
<h:graphicImage library="img" name="logo.png" />
How is it useful? The library value in those examples seems to be just repeating whatever is already been represented by the tag name. For a <h:outputStylesheet> it's based on the tag name already obvious that it represents a "CSS library". What's the difference with the following which also just works the same way?
<h:outputStylesheet name="css/style.css" />
<h:outputScript name="js/script.js" />
<h:graphicImage name="img/logo.png" />
Also, the generated HTML output is a bit different. Given a context path of /contextname and FacesServlet mapping on an URL pattern of *.xhtml, the former generates the following HTML with the library name as request parameter:
<link rel="stylesheet" type="text/css" href="/contextname/javax.faces.resource/style.css.xhtml?ln=css" />
<script type="text/javascript" src="/contextname/javax.faces.resource/script.js.xhtml?ln=js"></script>
<img src="/contextname/javax.faces.resource/logo.png.xhtml?ln=img" alt="" />
While the latter generates the following HTML with the library name just in the path of the URI:
<link rel="stylesheet" type="text/css" href="/contextname/javax.faces.resource/css/style.css.xhtml" />
<script type="text/javascript" src="/contextname/javax.faces.resource/js/script.js.xhtml"></script>
<img src="/contextname/javax.faces.resource/img/logo.png.xhtml" alt="" />
The latter approach makes in hindsight also more sense than the former approach. How exactly is the library attribute then useful?
Actually, all of those examples on the web wherein the common content/file type like "js", "css", "img", etc is been used as library name are misleading.
Real world examples
To start, let's look at how existing JSF implementations like Mojarra and MyFaces and JSF component libraries like PrimeFaces and OmniFaces use it. No one of them use resource libraries this way. They use it (under the covers, by #ResourceDependency or UIViewRoot#addComponentResource()) the following way:
<h:outputScript library="javax.faces" name="jsf.js" />
<h:outputScript library="primefaces" name="jquery/jquery.js" />
<h:outputScript library="omnifaces" name="omnifaces.js" />
<h:outputScript library="omnifaces" name="fixviewstate.js" />
<h:outputScript library="omnifaces.combined" name="[dynamicname].js" />
<h:outputStylesheet library="primefaces" name="primefaces.css" />
<h:outputStylesheet library="primefaces-aristo" name="theme.css" />
<h:outputStylesheet library="primefaces-vader" name="theme.css" />
It should become clear that it basically represents the common library/module/theme name where all of those resources commonly belong to.
Easier identifying
This way it's so much easier to specify and distinguish where those resources belong to and/or are coming from. Imagine that you happen to have a primefaces.css resource in your own webapp wherein you're overriding/finetuning some default CSS of PrimeFaces; if PrimeFaces didn't use a library name for its own primefaces.css, then the PrimeFaces own one wouldn't be loaded, but instead the webapp-supplied one, which would break the look'n'feel.
Also, when you're using a custom ResourceHandler, you can also apply more finer grained control over resources coming from a specific library when library is used the right way. If all component libraries would have used "js" for all their JS files, how would the ResourceHandler ever distinguish if it's coming from a specific component library? Examples are OmniFaces CombinedResourceHandler and GraphicResourceHandler; check the createResource() method wherein the library is checked before delegating to next resource handler in chain. This way they know when to create CombinedResource or GraphicResource for the purpose.
Noted should be that RichFaces did it wrong. It didn't use any library at all and homebrewed another resource handling layer over it and it's therefore impossible to programmatically identify RichFaces resources. That's exactly the reason why OmniFaces CombinedResourceHander had to introduce a reflection-based hack in order to get it to work anyway with RichFaces resources.
Your own webapp
Your own webapp does not necessarily need a resource library. You'd best just omit it.
<h:outputStylesheet name="css/style.css" />
<h:outputScript name="js/script.js" />
<h:graphicImage name="img/logo.png" />
Or, if you really need to have one, you can just give it a more sensible common name, like "default" or some company name.
<h:outputStylesheet library="default" name="css/style.css" />
<h:outputScript library="default" name="js/script.js" />
<h:graphicImage library="default" name="img/logo.png" />
Or, when the resources are specific to some master Facelets template, you could also give it the name of the template, so that it's easier to relate each other. In other words, it's more for self-documentary purposes. E.g. in a /WEB-INF/templates/layout.xhtml template file:
<h:outputStylesheet library="layout" name="css/style.css" />
<h:outputScript library="layout" name="js/script.js" />
And a /WEB-INF/templates/admin.xhtml template file:
<h:outputStylesheet library="admin" name="css/style.css" />
<h:outputScript library="admin" name="js/script.js" />
For a real world example, check the OmniFaces showcase source code.
Or, when you'd like to share the same resources over multiple webapps and have created a "common" project for that based on the same example as in this answer which is in turn embedded as JAR in webapp's /WEB-INF/lib, then also reference it as library (name is free to your choice; component libraries like OmniFaces and PrimeFaces also work that way):
<h:outputStylesheet library="common" name="css/style.css" />
<h:outputScript library="common" name="js/script.js" />
<h:graphicImage library="common" name="img/logo.png" />
Library versioning
Another main advantage is that you can apply resource library versioning the right way on resources provided by your own webapp (this doesn't work for resources embedded in a JAR). You can create a direct child subfolder in the library folder with a name in the \d+(_\d+)* pattern to denote the resource library version.
WebContent
|-- resources
| `-- default
| `-- 1_0
| |-- css
| | `-- style.css
| |-- img
| | `-- logo.png
| `-- js
| `-- script.js
:
When using this markup:
<h:outputStylesheet library="default" name="css/style.css" />
<h:outputScript library="default" name="js/script.js" />
<h:graphicImage library="default" name="img/logo.png" />
This will generate the following HTML with the library version as v parameter:
<link rel="stylesheet" type="text/css" href="/contextname/javax.faces.resource/css/style.css.xhtml?ln=default&v=1_0" />
<script type="text/javascript" src="/contextname/javax.faces.resource/js/script.js.xhtml?ln=default&v=1_0"></script>
<img src="/contextname/javax.faces.resource/img/logo.png.xhtml?ln=default&v=1_0" alt="" />
So, if you have edited/updated some resource, then all you need to do is to copy or rename the version folder into a new value. If you have multiple version folders, then the JSF ResourceHandler will automatically serve the resource from the highest version number, according to numerical ordering rules.
So, when copying/renaming resources/default/1_0/* folder into resources/default/1_1/* like follows:
WebContent
|-- resources
| `-- default
| |-- 1_0
| | :
| |
| `-- 1_1
| |-- css
| | `-- style.css
| |-- img
| | `-- logo.png
| `-- js
| `-- script.js
:
Then the last markup example would generate the following HTML:
<link rel="stylesheet" type="text/css" href="/contextname/javax.faces.resource/css/style.css.xhtml?ln=default&v=1_1" />
<script type="text/javascript" src="/contextname/javax.faces.resource/js/script.js.xhtml?ln=default&v=1_1"></script>
<img src="/contextname/javax.faces.resource/img/logo.png.xhtml?ln=default&v=1_1" alt="" />
This will force the webbrowser to request the resource straight from the server instead of showing the one with the same name from the cache, when the URL with the changed parameter is been requested for the first time. This way the endusers aren't required to do a hard refresh (Ctrl+F5 and so on) when they need to retrieve the updated CSS/JS resource.
Please note that library versioning is not possible for resources enclosed in a JAR file. You'd need a custom ResourceHandler. See also How to use JSF versioning for resources in jar.
See also:
JSF resource versioning
JSF2 Static resource caching
Structure for multiple JSF projects with shared code
JSF 2.0 specification - Chapter 2.6 Resource Handling
Related
I have a project in jsf that is shared by multiple projects. The structure of the project is the same as that mentioned in the answer to the question Structure for multiple JSF projects with shared code
The someTemplate.xhtml mentioned in that structure has a outputStyleSheet statement immediately after the opening
<h:body>
tag :
<h:outputStylesheet name="css/some.css" library="common"></h:outputStylesheet>
The shared project is packaged into shared.jar and is placed into the WEB-INF/lib directory of a client project.
When I make a client file (as part of a client project) that uses the someTemplate.xhtml as a template using
<ui:composition template="/common/someTemplate.xhtml">
the file some.css is not recognized. None of the styles mentioned in some.css take effect.
When I look into the source of the page that is generated, I see these two lines:
<link type="text/css" rel="stylesheet" href="/javax.faces.resource/some.css.jsf" />
<link type="text/css" rel="stylesheet" href="RES_NOT_FOUND" />
I have tried many different combinations of file names and locations for the css file, and the template file as well. But the problem remains the same. In all cases, the styles in some.css were not recognized. I am also curious as to why it says 'RES_NOT_FOUND' in the href. Any help will be highly appreciated.
Thanks
Mahendra
Here is my setup:
Web app 's folder structure and file names are exactly the same as the UnmappedResourceHandler 's javadoc
UnmappedResourceHandler is already registered in faces-config.xml
/javax.faces.resource/* is already mapped to facesServlet in web.xml
The style.css is :
body {
background: url("image/background.png");
}
body .test{
background-image: url("#{resource['css:image/background.png']}");
}
Then I request http://localhost:8080/app/javax.faces.resource/style.css?ln=css and the respond is :
body {
background: url("image/background.png");
}
body .test{
background-image: url("/app/javax.faces.resource/image/background.png?ln=css");
}
I expect that all the relative URLs in CSS will be converted to the JSF 's valid URL like what #{resource} does such that I do not have to use #{resource} to refer to the relative URLs in CSS anymore , but the background 's relative URL of the body selector still remains unchanged .
Update to BalusC 's reply:
If resource library is used , adding ?ln=libraryname to all CSS images will work!
But if resource library is not used , <h:outputStylesheet name="css/style.css" /> generates <link rel="stylesheet" media="screen" type="text/css" href="/app/javax.faces.resource/css/style.css.xhtml">
If I understand correctly from this , using UnmappedResourceHandler and mapping
/javax.faces.resource/* to the facesServlet in web.xml should cause JSF generates the link of the style.css without xhtml extension.
You're using css as a resource library as in:
<h:outputStylesheet library="css" name="style.css" />
This is not right. It's just a folder:
<h:outputStylesheet name="css/style.css" />
This will produce /javax.faces.resource/css/style.css URL instead of /javax.faces.resource/style.css?ln=css. You've otherwise to specify it in the image URL as well:
background: url("image/background.png?ln=css");
I will update the javadoc to clarify that more.
See also:
What is the JSF resource library for and how should it be used?
i have an external CSS file in the resources folder under WebContent folder, and i included it at the page header as follows:
<h:head>
<h:outputStylesheet name="css/style.css" library="css" />
</h:head>
i tried a simple selector to test the if the file is working like body {background-color:#b0c4de;} but unfortunately the file isn't linked
for more clarity i included here a screenshot for the exact location of the resources folder
First of all, this is not an external CSS file at all. It's internal to your web application. A real external CSS file would be served from a different domain and is not importable via <h:outputStylesheet>, but only via <link>.
Your concrete problem is caused because you unnecessarily repeated the CSS file folder into the library attribute. Just get rid of it.
<h:outputStylesheet name="css/style.css" />
The library attribute must represent the common module/theme/library name, such as "primefaces", but you don't have any here. Using a library name of "css" makes no utter sense as "css" just represents the file/content type.
See also:
How to reference CSS / JS / image resource in Facelets template?
What is the JSF resource library for and how should it be used?
Try
h:outputStylesheet name="style.css" library="css" />
here is a ref:
http://www.mkyong.com/jsf2/how-to-include-cascading-style-sheets-css-in-jsf/
Say I have a resources/ folder in the webroot. In it, I have a css/ folder and in it there is a theme.css file.
But I want to set an Expires: header. Therefore I want to use a version for resource libraries, say
<h:outputStylesheet library="css" name="theme.css"/>
would turn into
<link rel="stylesheet" src="javax.faces.resources/theme.css.xhtml?ln=css"/>
But I want to specify something like
<h:outputStylesheet library="css" name="theme.css" version="1.2"/>
And get
<link rel="stylesheet" src="javax.faces.resources/theme.css.xhtml?ln=css&v=1_2"/>
or similar. I have read that JSF2 has support for resource versioning, but how do I specify which version to load, and where do I put the files?
If you suppose to have the css library, you should use this directories naming scheme:
resources/css/1_1
resources/css/1_2
where resources in the jsf standard resource directory
I have the following on my main jsf wrapper page:
<head>
<meta http-equiv="Content-Type" content="text/xhtml; charset=UTF-8"/>
<title>
<ui:insert name="pageTitle" />
</title>
<a4j:loadScript src="resource://jquery.js" />
<a4j:loadScript src="resource:///bla/html/js/base.js" />
<a4j:loadScript src="resource:///bla/html/js/common.js" />
<a4j:loadScript src="resource:///bla/html/js/inactivity.js" />
</head>
Now I have a new page on the site and it requires some js functions. So i have created a new js file, myNewJSFile.js
I only want it loaded if a user lands on this page so obviosuly I dont want to add it to my above list of files in the head. Additionally I'd rather not include it at the top of my new page.
What I want is one place where I can define what files to load based on the current page.
So somthing like this (Pseudo code):
main jsf wrapper:
<head>
<jsIncludes>
</head>
jsIncludes file:
<a4j:loadScript src="resource://jquery.js" />
<a4j:loadScript src="resource:///bla/html/js/base.js" />
<a4j:loadScript src="resource:///bla/html/js/common.js" />
<a4j:loadScript src="resource:///bla/html/js/inactivity.js" />
<if page == "myNewPage>
<a4j:loadScript src="resource:///bla/html/js/myNewJsFile.js" />
<elfeif ...>
...
</if>
Is there a simple way of doing this?
Thanks
a4j:loadScript always places the javascript in the <head>, no matter where you use it, you have to do nothing. (the doc doesn't mention this for some strange reason)
So to answer your question: if you use <a4j:loadScript src="resource:///bla/html/js/myNewJsFile.js" /> in the page where you need it, the <script style="text/javascript" src="..." /> will appear in the <head>.
I'd rather add another <ui:insert> to the <head> of the main template.
<head>
...
<ui:insert name="headContent" />
</head>
Then in the page template, just define the additional script to be inserted there.
<ui:composition template="main.xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:a4j="http://??? can't tell from top of head :)"
>
<ui:define name="headContent">
<a4j:loadScript src="resource:///bla/html/js/myNewJsFile.js" />
</ui:define>
...
</ui:composition>