How to add component AFTER rendering page - java

After migrating wicket to 1.5 I encounter this issue.
In Wicket 1.5 I (programmer before me) was adding JS and CSS reference in constructor and then component, simmilar to this:
public abstract class PageTemplate extends WebPage implements IHeaderContributor {
public BarePageTemplate() {
this(null);
}
public BarePageTemplate(PageParameters params) {
super(params);
add(JavascriptPackageResource.getHeaderContribution(ResourceMarker.class, "js/jquery-1.4.2.min.js"));
add(JavascriptPackageResource.getHeaderContribution(ResourceMarker.class, "js/jquery-ui-1.8.4.custom.min.js"));
[...]
jGrowlMarker = new Label("jGrowlMarker"); // placeholder for jgrowl messages
jGrowlMarker.setOutputMarkupId(true);
jGrowlMarker.add(new JGrowlBehavior());
add(jGrowlMarker);
}
}
In wicket 1.5 this is no longer possible. According to migration guide I refactored this code into this:
public abstract class PageTemplate extends WebPage implements IHeaderContributor {
public BarePageTemplate() {
this(null);
}
public BarePageTemplate(PageParameters params) {
super(params);
jGrowlMarker = new Label("jGrowlMarker"); // placeholder for jgrowl messages
jGrowlMarker.setOutputMarkupId(true);
jGrowlMarker.add(new JGrowlBehavior());
add(jGrowlMarker);
}
#Override
public void renderHead(IHeaderResponse response) {
response.renderJavaScriptReference(new CommonResourceRef("js/jquery-1.4.2.min.js"));
response.renderJavaScriptReference(new CommonResourceRef("js/jquery-ui-1.8.4.custom.min.js"));
[...]
}
}
This piece of code works, what I mean by that is that it includes those js. What causing me an issue is fact that right now my component (in this case jGrowlMarker) is rendering in page before page includes those js:
// jGrowl component
<script type="text/javascript" src="./wicket/resource/pl.softq.commons.ui.resource.ResourceMarker/js/jquery-1.4.2.min-ver-65B352E1BA79F0E2A3B1E014BC2571AF.js"></script>
<script type="text/javascript" src="./wicket/resource/pl.softq.commons.ui.resource.ResourceMarker/js/jquery-ui-1.8.4.custom.min-ver-88A9784D8E08D25998F239E2D65F03D7.js"></script>
Because of that it doesn't work properly (I believe thats an issue). It tries to create jGrowl component but jGrowl.js is added after this component.
[...] symbolizes rest of my js and css refenreces (including jGrowl ones). I've tried to add super.renderHead(response); to renderHead but it also doesnt work (super.renderHead refers to empty one in Component.class).
So my question is: how to add component after renderHead initializes or how to add it inside renderHead.
I'm not an expert in wicket so if you need more piece of code, let me know.

You can move the renderHead() method to JGrowlBehavior. This way it will contribute the dependencies first and then jgrowl.js itself.
If the dependencies are contributed by something else in the page too Wicket will detect this and contribute them just once.
In Wicket 6.x there are further improvements in this area. You can read http://wicketinaction.com/2012/07/wicket-6-resource-management/

Related

Liferay: AJAX call in configuration mode impossible?

Is it possible to use AJAX in configuration mode?
I am using custom class extending DefaultConfigurationAction to customize my portlet in the configuration mode. I override processAction and render methods, which work OK, but when I try to implement serveResource method, it is never called (returned status is 200 OK, but no data is fetched and no debug message is printed to the Liferay console).
My code for serveResource method:
public class TestConfigurationController extends DefaultConfigurationAction {
...
#Override
public void serveResource(PortletConfig portletConfig, ResourceRequest resourceRequest,
ResourceResponse resourceResponse) throws PortletException, IOException, Exception {
String resourceID = resourceRequest.getResourceID();
System.out.println("Resource id=" + resourceID
+ " in TestConfigurationController.serveResource()."); // this message never prints, method is not invoked
if (IMG_EDIT_ADD_NEW.equals(resourceID)) {
// more code
include(EDIT_NEW_IMAGE, context, resourceRequest, resourceResponse); // uses PortletRequestDispatcher, returns a JSPF fragment
} else {
super.serveResource(portletConfig, resourceRequest, resourceResponse);
}
}
}
I tried all options on the JS side, including both JQuery and AUI. Here is relevant code in configuration.jsp:
<portlet:resourceURL var="newImageJsp" id = "<%=IMG_EDIT_ADD_NEW%>">
</portlet:resourceURL>
<aui:button name="addNewImage" type="button" value="${addImage}"/>
<div id="<portlet:namespace/>newImageContainer">
<aui:field-wrapper name="newImageContainer" label="${addImage}">
</aui:field-wrapper>
</div>
<script type="text/javascript" charset="utf-8">
// Even this simple AUI AJAX call does not trigger serveResource method!
// AUI().ready('aui-base', 'aui-module', 'node', 'aui-io-request', function (A) {
// A.io.request('<%=newImageJsp.toString()%>');
// });
jQuery(document).ready(function () {
jQuery('#<portlet:namespace/>addNewImage').on('click', function (event) {
console.log('addNewImage clicked, url: ${newImageJsp}'); // returns correct url
jQuery.ajax({
dataType: 'text',
url: '${newImageJsp}',
success: function (data, status) {
console.log('returned resource: ' + data); // returns empty string
console.log('returned status: ' + status); // returns 200 OK, which is also in the Firebunetwork panel
$('#<portlet:namespace/>newImageContainer').html(data);
}
});
return false;
});
});
</script>
Debugging in console revealed, JS is working fine, function was called and returned status was 200 OK. However, returned data was empty and serveResource method on the server was never called.
As an experiment, I also tried to set
<aui:form action="${newImageJsp}" method="get" name="fm1">
which didn't call the serveResource method either, instead, it returned the view.jsp of the configured portlet.
And finally my configuration, which is exactly as in this working case:
portlet.xml:
<portlet>
<portlet-name>test-portlet</portlet-name>
<portlet-class>org.springframework.web.portlet.DispatcherPortlet</portlet-class>
<init-param>
<name>contextConfigLocation</name>
<value>/WEB-INF/spring-context/portlet/test-portlet.xml</value>
</init-param>
<init-param>
<name>config-template</name>
<value>/WEB-INF/jsp/carousel/configuration.jsp</value>
</init-param>
<expiration-cache>0</expiration-cache>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>view</portlet-mode>
<portlet-mode>edit</portlet-mode>
</supports>
<portlet-info>
<title>Test</title>
</portlet-info>
</portlet>
and liferay-portlet.xml:
<liferay-portlet-app>
<portlet>
<portlet-name>test-portlet</portlet-name>
<icon>/icon.png</icon>
<configuration-action-class>com.test.TestConfigurationController</configuration-action-class>
<requires-namespaced-parameters>false</requires-namespaced-parameters>
<ajaxable>true</ajaxable>
<header-portlet-css>/css/main.css</header-portlet-css>
<header-portlet-javascript>/js/jquery-1.11.3.min.js</header-portlet-javascript>
<header-portlet-javascript>/js/main.js</header-portlet-javascript>
</portlet>
</liferay-portlet-app>
So, it seems I have a similar problem, as this unresolved issue
I was thinking, that maybe it is the window state? Configuration mode always uses 'pop-up', but in all examples I only found AJAX calls using 'normal' window state. Maybe that is the problem? Is it even possible to make asynchronous JSPF loadings in pop-up mode? And even in configuration window? I never found a working example of use of AJAX in configuration mode and official Liferay only has examples for view mode.
Last but not least, I tested the same code in view.jsp for view mode and the resource serving method in TestViewController was called OK. I used Spring annotations here (#ResourceMapping). So the problem must be with Liferay and configuration mode. A bug maybe?
Thank you!
I did something similar and use the PrintWriter Object in resourceResponse:
PrintWriter writer = resourceResponse.getWriter();
writer.print([yourResult]);
http://liferayiseasy.blogspot.hk/2015/03/ajax-call-in-spring-mvc-portlet.html
You can also add a class extends MVCPortlet
Your previous view.jsp
<portlet:resourceURL var="newImageJsp" name="newImageResource"
</portlet:resourceURL>
...
// create a new class:
public class CustomResourceController extends MVCPortlet {
...
#Override(name="newImageResource") // <---- define the name attribute which match with view.jsp
public void serveResource(PortletConfig portletConfig, ResourceRequest resourceRequest,
ResourceResponse resourceResponse) throws PortletException, IOException, Exception {
String resourceID = resourceRequest.getResourceID();
System.out.println("Resource id=" + resourceID
+ " in TestConfigurationController.serveResource()."); // this message never prints, method is not invoked
if (IMG_EDIT_ADD_NEW.equals(resourceID)) {
// more code
include(EDIT_NEW_IMAGE, context, resourceRequest, resourceResponse); // uses PortletRequestDispatcher, returns a JSPF fragment
} else {
super.serveResource(portletConfig, resourceRequest, resourceResponse);
}
}
}
So, I tried both liferay-portlet:resourceURL portletConfiguration="true" and portlet:resourceURL, also with manual parsing and modifying the url before sending. The resource serving method (whether implementation of the serveResource, or completely new method using either Spring MVC or Liferay MVC (implementation class of MVCPortlet)), none worked in configuration mode. Seems like a bug to me, as there is nowhere even a mention about this peculiarity in official documentation.
The solution for me was to avoid resource serving at all and instead choose action phase (p_p_lifecycle=1). It is completely doable in AJAX, just had to override processAction method in my DefaultConfigurationAction implementation class.
Hope this saves someone the countless hours I spent with it.

Return result view by name in Application.java

In a Play 2.2! web project I'm pursuing, I'd like to return views by name in Application.java
I've added the following in the routes config :
GET /:page controllers.Application.show(page: String)
And i'd like Application.java to return the correct view only using it's name (the String page).
At the moment I have :
public static Result show(String page) {
switch(page){
case "home":
return ok(home.render());
case "register":
return ok(register.render());
}
return ok(home.render());
}
I'd like to avoid the switch statement here, and have show(String page) programatically find the view that matches the String page given in argument and return it (or home page if no match has been found).
EDIT : I've read some stuff about reflexion but I don't really know what that is or how to use it :/
Thanks for your insight :)
Remember that Play's view is a Scala function - which takes parameters, for ensuring typesafety, dynamic content etc, etc. In this scenario you shouldn't use :path argument but make usage of different routes to different actions like:
GET /home controllers.Application.home
GET /register controllers.Application.register
Actions:
public static Result home() {
return ok(home.render());
}
public static Result register() {
return ok(register.render());
}
Crypto-advertisment: Use Intellij - create templates for actions and routes and you will be doing it within milliseconds ;)
On the other hand if you have a large set of HTML files you can render them as... files instead of Play views like (pseudo code, debug it yourself!)
public static Result show(String page) {
File htmlFile = new File(page+".html");
if (!htmlFile.exists()) htmlFile = new File("home.html");
return ok(htmlFile).as("text/html");
}
I will only add that is absolutely NOT Play's way for working with templates ;)

Wicket 6 !continueToOriginalDestination: operator ! is undefined

Situation
I'm migrating a project from Wicket 1.5.7 to Wicket 6.12, one of the errors I get is explained below.
Code
#Override
protected void onSubmit() {
final String usernameValue = mail.getModelObject();
//Password is left empty in this particular case
AuthenticatedWebSession.get().signIn(usernameValue,"");
if (!continueToOriginalDestination())
{
setResponsePage(getApplication().getHomePage());
}
}
Error
This is the error I got when changing wicket versions: The operator !
is undefined for the argument type(s) void
Note: I see this error when hovering over !continueToOriginalDestination
What did I try
In my search on stackoverflow I came accross this question:
continueToOriginalDestination does not bring me back to originating page
Also checked this topic on apache wicket:
http://apache-wicket.1842946.n4.nabble.com/Handling-ReplaceHandlerException-on-continueToOriginalDestination-in-wicket-1-5-td4101981.html#a4115437
So I changed my code to this:
#Override
public void onSubmit() {
final String usernameValue = mail.getModelObject();
AuthenticatedWebSession.get().signIn(usernameValue,"");
setResponsePage(getApplication().getHomePage());
throw new RestartResponseAtInterceptPageException(SignInPage.class);
}
Question
The old situation nor the code change seem to work in my particular case.
Maybe it's a small change, is my new code wrong, how should this work?
Has Wicket changed that much, so that the old code is not supported anymore, or can !continueToOriginalDestination be used as well?
This helps
http://www.skybert.net/java/wicket/changes-in-wicket-after-1.5/
In 1.5, you could do the following to break out of the rendering of one page, go to another page (like login page) and then send the user back to where he/she was:
public class BuyProductPage extends WebPage {
public BuyProductPage() {
User user = session.getLoggedInUser();
if (user null) {
throw new RestartResponseAtInterceptPageException(LoginPage.class);
}
}
}
and then in LoginPage.java have this to redirect the user back to BuyProductPage after he/she's logged in:
public class LoginPage extends WebPage {
public LoginPage() {
// first, login the user, then check were to send him/her:
if (!continueToOriginalDestination()) {
// redirect the user to the default page.
setResponsePage(HomePage.class);
}
}
}
The method continueToOriginalDestination has changed in Wicket 6, it's now void which makes your code look more magic and less than logic IMO:
public class LoginPage extends WebPage {
public LoginPage() {
// first, login the user, then check were to send him/her:
continueToOriginalDestination();
// Magic! If we get this far, it means that we should redirect the
// to the default page.
setResponsePage(HomePage.class);
}
}

getRequestCycle().urlFor not working in panel

I need the URL for a component in wicket. When I use a page it works properly, but when using panel it does not work.
public final class ImageP extends Panel {
public ImageP(String id) {
super(id);
List<Mapp> list = Mapp.loadall(); //load image from database
final Mapp asr = list.get(0);
ByteArrayResource resource = new ByteArrayResource("image/jpeg", asr.getImage());
Image image = new Image("img", resource);
add(image);
System.out.println(getRequestCycle().urlFor(image, IResourceListener.INTERFACE));
}
}
This code does not work and throws an exception, but when I use page instead of panel getRequestCycle().urlFor(image, IResourceListener.INTERFACE) it works properly.
I bet you've got the following exception:
java.lang.IllegalStateException: No Page found for component [Component id = img]
It's because RequestCycle object internally calls getPage() method of the component that's first parameter of the urlFor() method with the following signature:
urlFor(Component component, RequestListenerInterface interface)
In case of calling method urlFor() in the constructor of a panel it's impossible to get page of a panel's child because panel isn't attached to page yet. So Wicket throws "a nice exception".
To fix that problem you just can move your code to the onBeforeRender() method of the panel. Something like that:
#Override
protected void onBeforeRender() {
//
// ... init resource ...
//
Image image = new Image("img", resource);
addOrReplace(image);
System.out.println(getRequestCycle().urlFor(image, IResourceListener.INTERFACE));
super.onBeforeRender();
}
P.S. I also assume that you're using Wicket 1.4 or earlier because there's no RequestCycle.urlFor(component, listener) method in Wicket 1.5 and later. So I think neither your question nor my answer doesn't make sense in that case.

How to set displayed text for a HTML anchor tag using Wicket?

I would like to dynamically change the text displayed for a HTML anchor tag. So, for example if I have the following in my markup -
<a class="point" style="font-family:courier" wicket:id="link">[+]</a>
I want to change the '[+]' to something else. Currently the code fragment looks like this:
equipmentFamilyName.add(new Link<String>("link") {
#Override
protected void onComponentTag(ComponentTag tag) {
String id = "link" + equipmentFamilyName.getModelObject();
tag.put("onclick", "toggle('" + collapsibleId + "','" + id + "')");
tag.put("id", id);
}
#Override
public void onClick() {
}
});
Which just adds various attributes. I tried using a model associated with the Link object like this
IModel<String> linkModel = new Model<String>("-");
equipmentFamilyName.add(new Link<String>("link", linkModel) {
...
But that had no effect on the displayed text i.e. I still get '[+]' shown on my web page.
Any suggestions or code examples clarifying how to do this would be much appreciated.
Edit: Following the pointers in the comments, I added a method to override onComponentTagBody(). I now have a solution to this for our current version of Wicket (1.4.17).
#Override
protected void onComponentTagBody(final MarkupStream markupStream, final ComponentTag openTag) {
replaceComponentTagBody(markupStream, openTag, "[-]");
}
If you use Wicket 1.5 then this is quite easy: link.setBody(IModel).
The model's object will be used as link's body.

Categories

Resources