JSF <h:outputStyleshet> doesn't seem to cope with relative links in the css when using a library attribute

StackOverflow https://stackoverflow.com/questions/23385819

  •  12-07-2023
  •  | 
  •  

Question

I'm quite new to JSF so not sure if I'm just being dim, but when I use <h:outputStylesheet library="default" name="bootstrap/css/bootstrap.css"/> the style sheet is included fine, however the relative links in the following section of the bootstrap css:

@font-face {
  font-family: 'Glyphicons Halflings';

  src: url('../fonts/glyphicons-halflings-regular.eot');
  src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');
}

don't work. The only way I've found to get them to work is to remove the library and manually specificy the bootstrap css as <h:outputStylesheet name="default/1_2/bootstrap/css/bootstrap.css"/> or to edit the css to include ?ln=default on the URLs.

I don't want to edit the bootstrap.css as it seems a crazy thing to have to do, and I dont' really want to have to manually update 1_2 to 1_3 in my template when I make a change to the CSS. Can anyone offer any alternatives. For instance is there a way to get the faces servlet to assume ln=default ?

Was it helpful?

Solution

Since the outputStylesheet appends the library and version parameters to the end of the resource url, you cannot use relative paths inside of your css.

Option 1: You need to convert the url attributes inside your css to use JSF style paths using the following EL pattern:

#{resource['<libarary>:<filepath>']}

For example, if you have your fonts installed within the default library at "default/bootstrap/fonts", you need to change your css file as follows:

src: url('#{resource['default:bootstrap/fonts/glyphicons-halflings-regular.eot']}');



Option 2: If you don't want to modify your css file, the other option is to add a filter to forward the relative path request into the proper faces formatted path by appending the expected .xhtml and the default library name:

import java.io.IOException;

import javax.faces.application.ResourceHandler;
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;


@WebFilter(value = "/*", dispatcherTypes = { DispatcherType.REQUEST, DispatcherType.FORWARD })
public class RelativePathFacesFilter implements Filter {

    private FilterConfig filterConfig;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        String requestPath = ((HttpServletRequest) request).getServletPath();
        if (requestPath.startsWith(ResourceHandler.RESOURCE_IDENTIFIER) && !requestPath.endsWith(".xhtml")) {
            String path = requestPath + ".xhtml?ln=default";
            filterConfig.getServletContext().getRequestDispatcher(path).forward(request, response);
            return;
        }

        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
    }

}

The warning behind using this method is that you're skipping the benefit of resource versioning, which will make it harder to deliver updates to that version without requiring that they flush their browser cache. The easiest workaround to this is to include the version of the resource within the resource name itself (e.g. bootstrap_1_0/css/bootstrap.css).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top