how to get current page in wicket - wicket

i am trying to create dynamic navigation links in which current page link should be highlighted but i am unable to get desired outcome. i am using listview to display my menu items but unable to highlight the current page link.
please suggest necessary changes
public class SearchPage extends WebPage implements Serializable {
private static final long serialVersionUID = 1L;
Logger log = Logger.getLogger(SearchPage.class);
public SearchPage() {
List<HeaderListItems> headerPOJOItems = new ArrayList<HeaderListItems>();
HeaderListItems searchHLI = new HeaderListItems();
searchHLI.setLabel("Search");
searchHLI.setDestPage(SearchPage.class);
headerPOJOItems.add(searchHLI);
HeaderListItems jobsHLI = new HeaderListItems();
jobsHLI.setLabel("Jobs");
jobsHLI.setDestPage(Jobs.class);
headerPOJOItems.add(jobsHLI);
HeaderListItems urlHLI = new HeaderListItems();
urlHLI.setLabel("URL");
urlHLI.setDestPage(URL.class);
headerPOJOItems.add(urlHLI);
HeaderListItems syssettingsHLI = new HeaderListItems();
syssettingsHLI.setLabel("System Settings");
syssettingsHLI.setDestPage(Settings.class);
headerPOJOItems.add(syssettingsHLI);
HeaderListItems usersHLI = new HeaderListItems();
usersHLI.setLabel("Users");
usersHLI.setDestPage(User.class);
headerPOJOItems.add(usersHLI);
HeaderListItems logoutHLI = new HeaderListItems();
logoutHLI.setLabel("Logout");
logoutHLI.setDestPage(WebApp.get().getHomePage());
headerPOJOItems.add(logoutHLI);
add(new ListView("headerlistview", headerPOJOItems) {
#Override
protected void populateItem(ListItem item) {
final HeaderListItems headerlistitems = (HeaderListItems) item
.getModelObject();
log.info("Label: " + headerlistitems.getLabel() + " dest: "
+ headerlistitems.getDestPage());
Link newlink = new Link("newlink") {
#Override
public void onClick() {
setResponsePage(headerlistitems.getDestPage());
}
};
newlink.add(new Label("newlabel", headerlistitems.getLabel()));
newlink.add(new AttributeModifier("class",
new AbstractReadOnlyModel() {
#Override
public Object getObject() {
// TODO Auto-generated method stub
return getPage().getClass().equals(
headerlistitems.getDestPage()
.getClass()) ? "activeitem"
: AttributeModifier.VALUELESS_ATTRIBUTE_REMOVE;
}
}));
item.add(newlink);
}
});
}
List is list of pojo item. my pojo has two fields label(String) and destPage(Class)
My Mark-up:
<html xmlns:wicket="http://wicket.apache.org">
<head>
<title>Search Page</title>
<link href="css/design.css" type="text/css" rel="stylesheet" />
</head>
<body>
<div id="container">
<div class="header">
<div class="header_tab1">
<p align="center">Logo</p>
</div>
<div class="header_tab2"> </div>
<div class="header_tab3">
<table width="100%">
<tr>
<td wicket:id="headerlistview">
<ul>
<li><a href="#" wicket:id="newlink"><span
wicket:id="newlabel"></span></a></li>
</ul>
</td>
</tr>
</table>
</div>
</div>
</div>
</body>
</html>
I have a CSS class activeitem which i am using in attribute modifier
Thanks in advance

Change the class comparison to:
return getPage().getClass().equals(
headerlistitems.getDestPage()) ? "activeitem" : AttributeModifier.VALUELESS_ATTRIBUTE_REMOVE;
The next step would be to extract the navigation into its own panel, so you can reuse it in your pages.
Good luck.

Related

Dynamic queries and JpaSpecificationExecutor in Spring

I am trying to create a simple Spring project where restaurants can add menu items to shared database and users can use a html form to search the dishes based on a range of criteria- especially dietary requirements
Form example:
Restaurant Name: Chez Hans
Gluten Free: (X)
Egg Free: (X)
Vegan: ()
Example SQL command
Select all FROM "dishes" Dish WHERE restaurant_name = "Chez Hans" AND egg_free = TRUE AND
gluten_Free = TRUE;
A list of dishes that fit their criteria would then be returned to the user.
Any field in the form can be left blank, and not checking a box for example, "vegan" does not mean that criteria should be set as 'false', but rather not included within the query.
Because of this it seemed the best way to handle the issue was using JpaSpecificationExecutor to create dynamic SQL queries (similar to the implementation in the answer to the problem below)
Filtering database rows with spring-data-jpa and spring-mvc
I have created a solution based on my research and prior knowledge. However, when I implement my solution, no dishes are returned- even though there are dishes in the database that fit the search criteria. No errors are being produced, but simply a blank table, so I am not sure where I am going wrong.
I have researched countless articles/videos regarding JpaSpecificationExecutor/dynamic queries but there are parts of the that theory I am still unsure about. This is what I gather about JpaSpecificationExecutor/dynamic queries (but I may be wrong)
The meta model is not need to create dynamic queries but to verify the correctness of database query statements
To create queries using meta-model classes a wrapper class is required (In my example- DishSearch)
The following lines are to cast metamodel SingularAttribute class back to the original class value.
Path dname = root.get(Dish_.dname);
Path vegan= root.get(Dish_.vegan);
I am quite new to Spring and still finding it pretty difficult. Any help or advice would be very much appreciated!
Please see below my DishSpecification class:
package com.bron.demoJPA.specification;
public class DishSpecification implements Specification<Dish> {
private final DishSearch criteria;
public DishSpecification(DishSearch ds) {
criteria =ds;
}
#Override
public Predicate toPredicate(Root<Dish> root, CriteriaQuery<?> query,
CriteriaBuilder cb) {
Path<String> dname = root.get(Dish_.dname);
Path<Boolean> vegan= root.get(Dish_.vegan);
Path<Boolean> eggFree= root.get(Dish_.eggFree);
Path<Boolean> glutenFree= root.get(Dish_.glutenFree);
final List<Predicate> predicates = new ArrayList<Predicate>();
if(criteria.getDname()!=null) {
predicates.add(cb.equal(dname, criteria.getDname()));
}
if(criteria.isVegan()!=false) {
predicates.add(cb.equal(vegan, criteria.isVegan()));
}
if(criteria.isEggFree()!=false) {
predicates.add(cb.equal(eggFree, criteria.isEggFree()));
}
if(criteria.isGlutenFree()!=false) {
predicates.add(cb.equal(glutenFree, criteria.isGlutenFree()));
}
return cb.and(predicates.toArray(new Predicate[predicates.size()]));
}
}
Please see my DishSearch Class:
package com.bron.demoJPA.specification;
#AllArgsConstructor
#NoArgsConstructor
#Getter
#Setter
public class DishSearch {
private Long dishId;
private String dname;
private String description;
private double price;
private boolean vegan;
private boolean glutenFree;
private boolean eggFree;
private AppUser app;
}
Please see my SearchController Class:
#Controller
public class SearchController {
#Autowired
DishRepository drep;
#GetMapping("/showSearchForm")
public String showNewDishForm(Model model) {
// Create model attribute to bind form data
DishSearch dishSearch = new DishSearch();
model.addAttribute("dishSearch", dishSearch);
return "search_Dish";
}
#PostMapping("/showDishList")
public String saveUser(#ModelAttribute("dishSearch")DishSearch dishSearch) {
Specification<Dish> spec = new DishSpecification(dishSearch);
drep.findAll(spec);
return "show_dish_List";
}
}
Please see my DishRepository Class:
#Repository
public interface DishRepository extends JpaRepository<Dish, Long>, JpaSpecificationExecutor<Dish>{
#Transactional
#Modifying
List<Dish> findAll(Specification<Dish> spec);
}
Please see my search_Dish.html Thymeleaf Template:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="ISO-8859-1">
<title>Dish Management System</title>
<link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<br>
<div class="col-sm-10 offset-sm-1 text-center">
<div class="container">
<h2> Manage Dishes </h2>
<hr>
</div>
<form action="#" th:action="#{/showDishList}" th:object="${dishSearch}" method="POST">
<div class="col-sm-10 offset-sm-1 text-center">
<input type="text" th:field="*{dname}"
placeholder="Dish Name" class="form-control mb-4 col-10">
</div>
<div class="form-check form-check-inline">
<label class=" form-check-label" for="inlineCheckbox1 ">Vegan?</label>
<input type="checkbox" th:field="*{vegan}" />
<label class="form-check-label" for="inlineCheckbox1">Gluten Free?</label>
<input type="checkbox" th:field="*{glutenFree}" />
<label class="form-check-label" for="inlineCheckbox1">Egg Free?</label>
<input type="checkbox" th:field="*{EggFree}" />
</div>
<br>
<br>
<br>
<br>
<button type="submit" class="btn btn-info col-4"> Search Database</button>
</form>
</div>
<hr>
</body>
</html>
Please see my show_dish_List.html Thymeleaf Template:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<title>Search Results</title>
<link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
</head>
<body>
<br>
<div class="col-sm-10 offset-sm-1 text-center">
<h1>Dish List</h1>
</div>
<table border="1" class="table table-striped table-responsive-md">
<thead>
<tr>
<th>Dish Name</th>
<th>Dish description</th>
<th>Dish Price</th>
<th>Restaurant</th>
</tr>
</thead>
<tbody>
<tr th:each="dishSearch : ${listDishSearch}">
<td th:text="${dishSearch.dname}"></td>
<td th:text="${dishSearch.description}"></td>
<td th:text="${dishSearch.price}"></td>
</tr>
</tbody>
</table>
<div class="col-sm-10 offset-sm-1 text-center">
<a th:href="#{/showNewDishForm}"
class="btn btn-primary btn-sm mb-3"> Search Again</a>
</div>
----------------------------Update------------------------------
In addition to the answer provided below, in the Dish Specification Class I changed
if(criteria.getDname()!=null) {
predicates.add(cb.equal(dname, criteria.getDname()));
}
to
if(criteria.getDname()!="") {
predicates.add(cb.equal(dname, criteria.getDname()));
}
and the search is working fine now!
I believe the issue is that you are not adding the result in the Model which is being used to render the page show_dish_List.html, therefore nothing is being populated in the UI. Your UI is expecting the data to be in listDishSearch and there is nothing in that variable.
Update your code to:
#PostMapping("/showDishList")
public String saveUser(#ModelAttribute("dishSearch") DishSearch dishSearch, Model model) {
Specification<Dish> spec = new DishSpecification(dishSearch);
model.addAttribute("listDishSearch", drep.findAll(spec));
return "show_dish_List";
}
and everything should be working fine.
Remove the method findAll from your DishRepository repository. It is already being provided by the interface JpaSpecificationExecutor.

Event of StatelessLinks in WebMarkupContainer don't fire

I have a form with a StatelessLink ("Delete profile?"). When this link is clicked a WebMarkupContainer is made visible containing two more links ("Really delete profile!" and "Cancel").
Java:
private StatelessLink deleteProfileWarningLink;
private WebMarkupContainer deleteProfileContainer;
private StatelessLink deleteProfileLink;
private StatelessLink deleteProfileCancelLink;
public MyForm() {
...
deleteProfileWarningLink = new StatelessLink("profileDeleteWarningLink") {
#Override
public void onClick() {
deleteProfileWarning();
}
};
deleteProfileContainer = new WebMarkupContainer("deleteProfileContainer");
deleteProfileContainer.setVisible(false);
deleteProfileLink = new StatelessLink("reallyDeleteProfileLink") {
#Override
public void onClick() {
deleteProfile();
}
};
deleteProfileCancelLink = new StatelessLink("cancelDeleteProfileLink") {
#Override
public void onClick() {
cancelDeleteProfile();
}
};
...
add(deleteProfileWarningLink);
deleteProfileContainer.add(deleteProfileLink);
deleteProfileContainer.add(deleteProfileCancelLink);
add(deleteProfileContainer);
}
And some HTML:
<fieldset>
<div wicket:id="deleteProfileContainer" class="deleteProfil">
<div class="wrapper">
<a wicket:id="reallyDeleteProfileLink" class="button delete">Really delete profile!</a>
<a wicket:id="cancelDeleteProfileLink" class="button cancel">Cancel</a>
</div>
</div>
<span class="unitA">
<a wicket:id="profileDeleteWarningLink" class="button delete">Delete profile?</a>
</span>
</fieldset>
However the events of the StatelessLinks in the WebMarkupContainer never fire.
I think you should optimize this with some custom JavaScript.
The idea is the following: Wicket generates all three buttons in the initial version of the page. The first button is initially visible and uses JavaScript to show the initially hidden (CSS, display:none) container with the other two buttons. The rest is as it is now.
Recently we discussed something related to your problem in dev# mailing list:
http://markmail.org/message/dkmxw4urqm444ryc

Load partial view in a modal pop-up window using jquery

I have images that are loaded from database. When I click on an image, I want to show that image in a Modal Pop-up. My problem is that, I am not able to call the partial view from jquery. In fact, that action is not getting called from JQuery. Please help... I am a fresher. Below is my code:
_Layout.cshtml
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>_Layout</title>
#Styles.Render("~/bundle/ProfileStyle")
#Scripts.Render("~/bundle/JQuery")
#Scripts.Render("~/bundle/JQueryUI")
#Scripts.Render("~/bundle/CustomJS")
</head>
<body>
<div>
#RenderBody()
</div>
<div id="dialog">
#Html.Partial("_ProfileDetail")
</div>
</body>
</html>
Index.cshtml
#model IEnumerable<Profile.Models.TestProfile>
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<div class="tableOuterBlock">
#foreach (var item in Model)
{
<div class="tableInnerBlock">
<span>
#*<a href="#Url.Action("Edit", "Profile", new {#item.upi_Id})">*#
<img id="imgOpenDialog" src="#Url.Content(#item.upi_ImgData)" alt="No Image" width="100" height="100" />
#*</a>*#
</span>
</div>
}
</div>
Partial view
#model Profile.Models.TestProfile
<div>
#if(Model != null)
{
<img id="imgOpenDialog" src="#Url.Content(#Model.upi_ImgData)" alt="No Image" width="80%" height="50%" />
}
</div>
JQuery
$(function () {
$("[id*=imgOpenDialog]").click(function () {
var imgDetail = $(this).prop("src");
$("#dialog").dialog({
autoOpen: true,
position: { my: "center" },
modal: true,
resizable: false,
open: function () {
//parameter to c# function
data: { strImg = imgDetail }
$(this).load('#Url.Action("ShowProfileDetail","Profile")');
}
});
});
});
Controller
public PartialViewResult ShowProfileDetail(string strImg)
{
strImg = strImg.Substring(strImg.IndexOf('/'));
List<TestProfile> tpList = db.TestProfiles.Where(x => x.upi_ImgData ==strImg).ToList();
TestProfile testProfile = db.TestProfiles.Find(tpList[0].upi_Id);
return PartialView("_ProfileDetail", testProfile);
}
it may be a bit late but if you check out this blog, and download his code, you will see his use of jquery to create a modal pop up from a partial view.

Grails One to Many form

I am currently working on a grails project and am trying to create a one to many form. I have been using the tutorial at the link below to get started:
http://omarello.com/2010/08/grails-one-to-many-dynamic-forms/
The solution has a form with two field of data that are static and one dynamic fiwld where the user is allowed to add as many variables as they want and then save them. below you can see all the various files for this functionality:
Products.Groovy Domain Class
import org.apache.commons.collections.list.LazyList;
import org.apache.commons.collections.FactoryUtils;
/**
* Products
* A domain class describes the data object and it's mapping to the database
*/
class Products {
String productType
String product
List vars = new ArrayList()
//This represents a product belonging to a single department
static belongsTo = [dept:Depts]
static hasMany = [ vars:Dynam ]
static mapping = {
vars cascade:"all-delete-orphan"
}
def getVarsList() {
return LazyList.decorate(
vars,
FactoryUtils.instantiateFactory(Dynam.class))
}
static constraints = {
productType blank: false
product blank:false, size: 1..160
}
}
Dynam.groovy
class Dynam {
public enum VarType{
T("Testimonial"),
D("Dimentions"),
N("Networking")
final String value;
VarType(String value) {
this.value = value;
}
String toString(){
value;
}
String getKey(){
name()
}
static list() {
[T, D, N]
}
}
static constraints = {
index(blank:false, min:0)
data(blank:false)
type(blank:false, inList:VarType.list(), minSize:1, maxSize:1)
}
int index
String data
VarType type
boolean deleted
static transients = [ 'deleted' ]
static belongsTo = [ product:Products ]
def String toString() {
return "($index) ${data} - ${type.value}"
}
}
ProductsController.Groovy
Creation Function
def createDynProduct(){
def productsInstance = new Products()
productsInstance.properties = params
//This is used in order to create a new User Object for the current User logged in
def userObjects = springSecurityService.currentUser
//This passes the 2 models to the view one being Products and the other a User Department
[productsInstance: productsInstance, dept: userObjects.dept]
}
Save Function
def save() {
def productInfo = "dynam"
def userObjects = springSecurityService.currentUser
def dept = Depts.findByName(params.dept.name)
def product = new Products(product:productInfo, productType:params.productType, dept: dept, vars:params.varsList)
def _toBeRemoved = product.vars.findAll {!it}
// if there are vars to be removed
if (_toBeRemoved) {
product.vars.removeAll(_toBeRemoved)
}
//update my indexes
product.vars.eachWithIndex(){phn, i ->
if(phn)
phn.index = i
}
//If the the save is not successful do this
if (!product.save(flush: true)) {
render(view: "create", model: [productsInstance: product, dept: userObjects.dept])
return
}
redirect(action: "show", id: product.id)
}
createDynProduct.gsp
<%# page import="com.tool.Products" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name='layout' content='springSecurityUI'/>
<g:set var="entityName" value="${message(code: 'messages.label', default: 'Products')}" />
<title><g:message code="default.create.label" args="[entityName]" /></title>
</head>
<body>
<g:renderErrors bean="${productsInstance}" />
<g:form action='save' name='ProductForm' >
<br/>
<!-- Render the product template (_dynam.gsp) here -->
<g:render template="dynam" model="['productsInstance':productsInstance]"/>
<!-- Render the product template (_dynam.gsp) here -->
<div class="buttons">
<g:submitButton name="create" class="save" value="${message(code: 'default.button.create.label', default: 'Create')}" />
</div>
</g:form>
<!-- Render the var template (_var.gsp) hidden so we can clone it -->
<g:render template='var' model="['var':null,'i':'_clone','hidden':true]"/>
<!-- Render the var template (_var.gsp) hidden so we can clone it -->
</body>
</html>
_dynam.gsp
<div class="dialog">
<table>
<tbody>
<tr class="prop">
<td valign="top" class="name">
<label for="productType">Product Type</label>
</td>
<td>
<g:textField name='productType' bean="${productsInstance}" value="${productsInstance.productType}"
size='40'/>
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="Vars">Vars</label>
</td>
<!-- Render the vars template (_vars.gsp) here -->
<g:render template="vars" model="['productsInstance':productsInstance]" />
<!-- Render the vars template (_vars.gsp) here -->
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="Department">Department</label>
</td>
<td>
<g:textField name='dept.name' readonly="yes" value="${dept.name}" size='40'/>
</td>
</tr>
</tbody>
</table>
</div>
_vars.gsp
<script type="text/javascript">
var childCount = ${productsInstance?.vars.size()} + 0;
function addVar(){
var clone = $("#var_clone").clone()
var htmlId = 'varsList['+childCount+'].';
var varInput = clone.find("input[id$=number]");
clone.find("input[id$=id]")
.attr('id',htmlId + 'id')
.attr('name',htmlId + 'id');
clone.find("input[id$=deleted]")
.attr('id',htmlId + 'deleted')
.attr('name',htmlId + 'deleted');
clone.find("input[id$=new]")
.attr('id',htmlId + 'new')
.attr('name',htmlId + 'new')
.attr('value', 'true');
varInput.attr('id',htmlId + 'data')
.attr('name',htmlId + 'data');
clone.find("select[id$=type]")
.attr('id',htmlId + 'type')
.attr('name',htmlId + 'type');
clone.attr('id', 'var'+childCount);
$("#childList").append(clone);
clone.show();
varInput.focus();
childCount++;
}
//bind click event on delete buttons using jquery live
$('.del-var').live('click', function() {
//find the parent div
var prnt = $(this).parents(".var-div");
//find the deleted hidden input
var delInput = prnt.find("input[id$=deleted]");
//check if this is still not persisted
var newValue = prnt.find("input[id$=new]").attr('value');
//if it is new then i can safely remove from dom
if(newValue == 'true'){
prnt.remove();
}else{
//set the deletedFlag to true
delInput.attr('value','true');
//hide the div
prnt.hide();
}
});
</script>
<div id="childList">
<g:each var="var" in="${productsInstance.vars}" status="i">
<!-- Render the var template (_var.gsp) here -->
<g:render template='var' model="['var':var,'i':i,'hidden':false]"/>
<!-- Render the var template (_var.gsp) here -->
</g:each>
</div>
<input type="button" value="Add Var" onclick="addVar();" />
_var.gsp
<div id="var${i}" class="var-div" <g:if test="${hidden}">style="display:none;"</g:if>>
<g:hiddenField name='varsList[${i}].id' value='${var?.id}'/>
<g:hiddenField name='varsList[${i}].deleted' value='false'/>
<g:hiddenField name='varsList[${i}].new' value="${var?.id == null?'true':'false'}"/>
<g:textField name='varsList[${i}].number' value='${var?.data}' />
<g:select name="varsList[${i}].type"
from="${com.tool.Dynam.VarType.values()}"
optionKey="key"
optionValue="value"
value = "${var?.type?.key}"/>
<span class="del-var">
<img src="${resource(dir:'images/skin', file:'icon_delete.png')}"
style="vertical-align:middle;"/>
</span>
</div>
The solution works in part so you can go to the products page and it loads with the fields and the dynamic fields are added to the view fine and I can enter the data. However when I click save the data for the static fields is persisted but the dynamic vars are not saved to the domain.
I don’t get any errors but I believe it has something to do with the save function line below and the vars:params.varsList in particular.
def product = new Products(product:productInfo, productType:params.productType, dept: dept, vars:params.varsList)
I have checked the varsList data using println and it returns null, can someone please help with this?
Thanks in advance

Is it possible to repeat content from one placeholder multiple times?

Is it possible to use the content of a ContentPlaceHolder in multiple places in a master page?
For example, I often want to do something like:
<html>
<head>
<title><asp:ContentPlaceHolder ID="TitleContent" runat="server" /></title>
<link rel="Stylesheet" href="../../Content/Corporate.css" />
</head>
<body>
<div id="header">
<h1>I'd like to reuse the TitleContent ContentPlaceHolder content here?</h1>
</div>
<div id="content">
<asp:ContentPlaceHolder ID="MainContent" runat="server" />
</div>
<div id="footer">
© 2012 Acme corp.
</div>
</body>
</html>
Answer is here, so please reward author, but to adjust it to MVC, here is what you need to do:
First: Define your own master page class (Site.Master):
<%# Master Language="C#" Inherits="MyProject.Views.Shared.MyMasterPage" %>
Second: Class content:
public class MyMasterPage : ViewMasterPage
{
protected override void RenderChildren(HtmlTextWriter writer)
{
var mainPlaceHolder = FindControl("TitleContent");
var doublePlaceHolder = FindControl("TitleContentDuplicated");
var sb = new StringBuilder();
using (var sw = new StringWriter(sb))
using (var tw = new HtmlTextWriter(sw))
{
mainPlaceHolder.RenderControl(tw);
}
var lc = new LiteralControl(sb.ToString());
doublePlaceHolder.Controls.Add(lc);
base.RenderChildren(writer);
}
}
Third: Then you can use:
<title>
<asp:ContentPlaceHolder ID="TitleContent" runat="server" />
<asp:ContentPlaceHolder ID="TitleContentDuplicated" runat="server" />
</title>