Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I get JSF 2.0 to include JS as 'application/javascript' instead of 'text/javascript'

In our JSF 2.0 application at work, we include several javascript files via <h:outputscript>.

<h:outputScript library="javascript" name="DoStuff.js"/>

The resulting html references them as 'text/javascript'.

<script type="text/javascript" src="/mycontext/javax.faces.resource/DoStuff.js.jsf?ln=javascript"></script>

According to this question, "text/javascript" is obsolete, what's more, htmlunit complains about the type rather verbosely. Of course, everything works just fine and I could shut off htmlunit's logging, but I'd rather have JSF generate the correct type.

Is there a way to override the type chosen by <h:outputscript>?

like image 721
Urs Reupke Avatar asked Jul 13 '11 07:07

Urs Reupke


People also ask

How to include external JavaScript file in JSF?

In JSF 2.0, you can use <h:outputScript /> tag to render a HTML “script” element, and link it to a js file.

Can you use Javascript in JSF?

The h:outputScript tag renders an HTML element of the type "script" with type "text/javascript". This tag is used to add an external javascript file to JSF page.

Can we use jQuery in JSF?

You need to do a few things for jQuery to work with JSF 2.0. Assign ID for all relevant UI components and their parents. Only then can you be sure about the DOM element ID of the component you are trying to manipulate.


1 Answers

This is hardcoded in the default renderer of the <h:outputScript>. Assuming that you're using Mojarra, it's the com.sun.faces.renderkit.html_basic.ScriptRenderer. According to the source, the type attribute is been set in the startElement method. You could just override it:

public class ExtendedScriptRenderer extends ScriptRenderer {

    @Override
    protected void startElement(ResponseWriter writer, UIComponent component) throws IOException {
        writer.startElement("script", component);
        writer.writeAttribute("type", "application/javascript", "type");
    }

}

Or if you want to provide the enduser the possibility to specify the type attribute itself and default to application/javascript when unspecified:

public class ExtendedScriptRenderer extends ScriptRenderer {

    @Override
    protected void startElement(ResponseWriter writer, UIComponent component) throws IOException {
        writer.startElement("script", component);
        String type = (String) component.getAttributes().get("type");
        if (type == null) type = "application/javascript";
        writer.writeAttribute("type", type, "type");
    }

}

To get it to run, register it as follows in faces-config.xml:

<render-kit>
    <renderer>
        <component-family>javax.faces.Output</component-family>
        <renderer-type>javax.faces.resource.Script</renderer-type>
        <renderer-class>com.example.ExtendedScriptRenderer</renderer-class>
    </renderer>
</render-kit>

There's by the way also the nice @FacesRenderer annotation which should work as follows

@FacesRenderer(componentFamily="javax.faces.Output", rendererType="javax.faces.resource.Script")
public class ExtendedScriptRenderer extends ScriptRenderer {

    // ...
}

However, when it's already been definied by a standard renderer (the ScriptRenderer!), then the custom one will fail to override it by a @FacesRenderer. See also issue 1748.

like image 142
BalusC Avatar answered Sep 23 '22 03:09

BalusC