- Notifications
You must be signed in to change notification settings - Fork 57
Script resources in <body> are never run during Ajax requests #4340
Description
Steps to Reproduce:
-
Create the following 3 files in a webapp:
index.xhtml:<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html" xmlns:f="http://xmlns.jcp.org/jsf/core"> <h:head/> <h:body> <h:form> <h:commandButton value="result.xhtml" action="result.xhtml"> <f:ajax render="@all" /> </h:commandButton> </h:form> </h:body> </html>result.xhtml<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html"> <h:head /> <h:body> <h:outputScript name="result.js" /> </h:body> </html>result.js:document.getElementsByTagName('body')[0].innerHTML += '<div id="result">SUCCESS</div>'; -
Navigate to
index.xhtml. -
Click the result.xhtml button to navigate to
result.xhtml.
If the bug still exists, an empty page will appear indicating that result.js has not been loaded.
If the bug is fixed, then "SUCCESS" will appear indicating that result.js was loaded correctly.
Explanation
jsf.js attempts to strip scripts out of the partial response and run them separately using this regex:
/<script[^>]*type="text\/javascript"*>([\S\s]*?)<\/script>/igm. Unfortunately, this regex fails to match any script resources since they all include attributes after type="text/javascript" (which the regex above expects to be the last attribute). Since the scripts are not removed, the scripts are added to the HTML document. Then jsf.js attempts to run the partial response scripts. Before running each script resource, jsf.js checks whether it appears in the HTML document (via its src attribute). Since the partial response script resources were never stripped, jsf.js has added them to the HTML document. So jsf.js finds them in the view, and they are never run since they appear to have already been run.
Workarounds
One workaround to this bug would be to ensure that type="text/javascript" is always the last attribute rendered on each <script> via a custom ResponseWriterWrapper. This would ensure that <script>s are correctly stripped from the partial response before jsf.js adds the markup to the view.