Customizing IndicatingAjaxLink in wicket - java

in my current project i've faced a problem of customizing IndicatingAjaxLink in wicket, is there any solution to change standart gif image to my own?
For example we have following listeneer
add(new IndicatingAjaxLink("closeReceivedBillspanel") {
public void onClick(AjaxRequestTarget art) {
// some timeconsuming calculations
}
});
as user clicks this link, the gif with loading appears, and i want to change this gif, is there any solution for this problem?

Have your page implements the IAjaxIndicatorAware interface
public class BasePage extends WebPage implements IAjaxIndicatorAware {
public BasePage(final PageParameters parameters) {
// Home link
AjaxLink<Page> homeLink = new AjaxLink<Page>("homeLink") {
private static final long serialVersionUID = 1L;
#Override
public void onClick(AjaxRequestTarget target) {
setResponsePage(HomePage.class);
}
};
add(homeLink);
}
#Override
public String getAjaxIndicatorMarkupId() {
return "indicator";
}
This way, you can set, in the html, any image you want to display when the loading appears by changing the image in the "img" tag
<div id="indicator" style="display: none;">
<div class="indicator-content">
Please wait... <wicket:link><img src="images/loading.gif" width="16" height="16" alt="loading" /></wicket:link>
</div>
</div>

Create yoru own custom class like, (copy whats inside IndicatingAjaxLink and update)
public class MyIndicatingAjaxLink<T> extends AjaxLink<T> implements IAjaxIndicatorAware {
private final MyAjaxIndicatorAppender indicatorAppender = new MyAjaxIndicatorAppender();
.
//rest of the code is same as IndicatingAjaxLink class
.
}
Also you need a custom AjaxIndicatorAppender within your customIndicatingAjaxLink and you need to override below method of indicatorAppender to return path of your custom image
protected CharSequence getIndicatorUrl()

Related

Wicket form and back button issue

I do not know if I missed something but I have following problem.
I am using wicket 6.5.0, i have simple form there with one field. Submitting the form redirect me on the other page. When I press the back button on my browser (firefox 14) i go back to my form, but it is empty. I would like to see it in the state i submitted it.
I also noticed that if i am on the first page with form, i have version /?0. Submitting take me to the page with version /second?2, the back button take me back to the page with version /?0.
Why is this happening? why i am skipping version ?1 ?
here is my code:
WicketApplication.java
public class WicketApplication extends WebApplication
{
#Override
public Class<? extends WebPage> getHomePage()
{
return HomePage.class;
}
#Override
public void init()
{
super.init();
mountPage("second", SecondPage.class);
}
}
HomePage.java :
public class HomePage extends WebPage {
private static final long serialVersionUID = 1L;
public HomePage(final PageParameters parameters) {
super(parameters);
add(new SimpleForm("form"));
}
public final class SimpleForm extends Form<Void>
{
private static final long serialVersionUID = -562538189475312724L;
private final ValueMap properties = new ValueMap();
public SimpleForm(final String id)
{
super(id);
add(new TextField<String>("field", new PropertyModel<String>(properties, "field")));
}
#Override
public final void onSubmit()
{
setResponsePage(new SecondPage(getPageParameters()));
}
}
}
HomePage.html
...
<form wicket:id="form">
<input type="text" wicket:id="field" value="" size="50" /> <input
type="submit" value="submit" />
</form>
...
Thank you for your replies.
When you submit, because the model has changed, the page is dirtied and wicket increases the version of the page and adds it to the Page Manager. So there is a version 1 created that you could get to by plugging in ?1. If you try it out you should see the expected value in the html wicket is sending back.
You could get around this by overriding isVersioned on your page, returning false.
From Component - isVersioned():
If a Page is not versioned then it wont track changes in its components and will use the same Page#getPageId() during its lifetime
Meaning it will serialize the dirtied page against the existing page id.

How to create a Link that supplies its own Markup?

I'm trying to create a link that will hide or show a part of my page. The link should be reusable and display one of two images, depending on state.
Adding the two subcomponents on every page where I use the link is kind of clunky so I wanted to create a component that behaves like a link while automatically adding its content.
This is the Link component:
public class ToggleVisibilityLink extends AjaxFallbackLink<Boolean>
{
public ToggleVisibilityLink(final String id, final IModel<Boolean> model)
{
super(id, model);
setOutputMarkupId(true);
add(new Image("collapseImage")
{
#Override
public boolean isVisible()
{
return !getModelObject();
}
});
add(new Image("expandImage")
{
#Override
public boolean isVisible()
{
return getModelObject();
}
});
}
#Override
public void onClick(final AjaxRequestTarget target)
{
setModelObject(!getModelObject());
if (target != null)
{
target.add(this);
send(this.getParent(), Broadcast.EXACT, target);
}
}
}
And this is how I currently use it in HTML (this is added to the page or panel where I use the link):
<a href="#" wicket:id="collapseExpandLink" class="collapseExpandLink">
<wicket:link>
<img src="collapse.png" wicket:id="collapseImage" class="collapseExpandImage collapse">
</wicket:link>
<wicket:link>
<img src="expand.png" wicket:id="expandImage" class="collapseExpandImage expand">
</wicket:link>
</a>
And the corresponding Java call:
add(new ToggleVisibilityLink("collapseExpandLink", new PropertyModel(this, "hidden")));
But I want to be able to skip the body inside the link as one would have to know about the internals of ToggleVisibilityLink.
I experimented with IMarkupResourceStreamProvider, using Dynamic markup in Wicket as a starting point. By googling I found another example where the poster was only able to get that to work when using a Panel, and I was able to do that as well. But I'd really like to keep the link and not package it inside a Panel, as I would not be able to style the link in the markup.
I'm also open to alternatives to encapsulate the link and its body.
I was able to get this to work using setBody(), even though I was trying to sabotage myself quite badly (I had duplicate libraries, my own incompatible jQuery library import and a custom resource versioning strategy).
Here is the current ToggleVisibilityLink:
public class ToggleVisibilityLink extends AjaxFallbackLink<Boolean>
{
static {
Application.get().getSharedResources().add("ToggleVisibilityLinkCollapse",
new MyPackageResource(ToggleVisibilityLink.class, "collapse.png"));
Application.get().getSharedResources().add("ToggleVisibilityLinkExpand",
new MyPackageResource(ToggleVisibilityLink.class, "expand.png"));
}
public ToggleVisibilityLink(final String id, final IModel<Boolean> model)
{
super(id, model);
setOutputMarkupId(true);
setEscapeModelStrings(false);
setBody(new BodyModel(model));
}
#Override
public void onClick(final AjaxRequestTarget target)
{
setModelObject(!getModelObject());
if (target != null)
{
target.add(this);
send(this.getParent(), Broadcast.EXACT, target);
}
}
private static final class BodyModel extends AbstractReadOnlyModel<String>
{
private final IModel<Boolean> model;
private BodyModel(final IModel<Boolean> model)
{
this.model = model;
}
#Override
public String getObject()
{
return this.model.getObject() ?
"<img src=\""
+ RequestCycle.get().urlFor(new SharedResourceReference("ToggleVisibilityLinkExpand"), null)
+ "\" class=\"collapseExpandImage expand\">"
:
"<img src=\""
+ RequestCycle.get().urlFor(new SharedResourceReference("ToggleVisibilityLinkCollapse"), null)
+ "\" class=\"collapseExpandImage collapse\">";
}
}
}
Where MyPackageResource is a simple Implementation of PackageResource (why is that constructor protected?).
Then one can simply add the ToggleVisibilityLink to a container:
super.add(new ToggleVisibilityLink("collapseExpandLink", new PropertyModel(this, "hidden")));
and
<a wicket:id="collapseExpandLink" class="collapseExpandLink"></a>
and get notified via Event when the link is clicked.

Hiding a component in Wicket

I have a component inside an <a/> tag that opens a popup window on click. It's an "add to favourite" link which works on KML files. My KML file has a field named "favourite[boolean]". Now I'd like to hide or show my "add to favourite" link. The KML list is generated with a table:
public class CustomTracksAjaxDataTable<T> extends CustomAjaxDataTable<T> {
public CustomTracksAjaxDataTable(String id, List<IColumn<T>> iColumns,
ISortableDataProvider<T> tiSortableDataProvider, int rowsPerPage) {
super(id, iColumns, tiSortableDataProvider, rowsPerPage);
}
protected void onEventHandler(AjaxRequestTarget ajaxRequestTarget,
KMLFile file) {
setKMLData(file); // it just update map, dont care about it
add(new FavouriteStarIconState(file.isSaved()));
}
}
I tried to add a behavior thus:
public class FavouriteStarIconState extends AbstractDefaultAjaxBehavior {
private boolean isFavourite;
public FavouriteStarIconState(boolean isFavourite) {
super();
this.isFavourite = isFavourite;
}
#Override
protected void respond(AjaxRequestTarget target) {
if (isFavourite) {
target.appendJavascript("jQuery('.map_container_star').css(
{'display' : 'none' });");
} else {
target.appendJavascript("jQuery('.map_container_star').css(
{'display' : 'block' });");
}
}
#Override
public void renderHead(IHeaderResponse response) {
response.renderOnLoadJavascript(getCallbackScript().toString());
}
}
The part of the HTML containing the component:
<div id="map_container">
<a wicket:id="favourite_star" class="map_container_star"></a>
</div>
This isn't working. I got the same result with component.setVisible(false). How can I get hiding to work?
Well it finds out that I make a terrible mistake and put javascript appending in wrong place. AJAX request was not rendered. The proper class was CustomAjaxDataTable being extended by my class CustomTracksAjaxDataTable. I just add
new AjaxEventBehavior( "onclick" )
and override
protected void onEvent( AjaxRequestTarget ajaxRequestTarget )
and it works great now
You could use a CSS class like this
.hiddenClass
{
visibility:hidden;
}
then with AttributeModifier you add the class to the element
component.add(new AttributeModifier("class", "hiddenClass"));
or add the style directly to the style attribute
component.add(new AttributeModifier("style", "visibility:hidden;"));

GWT RootLayoutPanel - Problem rendering page from second to first (first works fine)

Sorry if this was already answered before. I did a little searching and found nothing that could solve my problem. I created an application with Spring Roo, then converted to a GWT app.
All the code generated by Spring Roo is only for CRUD. Now i want to add a Calendar for make appointments, so i need to move to another page.
I´ve added this code to
ScaffoldDesktopShell.java()
public ScaffoldDesktopShell() {
initWidget(BINDER.createAndBindUi(this));
startButton.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
RootLayoutPanel.get().add(new NovoPainel());
}
});
}
...
Then created a new UIbinder, called it NovoPainel() and added this code:
public NovoPainel() {
initWidget(uiBinder.createAndBindUi(this));
botao.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
RootLayoutPanel.get().clear();
RootLayoutPanel.get().add (new ScaffoldDesktopShell());
}
});
}
Everything goes fine moving from my root panel to NovoPainel, but when i need to go back to rootPanel the page doesn´t render correctly.
EX: Doesn´t show ** ValuePicker ** to click on left panel and render on center.
This is my RootPanel
and this image is when navigate from rootPanel to NovoPainel
and finally this one is returning from NovoPainel to RootPanel
You have to integrate with Roo generated architecture so that you can still benefit from Roo scaffolding.
Roo generated code hides most of behavior in _Roo_Gwt classes and it is because GWT doesn’t currently support ITDs. So changes have to be made in derived classes by overriding methods from _Roo_Gwt class.
To navigate application use Places, ActivityMapper and ActivitiManager (you can find good read on #Thomas Broyer posterous and GWT help).
If you take a look in ScaffoldDesktopShell.ui.xml - page is devided in three main areas.
ApplicationMasterActivities class is responsible for master area.
masterActivityManager.setDisplay(shell.getMasterPanel());
proxyListPlacePicker in ScaffoldDesktopApp.init() generates place change event with apropriate ProxyListPlace.
public void onValueChange(ValueChangeEvent<ProxyListPlace> event) {
placeController.goTo(event.getValue());
}
ApplicationMasterActivities class creates appropriate Activity in Master area by checking EntityProxy type contained in ProxyListPlace object.
public Activity getActivity(Place place) {
if (!(place instanceof ProxyListPlace)) {
return null;
}
ProxyListPlace listPlace = (ProxyListPlace) place;
return new ApplicationEntityTypesProcessor<Activity>() {
#Override
public void handlePet(PetProxy isNull) {
setResult(new PetListActivity(requests, ScaffoldApp.isMobile() ? PetMobileListView.instance() : PetListView.instance(), placeController));
}
#Override
public void handleOwner(OwnerProxy isNull) {
setResult(new OwnerListActivity(requests, ScaffoldApp.isMobile() ? OwnerMobileListView.instance() : OwnerListView.instance(), placeController));
}
}.process(listPlace.getProxyClass());
}
Navigation is created by listing all EntityProxy's in ScaffoldApp class
protected HashSet<ProxyListPlace> getTopPlaces() {
Set<Class<? extends EntityProxy>> types = ApplicationEntityTypesProcessor.getAll();
HashSet<ProxyListPlace> rtn = new HashSet<ProxyListPlace>(types.size());
for (Class<? extends EntityProxy> type : types) {
rtn.add(new ProxyListPlace(type));
}
return rtn;
}
To output meaningfull name in navigation menu they are rendered using ApplicationListPlaceRenderer
public String render(ProxyListPlace object) {
return new ApplicationEntityTypesProcessor<String>() {
#Override
public void handlePet(PetProxy isNull) {
setResult("Pets");
}
#Override
public void handleOwner(OwnerProxy isNull) {
setResult("Owners");
}
}.process(object.getProxyClass());
}
So you have to create new Activity.
public class SomeActivity extends Composite implements Activity{
private static SomeActivityUiBinder uiBinder = GWT
.create(SomeActivityUiBinder.class);
interface SomeActivityUiBinder extends UiBinder<Widget, SomeActivity> {
}
private AcceptsOneWidget display;
public SomeActivity() {
initWidget(uiBinder.createAndBindUi(this));
}
#Override
public String mayStop() {
return null;
}
#Override
public void onCancel() {
onStop();
}
#Override
public void onStop() {
this.display.setWidget(null);
}
#Override
public void start(AcceptsOneWidget panel, EventBus eventBus) {
this.display = panel;
this.display.setWidget(this);
}
}
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui">
<g:HTMLPanel>
Hello world!
</g:HTMLPanel>
</ui:UiBinder>
Create appropriate EntityProxy. It is only to obey ProxyListPlace mechanism.
public interface SomeEntityProxy extends EntityProxy {
}
Create SomeActivity in A
#Override
public Activity getActivity(Place place) {
if (!(place instanceof ProxyListPlace)) {
return null;
}
Activity activity = super.getActivity(place);
if (activity == null) {
ProxyListPlace listPlace = (ProxyListPlace) place;
if (SomeEntityProxy.class.equals(listPlace.getProxyClass())) {
activity = new SomeActivity();
}
}
return activity;
}
Add place to navigation in ScaffoldApp or override getTopPlaces in derived class.
rtn.add(new ProxyListPlace(SomeEntityProxy.class));
Set correct menu rendering text in ApplicationListPlaceRenderer
#Override
public String render(ProxyListPlace object) {
String label = super.render(object);
if(label == null) {
if (SomeEntityProxy.class.equals(object.getProxyClass())) {
label = "Some activity";
}
}
return label;
}
Code in GitHub.
GWT 2.1 introduced new classes that implements the Model-View-Places pattern (MVP). This pattern (and the GWT 2.1 concepts) are heavily based on best practices from developers who have build scalable GWT-based applications, so many people are migrating in this direction.
Roo generates a GWT 2.1 application; all of its navigational code is built on top of Activities and Places. The reason I bring this up is it sounds like you are attempting to side-step a lot of this navigational framework to implement your own. I'm not sure, but I believe your problem is coming from the fact that the MVP code is getting confused as a result.
My recommendation would be to work through the GWT MVP article linked above first. Do it completely separate of Roo, because the application that Roo generates is more complex. Once you have a good handle on it, go back through the Roo-generated application and it will likely make more sense.
You can create two div tags in your Porject.html file respectively with id firstdivtag_id1 and seconddivtag_id2.
Display first page by using
RootPanel.get("firstdivtag_id1").add(Panel1);
And then to switch over to another panel use
RootPanel.get("seconddivtag_id2").add(Panel2);

Wicket - Replace Label By TextField and vice versa

I am trying to replace a Label by a TextField in a ListView. I saw a similar wicket example few weeks ago over internet, but I don't remember the link. I have added AjaxEventBehavior - "onDblClick" to the ListItem by which I want to replace a Label by a TextField and also added AjaxFormComponentUpdatingBehavior - "onBlur" to the TextField such that the TextField will be replaced by Label. Somehow it is not working. The List model for the ListView contain only {"aaaaaaaaaaaaa", "bbbbbbbbbbbbbbbb", "cccccccccccccc"} [as I am testing it] so the first Label will be "aaaaaaaaaaaaa", if I double click on this Label the TextField is appearing the place of the Label "cccccccccccccc", which is unexpected. And also the "onBlur" event is not working. Hope I can explain the problems. The code is given below:
public class TaskTypeSettingsPage extends BasePage implements Serializable {
private String val;
public TaskTypeSettingsPage() {
add(new TaskTypeSettingsForm("form"));
}
public void setVal(String val) {
this.val = val;
}
public String getVal() {
return val;
}
private class TaskTypeSettingsForm extends Form {
private static final long serialVersionUID = 10058L;
private Fragment labelFragment;
private Fragment textFragment;
public TaskTypeSettingsForm(String id) {
super(id);
setOutputMarkupId(true);
ListView listView = new ListView("row", Arrays.asList("aaaaaaaaaaaaa", "bbbbbbbbbbbbbbbb", "cccccccccccccc")) {
#Override
protected void populateItem(ListItem item) {
String str = (String) item.getModelObject();
item.add(new Label("listLabel", str));
item.setOutputMarkupId(true);
labelFragment = new Fragment("frag", "labelFragment", this.getPage());
Label label = new Label("label", str);
label.setOutputMarkupId(true);
labelFragment.setOutputMarkupId(true);
labelFragment.add(label);
item.add(labelFragment);
textFragment = new Fragment("frag", "textFragment", this.getPage());
TextField text = new TextField("text", new PropertyModel(TaskTypeSettingsPage.this, "val"));
text.setOutputMarkupId(true);
textFragment.setOutputMarkupId(true);
textFragment.add(text);
item.add(new AjaxEventBehavior("onDblClick") {
#Override
protected void onEvent(AjaxRequestTarget target) {
labelFragment.replaceWith(textFragment);
labelFragment = textFragment;
target.addComponent(textFragment);
}
});
text.add(new AjaxFormComponentUpdatingBehavior("onBlur") {
#Override
protected void onUpdate(AjaxRequestTarget target) {
textFragment.replaceWith(labelFragment);
textFragment = labelFragment;
target.addComponent(labelFragment);
}
});
}
};
add(listView);
}
}
}
And
<html>
<body>
<wicket:extend>
<div class="heading"><wicket:message key="extras.taskType" /></div>
<form wicket:id="form" autocomplete="off">
<table>
<tr wicket:id="row">
<td>
<span wicket:id="frag"></span>
</td>
</tr>
</table>
<wicket:fragment wicket:id="labelFragment"><span wicket:id="label"></span>
</wicket:fragment>
<wicket:fragment wicket:id="textFragment"><input type="text" wicket:id="text">
</wicket:fragment>
</form>
</wicket:extend>
</body>
</html>
Any information or example code will be very helpful to me. Thank you.
Edit: I found the link: example but the source code is not available.
You can replace an entire component, but you also have to consider that the same markup might not work for both a label and a text field. But you can always replace a fragment with another fragment, so if you wrap your field and label in a fragment each, you can switch between them anytime.
However you're better off using a dedicated component for this purpose, I seem to remember an Ajax field component in either core Wicket or Wicket Extensions that did it. It is called AjaxEditableLabel
The example you are trying to remember might be this editable label example.
There is a Visural Wicket library that has ViewOrEdit component. It sounds something like you are looking for.
The ListView component may not be the best basis for a form. See http://wicketinaction.com/2008/10/building-a-listeditor-form-component/

Categories