This question already has answers here:
Why split the <script> tag when writing it with document.write()?
(5 answers)
Closed 8 years ago.
How can I write a HTML-conform String to a new window using a JSP with inner Javascript?
Our Situation:
- Theres a .jsp-File used by a Tomcat-Server
- The .jsp contains a <script language="Javascript>-Tag
- this script needs to write a complete, HTML-5-valid-String to a new Window using window.open and 'window'.document.write(htmlString)
Our .jsp-File (schematic):
<%# include file = "..." %>
<...some page imports...>
<...some scripts...>
(e.g. <script type = "text/javascript" src="...."> </script>)
<%
String strMethod = "foo_Method_Bar";
String strOutput = "";
strOutput = someJavaBean-Call_that_brings_valid_html5_string_with_script-Nodes;
%>
...
<script language="Javascript">
var strHTML = "<%=strOutput%>";
var win = window.open('','','width=...,height=...');
win.document.write(strHTML);
top.close();
win.focus();
</script>
Our Problem (schematic):
- .jsp-File gets called.
- .jsp-File calls a JavaBean and sets a global String-Variable to the HTML-String (including <script>-Tags, DocType-Declarations, etc.)
- .jsp-File replaces all occurrences of the Variable with the obtained String
- javascript (<script>-Tag in the .jsp-File) gets Executed
- <script>-Tag of Javascript is already closed, before 'window'.document.write(strHTML) gets executed, because theres a </script>-Tag in the Javascript
e.g.
<script language="Javascript">
var strHTML = "<!DOCTYPE html> <html> ... <script> ... </script> ... </html>;
var win = window.open(...);
win.document.write(strHTML);
</script>
- I've searched for quite some time now and I don't have a clue how to solve this issue.
- Writing the HTML-Sourcecode into the Server-File-System and accessing it later on or something like that would be really, really dirty.
- Part of the Problem is that we (of course) have to use this type of javascript-call in the .jsp-File for historical reasons...;-)
- Is there maybe a way to assign the strHTML-Variable in the .jsp-File by Reference only (e.g. without replacing the <%=strOutput%>-Variable)?
Additional Info:
The HTML-String-Generation is used at various places of our programs, multiple times, so i hoped not to have to escape any special CharacterSequences for this particular Call to work.
Appreciate all your help and ideas on this...;-)
Solved:
See also Why split the tag when writing it with document.write()? on this issue.
You MUST escape the closing script in the string <\/script> unless the document.write lives in an external .script
Also remember to close the document, and no spaces in the parameters to window.open
like this
<script type="text/javascript">
var strHTML = '<!DOCTYPE html> <html> ... <script> ... <\/script> ... </html>';
var win = window.open("","winname","resizable,scrollbars");
win.document.write(strHTML);
win.document.close();
</script>
Related
I have a project with Java 8, bringing data to the frontend with Thymeleaf. The data entity I want to ouput in my frontend is calles logs and is a list of entities that have an attribute containig json data. I output it in the html file as follows:
<script type="text/javascript">
let logs = [[${logs}]];
</script>
The json has the following structure:
{
"oldest": 712367620,
"youngest": 712378606,
"measurements": []
}
But on the page it appears with the double quotes escaped which completely messes up the js:
<script type="text/javascript">
let logs = [LogEntity(id=52, success=true, runtimes={
"oldest" : 712367620,
"youngest" : 712378606,
"measurements" : []
})]
</script>
How can I prevent the escaping of the double quotes in the json string?
I work with php and twig in another project and there it is as simple as {{ logs|raw }}. Is there some kind of modifier in thymeleaf like |raw in php twig?
Security is not an issue since I have complete control over the data objects.
You have to enable JavaScript inlining with th:inline="javascript":
<script type="text/javascript" th:inline="javascript">
let logs = [[${logs}]];
</script>
(I'm not sure what you mean by "json data". Do you mean you have a String that contains JSON?)
I need to store the html retrieved from a <jsp:include> in a javascript variable. So I will have something like this
<script>
var html = '<jsp:include page="...">';
</script>
The problem is the jsp file has lots of whitespace and newlines which makes the javascript invalid! I tried using the trimDirectiveWhitespaces directive as suggested here, but that does not remove newlines.
How can I remove newlines as well from html so it can be a valid javascript string?
Or, another solution is welcome as well.
EDIT:
The snippet should eventually look like this (but with many more options):
<script>
var html = '<label class="someClass">Label</label><select><option value="val1">Value</option></select>';
</script>
This question already has answers here:
Access Java / Servlet / JSP / JSTL / EL variables in JavaScript
(5 answers)
Closed 5 years ago.
I want to read a jstl variable in a javascript function.
JS code submits a form.
$("#userSubmit").on('submit', function () {
document.getElementById("userForm").submit();
});
So in server code -
request.setAttribute("userId", 435);
and after the page is loaded -> in the javascript code -
$("#textBoxInp").keyup(function() {
// I want to access the userId here.
// in html code i can acccess it using JSTL syntax ${userId}
});
Just write the Expression Language directly in your JavaScript code:
$("#textBoxInp").keyup(function() {
var userId = '${userId}';
});
Note that this won't work if the JavaScript code is placed in a external file and is invoked in the JSP. In this case, you may refer to one of the four ways that BalusC explain here: Mixing JSF EL in a Javascript file (he explains five, but one of them is JSF specific).
One way is as suggested by Mendoza, but it will not work in case of having separate Javascript file.
in that case, another way is adding hidden field in JSP page, and reading same from Javascript.
JSP code:
<input type="hidden" id="xID" name="x" value="${myAttribute}">
JS code:
var myAtt = document.getElementById("xID").value;
If you want to access jstl variable in a javascript script function, you won't be able to access them directly. Here's a roundabout way(easy to implement) to do it.
In the HTML code have a paragraph with the required variable.
<p id = "var" disabled = "disabled">${variable}</p>
Access the variable using .innerHTML inside the JavaScript function.
function myFunction() {
var jstl_var = document.getElementById("var").innerHTML;
}
totalClients is jstl variable and to read in javascript block please see below
<script type="text/javascript">
$(document).ready(function() {
var tc = "<c:out value='${totalClients}'/>";
});
In an ideal world I would like to separate out Javascript to a completely different file and include it in the JSP page. But there are cases were I struggle to follow this rule simply because dynamically generated Javascript is so much easier to write !!
Couple of examples :
1) Locale specific error messages in alert boxes.
<%
Locale locale = ..//get current locale
%>
<script language="JavaScript">
function checkMessage() {
if(document.form.msg.value=='') {
alert(<%= *LocaleHelper.getMessage(locale,"please_provide_message")* %>); //get the locale specific message . mixing Javascript and JSP !!!
}
}
2) Initializing values .Sometimes you need to get values using JSP which will be used inside a javascript method
function computeExpiry () {
var creationDate= <%= creationDate =%>
var currentDate = document.form.date.value;
var jsCreationDate= converToDate(creationDate);
return currentDate>creationDate ;
}
3) Initializing config objects dynamically
var myConfig = {
modal:true,
resize:true,
<% if (lastPage) { %>
showPreviousButton :true,
showNextButton : false ,
showSubmitButton : true,
<%} else {%>
showPreviousButton :true,
showNextButton : true ,
showSubmitButton : false,
<%} %>
As you can imagine, without any kind of conventions , all our JSPs will be a unsightly mix of Javascript and JSP, hard to understand and maintain, with lots of non-reusable javascript code
I am not looking for a perfect solution. I know its easier to do this than try to maintain a pure Javascript and JSP separation. I am looking for suggestions to ease this process and hope lots of people have experience worth sharing.
Mixing JavaScript and JSP makes code harder to read, reuse, maintain and also degrades performance(such JS code cannot be externalized and compressed). Avoid that when possible.
One way is collecting all JSP related variables in one place and factoring out non-JSP codes into another pure/static JavaScript files. For example:
<script type='text/javascript' >
var app = { // global app "namespace" holds app-level variables
msg: "<%= *LocaleHelper.getMessage(locale,"please_provide_message")* %>";
creationDate: <%= creationDate =%>;
btnConfig: {
<% if (lastPage) { %>
showNextButton : false ,
showSubmitButton : true,
<%} else {%>
showNextButton : true ,
showSubmitButton : false,
<%} %>
}
};
</script>
// following JS has no JSP, you can externalize them into a separate JS file
// s.t. they can be compressed and cached.
function checkMessage() {
if(document.form.msg.value=='') {
alert(app.msg);
}
}
function computeExpiry () {
var creationDate= app.creationDate;
var currentDate = document.form.date.value;
var jsCreationDate= converToDate(creationDate);
return currentDate > creationDate;
}
var myConfig = _.extend({ // underscore library's extend
modal: true,
resize: true,
showPreviousButton: true,
}, app.btnConfig);
BTW, in practical application, I recommend module loader library like RequireJS instead of defining global variables primitively.
I try to avoid this but when I have to pass data from back-end to front-end I use a flat JavaScript Object which is created by a Hash in the backend. You can convert Hashes in any language to JSON strings. Place a <script> tag in your HTML page and dump that JSON string in it and assign it to a JavaScript variable.
For example:
<script>
var dataFromBackEnd = JSON.parse(<%= Hash.toJSON(); %>); // I'm just assuming JSP part
</script>
From this point JavaScript should take care about logic. If there is a condition that JS need to take action about it pass the boolean value of it to JS. Don't mix logic.
First you can do is avoing using scriptlets. Instead using it use JSP tags, as JSTL. It will allow you to format your code better.
arrays.jsp:
//...
var x = <c:out value="${x}"/>
<c:if test="${empty doExternal}">
processExternalArrays();
</c:if>
//...
I want to minify/obfuscate JavaScript contained in a large JSP file in which numerous JSP/JSTL variables are mixed into the JavaScript code such as in the snippet above.
The code relies on variables populated using server-side logic and then passed to the client-side code, as above.
I'm already minifying my JS files using YUI compressor but I don't know what to do about the JavaScript code in my JSPs.
Is it possible to minify/obfuscate this code, given that it is dynamically created?
Probably the best solution for you would be use Granule JSP tag.
You can download it at
http://code.google.com/p/granule/
code sample is:
<g:compress>
<script type="text/javascript" src="common.js"/>
<script type="text/javascript" src="closure/goog/base.js"/>
<script>
goog.require('goog.dom');
goog.require('goog.date');
goog.require('goog.ui.DatePicker');
</script>
<script type="text/javascript">
var dp = new goog.ui.DatePicker();
dp.render(document.getElementById('datepicker'));
</script>
</g:compress>
...
Have you taken a look at htmlcompressor? In short it's a:
Java HTML/XML Compressor is a very
small, fast and easy to use library
that minifies given HTML or XML source
by removing extra whitespaces,
comments and other unneeded characters
without breaking the content
structure.
It's main function is so compress HTML and XML, but it also comes with JSP tags that can be used to compress inline JavaScript blocks by leveraging YUI Compressor. Check out the Google Code page, especially the Compressing selective content in JSP pages section.
I don't see other ways than fully delegating the job to pure JS with help of Ajaxical powers in combination with a Servlet which returns the desired information on an Ajax request (in flavor of JSON?).
E.g. in Servlet
Map<String, Object> data = new HashMap<String, Object>();
data.put("doExternal", doExternal);
data.put("x", x);
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
response.getWriter().write(new Gson().toJson(data)); // Gson is a Java-JSON converter.
and in JS (with little help of jQuery since it makes the Ajax works less verbose)
$.getJSON('servleturl', function(data) {
var x = data.x;
if (!data.doExternal) {
processExternalArrays();
}
});
This way you end up with clean JS without server-side specific clutter.
Ensure that your output is gzip encoded (apache mod_deflate). Minimizing the html/js first may make it a bit smaller, but not by much.
If you can't, or don't want to, move your JavaScript out of your HTML, one possibility would be to create a tag handler that wraps the content of your <script> tags:
<script type="text/javascript"><js:compress>
...
</js:compress></script>
The handler could probably extend SimpleTagSupport. You'd then have to investigate the Java APIs for compressors/minifiers, like YUI Compressor or dojo ShrinkSafe, and use them to process the tag body.
Edit: Sorry, I skimmed the other answers and it appears that Zack Mulgrew might be referencing a taglib that already does exactly what I'm suggesting...
Edit2: Yup, JavaScriptCompressorTag. Guess I'll have to up-vote his answer ;-)...