I'm building a freemarker template to generate a jsp view. Using a layout in 2 columns where each field in a form is floating and occupies the entire width of the column.
Each field type is in a independent FTL to easily add and remove fields.
FTL template has the following code:
<#if (data)?has_content>
<%# page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%# taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<#include "estructura/Cabecera.ftl">
<s:include value="${tipoFormulario}_${data.Artefacto.nombreSubModulo?lower_case}_scripts.jsp"></s:include>
</head>
<body>
<div class="" id="dim-listas">
<s:fielderror />
</div>
<s:form theme="simple" action="Mostrar${data.Artefacto.nombreSubModulo?cap_first}.action">
<#-- Estructura en columnas, parseo usando CSS -->
<#list data.Artefacto.formulario.grupoCampos as grupoCampos>
<div class="grupoCampos" <#if grupoCampos[0].#id[0]?has_content >id="${grupoCampos[0].#id[0]!}"</#if> <#if grupoCampos[0].#estilo[0]?has_content >style="${grupoCampos[0].#estilo[0]!}"</#if>>
<#list grupoCampos?children as nodos>
<#if nodos?node_type = 'element' && chequearPermisos(nodos[0].#permiso[0]!"all")>
<#if ((nodos[0].#mostrar[0]!"todos") == 'todos' || (nodos[0].#mostrar[0]!"todos") == tipoFormulario)>
<div style="${nodos[0].#estilo[0]!}" <#if nodos[0].#id[0]?has_content>id="${nodos[0].#id[0]!}"</#if> class="${nodos?node_name} ${nodos[0].#tipo[0]!}">
<#list nodos?children as campo>
<#if campo?node_type = 'element' && chequearPermisos(campo[0].#permiso[0]!"all")>
<#if ((campo[0].#mostrar[0]!"todos") == 'todos' || (campo[0].#mostrar[0]!"todos") == tipoFormulario)>
<#switch campo?node_name>
<#case "subtitulo">
<div class="subtitulo " style="${campo[0].#estilo[0]!}">${campo[0]}</div>
<#break>
<#case "texto">
<#-- campo de texto -->
<#include "campos/Campos Texto.ftl">
</#switch>
</#if>
</#if>
</#list>
</div>
</#if>
</#if>
</#list>
</div>
</#list>
</s:form>
<#include "estructura/Pie.ftl">
</body>
</html>
<#else>
<#pp.dropOutputFile />
</#if>
this FTL run with FMPP, using a XML to fill the data.
The problem I am having is when I have to adjust the layout of the view, this layout is designed for a form 2 columns and I need to:
add a header or more columns to the layout
change the background color or image, font size and color
add images to header
i don't know how to do it without complicating the FTL with #IF, marks each part of the CSS and then having a big xml.
there are any layouts in freemarket for example i can see or use?
The idea is to keep using single set of FTLs a web system and a simple web page, in java.
You can create a freemarker template for use as your layout. In the template you will want to embed your complex logic as well as your styling.
Here is an example of a layout template that I have been using on a current project.
<#include "../common/commonStyles.ftl">
<#if document.visuallyImpaired>
<link rel="stylesheet" type="text/css" href="css/visuallyImpaired/devLetterLayout.css" media="all" />
<#else>
<link rel="stylesheet" type="text/css" href="css/devLetterLayout.css" media="all" />
</#if>
<table class="headerTable">
<tbody>
<#if document.visuallyImpaired>
<tr>
<td class="visImpairedTitle">
<#include "title.ftl">
</td>
</tr>
</#if>
<tr>
<td class="headerSideColumn">
<#include "bannerImage.ftl">
</td>
<td class="headerCenterColumn">
<#if !document.visuallyImpaired>
<#include "title.ftl">
</#if>
</td>
<td class="headerSideColumn">
</td>
</tr>
<tr>
<td class="letterDate">
<#include "letterDate.ftl">
</td>
</tr>
</tbody>
</table>
In your main template you will use the <#assign> tags for your variables and the <#include> tags to pull in the .ftl templates you created.
You can also break out some of your logic into separate templates to keep your source page clean. Just put an <#assign> and <#include> in your <#list>.
For the number of columns I haven't found anything elegant yet, but you can do something like <#assign columnCount=x> and then <#include "tableColumn" + columnCount + ".css"> to limit the amount of changes you need to add.
You could even assign a local variable using <#local> and implement a counter to determine the number of columns you have if the table is created dynamically each time.
Related
Doing a PDF design in an ERP system. The design tool is a combination of HTML and Freemarker. I want to add a table if any of the order's orderlines has a value in a specific field greater than 0, and the table data shall only consist of these lines. It looks like this now:
<#if order.item?has_content>
<table class="itemtable" style="width: 100%; margin-top: 10px;">
<thead>
<tr>
<th colspan="8">Item</th>
<th align="right" colspan="3">Quantity</th>
</tr>
</thead>
<#list salesorder.item as tranline><#if tranline.quantity!=0>
<tr>
<td colspan="8">{tranline.item}</td>
<td align="right" colspan="3">${tranline.quantity}</td>
</tr>
</#if>
</#list>
</table>
</#if>
--
So, the table contains only of the lines that has quantity > 0, which is the result I want. But I also want the table head to be printed only if my condition is OK. Now, if none of the orderlines has quantity > 0, the table head is created with no lines. I don't want it to appear at all in that case.
Really simple thing I would guess, but I'm a newbie.
Any ideas?
SO, I just want to do something like:
IF MAX(Order.Quantity) > 0 THEN .... create table
Hoping this is not Netsuite (which uses a modified variant of some old FreeMarker version), you can use ?filter, combined with #list+#items (see https://freemarker.apache.org/docs/ref_directive_list.html#ref.directive.items):
<#list salesorder.item?filter(order -> order.quantity != 0)>
<table>
<thead>...</thead>
<#items as order>
<tr>... print order data here
</#items>
<table>
</#list>
Under Netsuite, if ?filter is still not supported when you read this, you could loop twice. In the first loop check if there's any line that satisfies the condition, but print nothing, and then only if there was a match, do a second loop that prints the items:
<#assign hasMatchingOrder = false>
<#list salesorder.item as order>
<#if order.quantity != 0>
<#assign hasMatchingOrder = true>
<#break>
</#if>
</#list>
<#if hasMatchingOrder>
<table>
<thead>...</thead>
<#list salesorder.item as order>
<#if order.quantity != 0>
<tr>... print order data here
</#if>
</#list>
</table>
</#if>
So this is much uglier and error-prone to do, so please pester Oracle to update FreeMarker in Netsuite.
Otherwise, if things like above is often needed, then it can be put into a macro, although I don't know if Netsuite supports templates having shared macros (that is, a shared #include-ed or #importe-ed files).
How can I get/set checkbox value using jstl and delete only those record from the database where the checkbox is checked? can you also advise how to use ternary operators in jstl for this scenario?
SearchStudent.jsp
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%# taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
<%#page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Lookup Students</title>
</head>
<form method="post" action="deleteStudentServlet" class="form">
<body class="body">
<!-- List results -->
<c:if test="${not empty studentList}">
<table border="1" cellspacing="0" cellpadding="0" :>
<tr>
<th></th>
<th>ID</th>
<th>Title</th>
<th>First Name</th>
<th>Last Name</th>
<th></th>
</tr>
<c:forEach var="students" items="${studentList}">
<tr>
<td><input type="checkbox" name="chkBox"> </td>
<td>${students.studentID}</td>
<td>${students.title}</td>
<td>${students.firstName}</td>
<td>${students.lastName}</td>
<td><c:url value="UDS" var="url">
<c:param name="StudentID" value="${students.studentID}" />
</c:url> Edit</td>
</tr>
</c:forEach>
</table>
</c:if>
<td><input type="submit" name="submit" value="Delete" ></td>
</form>
<p>There are ${fn:length(studentList)} results.</p>
</body>
</html>
thanks.
Your checkbox has currently no value associated with the parameter name at all:
<input type="checkbox" name="chkBox">
So it's hard to find out the checked ones. You need to give the checkbox a value which uniquely identifies the selected item. In your particular example, the student ID seems to be an obvious choice:
<input type="checkbox" name="selected" value="${student.studentID}">
(by the way, why are you duplicating the entity name in the property name? why not just name it id so that you can just self-documentary use ${student.id}? also your var="students" is kind of odd, it is referring only one student, so just name it var="student"; the ${studentList} can better be named ${students})
When the form is submitted, all checked value are available as follows:
String[] selectedStudentIds = request.getParameterValues("selected");
Finally, just pass it through to your DAO/service class which does the business job:
studentService.delete(selectedStudentIds);
See also:
How to transfer data from JSP to servlet when submitting HTML form
ServletRequest.getParameterMap() returns Map<String, String[]> and ServletRequest.getParameter() returns String?
Send an Array with an HTTP Get
this may help you.
In ajax call:
var boolValue= $(this).closest(".tr").find('.checkboxClass').is(':checked');
$.post("/api/dosomething", {
someSettings : boolValue
})
hi i had created the jsp page contains the table. the table cell values are loaded dynamically using the jstl. in the table cell contains the date. the in between space of date,month and year is two spaced. but the tabel cell shows single space only. my sample code is show below please solve my problem. sorry for my bad English. thanks in advance.
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Precision Attendance</title>
</head>
<body>
<%
ArrayList list = new ArrayList();
Map empDetails = new HashMap();
empDetails.put("EmployeeID", "1");
empDetails.put("EmployeeCode","PB131");
empDetails.put("EmployeeName","Balaji");
empDetails.put("DOJ","17 January 2014");
list.add(empDetails);
request.setAttribute("empDetailsList", list);
%>
<table cellpadding="5px" cellspacing="5px" class="TableGrid"
id="dgEmpShiftDetails">
<tr>
<th>Employee ID</th>
<th>Employee Code</th>
<th>Employee Name</th>
<th>DOJ</th>
</tr>
<c:forEach items="${empDetailsList}" var="empDetLst">
<tr>
<td><c:out value="${empDetLst.EmployeeID}" /></td>
<td><c:out value="${empDetLst.EmployeeCode}" /></td>
<td><c:out value="${empDetLst.EmployeeName}" /></td>
<td><c:out value="${empDetLst.DOJ}" /></td>
</tr>
</c:forEach>
</table>
</body>
</html>
i set DOJ as 17 January 2014 but table cell shows this like 17 January 2014. in between space is single. how can i resolve this problem.please do the needful.
HTML doesn't preserve two consecutive spaces except when using a space enity. See this question:
Why do multiple spaces in an HTML file show up as single spaces in the browser?
If you want doucle-spaces to be preserved use two non-breaking space characters where you want the spaces:
I have an interesting issue. I have a website which sends emails.
The email templates are often straight forward but for one client he wants me to convert content from his public website into email friendly html.
I want to not just solve the problem for his specific website but for other unknown websites.
So I remembered that you can run Razor as a template engine.
Long story short. It is working and working well.
My issue comes down to this. When someone edits the template with razor style for loops Ckeditor acts quite strangely.
Any idea how to keep CKEditor from screwing up?
<table style="width: 100%;" width="100%">
<tbody>
#foreach (var row in body.indexPageRow) {
foreach (var cell in row.teaser) {
<tr>
<td class="row">#Raw(cell.teaserContent.a.Html)</td>
<td class="row">#Raw(cell.teaserContent.div.InnerHtml)</td>
</tr>
}}
</tbody>
</table>
The above code when saved in ckeditor removes the razor information and becomes an empty table
<table style="width: 100%;" width="100%">
<tbody></tbody>
</table>
The only way I can think of to achieve this would be to use html comments in conjunction with razor comments.
Initially you would author the razor template like so:
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<title>Index</title>
</head>
<body>
<table>
<tbody>
<tr><td>X</td><td>Y</td></tr>
#*<!--*#
#for (var x = 1; x < 5; x++) {
for (var y = 1; y < 5; y++) {
#*-->*#
<tr>
<td class="row">#Html.Raw(x)</td>
<td class="row">#Html.Raw(y)</td>
</tr>
#*<!--*#
}
}
#*-->*#
</tbody>
</table>
</body>
</html>
The code above is valid and will render without error. But when you put it into the html editor it will be rearranged by the browser, so you will need to alter it just before it is displayed for editing so that the razor comments are removed and only the html comments remain.
So, once you have removed the razor comments by replacing all instances of #*<!--*# with <!-- and all instances of #*-->*# with --> you should have the following
<!DOCTYPE html>
<html>
<head>
<title>Index</title>
</head>
<body>
<table>
<tbody>
<tr><td>X</td><td>Y</td></tr>
<!--
#for (var x = 1; x < 5; x++) {
for (var y = 1; y < 5; y++) {
-->
<tr>
<td class="row">#Html.Raw(x)</td>
<td class="row">#Html.Raw(y)</td>
</tr>
<!--
}
}
-->
</tbody>
</table>
</body>
</html>
This will render in the html editor and wont get mangled by the browser as pointed out by Alfonso, an example of this on jsfiddle http://jsfiddle.net/wPGLd/3/
Once the editing is complete you will need to capture the html and reapply the razor comments by replacing all instances of <!-- with #*<!--*# and all instances of --> with #*-->*#
Intercepting the html before and after it enters the ckeditor is fairly straight forward and well documented. I found the following article that explains a little about how to get the ckeditor content on submit
How to update CKEditor content on form submit – equivalent of OnAfterLinkedFieldUpdate FCKEditor
The following question also covers this
Update editor content immediately before save in CKEditor plug-in
You can't.
The browser will rearrange those contents: http://jsfiddle.net/wPGLd/
<!DOCTYPE html>
<html>
<head>
<script type='text/javascript'>//<![CDATA[
window.onload=function(){
alert(document.body.innerHTML)
}//]]>
</script>
</head>
<body>
<table style="width: 100%;" width="100%">
<tbody>
#foreach (var row in body.indexPageRow) {
foreach (var cell in row.teaser) {
<tr>
<td class="row">#Raw(cell.teaserContent.a.Html)</td>
<td class="row">#Raw(cell.teaserContent.div.InnerHtml)</td>
</tr>
}}
</tbody>
</table>
</body>
</html>
I'm reading a local HTML document with Nokogiri like so:
f = File.open(local_xml)
#doc = Nokogiri::XML(f)
f.close
#doc contains a Nokogiri XML object that I can parse using at_css.
I want to modify it using Nokogiri's XML::Node, and I'm absolutely stuck. How do I take this Nokogiri XML document and work with it using node methods?
For example:
#doc.at_css('rates tr').add_next_sibling(element)
returns:
undefined method `add_next_sibling' for nil:NilClass (NoMethodError)
despite the fact that #doc.class is Nokogiri::XML::Document.
For completeness, here is the markup I'm trying to edit.
<html>
<head>
<title>Exchange Rates</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<table class="rates">
<tr>
<td class="up"><div></div></td>
<td class="date">Saturday, Jan 12</td>
<td class="rate up">3.83</td>
</tr>
<tr>
<td class="up"><div></div></td>
<td class="date">Friday, Jan 11</td>
<td class="rate up">3.70</td>
</tr>
<tr>
<td class="down"><div></div></td>
<td class="date">Thursday, Jan 10</td>
<td class="rate down">3.68</td>
</tr>
<tr>
<td class="down"><div></div></td>
<td class="date">Wedensday, Jan 9</td>
<td class="rate down">3.70</td>
</tr>
<tr>
<td class="up"><div></div></td>
<td class="date">Tuesday, Jan 8</td>
<td class="rate up">3.66</td>
</tr>
</table>
</body>
</html>
This is an example how to do what you are trying to do. Starting with f containing a shortened version of the HTML you want to parse:
require 'nokogiri'
f = '
<html>
<head>
<title>Exchange Rates</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<table class="rates">
<tr>
<td class="up"><div></div></td>
<td class="date">Saturday, Jan 12</td>
<td class="rate up">3.83</td>
</tr>
</table>
</body>
</html>
'
doc = Nokogiri::HTML(f)
doc.at('.rates tr').add_next_sibling('<p>foobar</p>')
puts doc.to_html
Your code is incorrectly trying to find the class="rates" parameter for <table>. In CSS we'd use .rates. An alternate way to do it using CSS is table[class="rates"].
Your example didn't define the node you were trying to add to the HTML, so I appended <p>foobar</p>. Nokogiri will let you build a node from scratch and append it, or use markup and add that, or you could find a node from one place in the HTML, remove it, and then insert it somewhere else.
That code outputs:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Exchange Rates</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<table class="rates">
<tr>
<td class="up"><div></div></td>
<td class="date">Saturday, Jan 12</td>
<td class="rate up">3.83</td>
</tr>
<p>foobar</p>
</table>
</body>
</html>
It's not necessary to use at_css or at_xpath instead of at. Nokogiri senses what type of accessor you're using and handles it. The same applies using xpath or css instead of search. Also, at is equivalent to search('some accessor').first, so it finds the first occurrence of the matching node.
Try to load as HTML instead of XML Nokogiri::HTML(f)
Not getting in much detail on how Nokogiri works, lets say that XML does not have css right? So the method at_css doesn't make sense (maybe it does I dunno). So it should work loading as Html.
Update
Just noticed one thing. You want to do at_css('.rates tr') insteand of at_css('rates tr') because that's how you select a class in css. Maybe it works with XML now.