NavbarDropDownButton displaying blank links - wicket

I'm trying to use Wicket-Bootstrap Navbar and NavbarDropDownButton inside my Wicket Application to display a list of links.
Web application is built with Wicket 8.7.0 and Wicket-Boostrap-core 3.0.0-M13.
The component I added to the Wicket Panel seems to work correctly, but once I click on the main link to display the dropdown content, all links are blank. Anyway I can click the links and they made their job.
Here's the picture taken from the browser:
Here's the HTML used:
....
<div class="navbar" wicket:id="utenteNavbar">
</div>
</div>
while this is my Java code:
Model<String> cambioPasswordStringModel = Model.of(getString("cambioPassword"));
Navbar navbar = new Navbar("utenteNavbar");
INavbarComponent dropDownComponent = new INavbarComponent() {
#Override
public ComponentPosition getPosition() {
return Navbar.ComponentPosition.LEFT;
}
#Override
public Component create(String markupId) {
NavbarDropDownButton dropdownButton = new NavbarDropDownButton(Model.of(welcomeMessage)) {
#Override
protected List<AbstractLink> newSubMenuButtons(String buttonMarkupId) {
final List<AbstractLink> linksList = new ArrayList<AbstractLink>();
AjaxLink<String> cambioPasswordLink = new AjaxLink<String>(buttonMarkupId,
cambioPasswordStringModel) {
#Override
public void onClick(AjaxRequestTarget target) {
setResponsePage(CambioPasswordPage.class);
}
};
linksList.add(cambioPasswordLink);
return linksList;
}
};
return dropdownButton;
}
};
navbar.addComponents(dropDownComponent);
add(navbar);
add(welcomeMessageLabel);
Where's the mistake? Maybe I'm missing something on the CSS side?
Hope everything is clear, thanks for any help.

Related

Wicket 7 Link/Label error when using inheritance

With Wicket 7, I am working on an app that uses a base page as a template for other pages to extend.
On the base page, I want to have a label and a link that changes depending on whether the user is authenticated or not.
Here's my BasePage.html:
<div wicket:id="chromeMenu">foo</div>
<div>
<h2 wicket:id="userGreeting"></h2>
<h2><span wicket:id="loginLabel"></span> </h2>
</div>
<wicket:child/>
and the BasePage.java:
public BasePage() {
super();
add(new ChromeDropDownMenu("chromeMenu", buildMenu()));
add(new Label("pageTitle", new StringResourceModel("page.title", this, null)));
if(BasicAuthenticatedSession.get().isSignedIn()) {
// Do stuff here
} else {
add(new Label("userGreeting", "Hello Visitor"));
add(new Link("loginLink") {
#Override
public void onClick() {
setResponsePage(LoginPage.class);
}
});
add(new Label("loginLabel","Test"));
}
}
HomePage extends BasePage.
HomePage.html
<wicket:extend/>
HomePage.java
public class HomePage extends BasePage {
private static final long serialVersionUID = 1L;
public HomePage() {
super();
setPageTitle(new StringResourceModel("page.title", this, new Model<Serializable>("Admin")));
add(new Label("version", getApplication().getFrameworkSettings().getVersion()));
}
}
HomePage is the class returned by the Wicket application.
When I try to load HomePage, I get the following error:
Last cause: Unable to find component with id 'loginLabel' in [Link [Component id = loginLink]]
Expected: 'loginLink:loginLabel'.
Found with similar names: 'loginLabel'
It points to the <a><span/></a> structure from BasePage.html as the root of the problem.
I've tried a few ways to work around this, but without success. I thought maybe an add(Link).add(Label) might be needed, but that didn't work either.
Any thoughts out there on what I'm missing?
The error message says it all.
Last cause: Unable to find component with id 'loginLabel' in [Link
[Component id = loginLink]]
Expected: 'loginLink:loginLabel'.
Found with similar names: 'loginLabel'
Wicket is expecting the same component hierarchy in your Java code as you've written in the HTML. In BasePage.html you have:
<h2><span wicket:id="loginLabel"></span> </h2>
In the BasePage.java code you need to add loginLabel as a child of loginLink component.
Link loginLink = new Link("loginLink") {
#Override
public void onClick() {
setResponsePage(LoginPage.class);
}
};
add(loginLink);
loginLink.add(new Label("loginLabel", "Test"));
The problem is at
add(new Link("loginLink") {
#Override
public void onClick() {
setResponsePage(LoginPage.class);
}
});
add(new Label("loginLabel","Test"));
The Link should be the parent of the Label:
link = new Link("loginLink") {
#Override
public void onClick() {
setResponsePage(LoginPage.class);
}
};
link.add(new Label("loginLabel","Test"));
add(link);
Few extra notes:
better use BookmarkablePageLink if setResponsePage() is the only thing you need in onClick()
use AbstractLink#setBody(IModel label) instead of Link+Label

Link to last version of stateful page

I have a number of stateful pages with some state for each page. For example each page has a form that was submitted.
How can I organize a menu with links to last versions of these stateful pages? Should I store anywhere (may be in the session) reference to appropriate object for each page? If I use
onClick() { setResponsePage(MyPage.class); }
than I lose the previous state of the page. I want to link to last state of the page.
Each time the page is rendered store the page's id in the session.
int pageId = pageInstance.getPageId();
A list or stack data structure could be used to hold the identifiers.
You can implement the navigation menu using a repeater (RepeatingView or such) that creates a new link for each page id in the session.
In the link's click handler you can redirect the user as follows:
Page pageInstance = (Page) new PageProvider(pageId, null).getPageInstance();
setResponsePage(pageInstance);
pageId = this.getPageId(); // get current version of lets say a HomePage
//OnClick for Link
public void onClick()
{
WebPage homePageInstance =
(WebPage) new PageProvider(HomePage.pageId, null).getPageInstance();
setResponsePage(homePageInstance);
}
});
I make it passing int previousId parameter via constructor :
#MountPath(value = "editSomethingPage")
public class TestPage extends WebPage {
int previousPageId = 0;
public TestPage(int previousPage) {
super();
this.previousPageId = previousPage;
}
#Override
protected void onInitialize() {
super.onInitialize();
add(new Link("goBack") {
#Override
public void onClick() {
if (previousPageId != 0) {
setResponsePage((Page) AuthenticatedWebSession.get().getPageManager().getPage(previousPageId));
} else {
setResponsePage(PreviousPage.class);
}
}
});
}
}
It prevents creation of new page instance and keeps all states of page made by user.

How to find out component-path

I use junit to assert the existing of wicket components:
wicketTester.assertComponent("dev1WicketId:dev2WicketId:formWicketId", Form.class);
This works for some forms. For complex structure, it is defficult to find out the path of the form by searching all html files. Is there any method how to find out the path easy?
If you have the component you can call #getPageRelativePath(). E.g.
// Supposing c is a component that has been added to the page.
// Returns the full path to the component relative to the page, e.g., "path:to:label"
String pathToComponent = c.getPageRelativePath();
You can get the children of a markup container by using the visitChildren() method. The following example shows how to get all the Forms from a page.
List<Form> list = new ArrayList<Form<?>>();
Page page = wicketTester.getLastRenderedPage();
for (Form form : page.visitChildren(Form.class)) {
list.add(form);
}
An easy way to get those is to call getDebugSettings().setOutputComponentPath(true); when initializing your application. This will make Wicket to output these paths to the generated HTML as an attribute on every component-bound tag.
It's recommended to only enable this on debug mode, though:
public class WicketApplication extends WebApplication {
#Override
public void init() {
super.init();
if (getConfigurationType() == RuntimeConfigurationType.DEVELOPMENT) {
getDebugSettings().setOutputComponentPath(true);
}
}
}
Extending the RJo's answer.
It seems that the method page.visitChildren(<Class>) is deprecated (Wicket 6), so with an IVisitor it can be :
protected String findPathComponentOnLastRenderedPage(final String idComponent) {
final Page page = wicketTester.getLastRenderedPage();
return page.visitChildren(Component.class, new IVisitor<Component, String>() {
#Override
public void component(final Component component, final IVisit<String> visit) {
if (component.getId().equals(idComponent)) {
visit.stop(component.getPageRelativePath());
}
}
});
}

Gwt form question

I have a gwt form which has about 70-100 widgets (textboxes,listboxes,custom widgets etc)
I am trying to implement the features of CUT ,COPY in this form .For this i have 2 buttons right on top of the form.
Now the problem i have is that when i click on the copy button , the widget that was focused in the form looses focus and i dont know which text to copy(or which widget was last focused before the focus getting to the copy button)
I was planning to implement blur handlers on all the widgets but i feel is a very laborious and not a good solution.
How can i get around this issue?
Thanks
Perhaps someone with a deeper insight might provide a better approach but I beleive adding blur handlers is perfectly valid. I do not quite see why you think it would be laborious, after all you don't need a different handler for each of your widgets, you can get away with only one(at most a couple for a variety of controls..), here is a very simple example,
public class CustomBlurHandler implements BlurHandler{
Object lastSource;
String text;
#Override
public void onBlur(BlurEvent event) {
if (event.getSource() instanceof TextBox) {
lastSource = event.getSource();
text = textBox.getSelectedText();
}
}
public Object getLastSource() {
return lastSource;
}
public String getText() {
return text;
}
}
and onModuleLoad :
public class Test implements EntryPoint {
CustomBlurHandler handler = new CustomBlurHandler();
public void onModuleLoad() {
TextBox text1 = new TextBox();
TextBox text2 = new TextBox();
text1.addBlurHandler(handler);
text2.addBlurHandler(handler);
Button b = new Button("Get last selected text");
b.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
Window.alert(handler.getLastSource()+ " " + handler.getText());
}
});
RootPanel.get().add(text1);
RootPanel.get().add(text2);
RootPanel.get().add(b);
}
}

GWT Tab panel close

I am building an application in GWT. I have a decorated tabpanel in
my application.Where in am adding panels to it dynamically.Now i want
to achieve the closing of these tabs. I want to add a close image to
the tab bar and event to that image for closing. I am using UIbinder.
the working code is like that;
private Widget getTabTitle(final Widget widget, final String title) {
final HorizontalPanel hPanel = new HorizontalPanel();
final Label label = new Label(title);
DOM.setStyleAttribute(label.getElement(), "whiteSpace", "nowrap");
ImageAnchor closeBtn = new ImageAnchor();
closeBtn.setResource(images.cross());
closeBtn.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
int widgetIndex = tabs.getWidgetIndex(widget);
if (widgetIndex == tabs.getSelectedIndex()) {
tabs.selectTab(widgetIndex - 1);
}
tabs.remove(widgetIndex);
}
});
hPanel.add(label);
hPanel.add(new HTML("&nbsp&nbsp&nbsp"));
hPanel.add(closeBtn);
hPanel.setStyleName("gwt-TabLayoutPanelTab");
return hPanel;
}
In order to add tab,
public void addTab() {
TabWriting tw = new TabWriting(); /* TabWriting in my case, this can be any widget */
tabs.add(tw, getTabTitle(tw, "Writing"));
tabs.selectTab(tw);
}
You'll going to need, ImageAnchorClass
public class ImageAnchor extends Anchor {
public ImageAnchor() {
}
public void setResource(ImageResource imageResource) {
Image img = new Image(imageResource);
img.setStyleName("navbarimg");
DOM.insertBefore(getElement(), img.getElement(), DOM
.getFirstChild(getElement()));
}}
It isn't supported natively in GWT.
You can manually try to add it.
Read this - http://groups.google.com/group/google-web-toolkit/browse_thread/thread/006bc886c1ccf5e1?pli=1
I haven't tried it personally, but look at the solution by gregor (last one).
You kinda need to do something along the lines of this
GWT Close button in title bar of DialogBox
First you need to pass in the tab header when you create the new tab. The header you pass in should have your tab text and also an X image or text label to click on. Then add a event handler on the close object that gets the widget you are adding to the tabPanel and removes it. Here is some inline code that works
public void loadTab(final Widget widget, String headingText, String tooltip) {
HorizontalPanel panel = new HorizontalPanel();
panel.setStyleName("tabHeader");
panel.setTitle(tooltip);
Label text = new Label();
text.setText(headingText);
text.setStyleDependentName("text", true);
Label close = new Label();
close.setText("X");
close.setTitle(closeText_ + headingText);
text.setStyleDependentName("close", true);
close.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
Window.alert("close this tab");
ClientGlobal.LOG.info("widget : " + tabPanel_.getWidgetIndex(widget));
tabPanel_.remove(tabPanel_.getWidgetIndex(widget));
}
});
panel.add(text);
panel.add(close);
panel.setCellHorizontalAlignment(text, HasHorizontalAlignment.ALIGN_LEFT);
panel.setCellHorizontalAlignment(close, HasHorizontalAlignment.ALIGN_RIGHT);
tabPanel_.add(widget, panel);
tabPanel_.getTabWidget(widget).setTitle(tooltip);
tabPanel_.selectTab(widget);
}