How to navigate DOM from Wicket - wicket

I wonder if it is possible to modify the HTML code of the parent of a wicket component in the Java code to modify its attribute without making it a component in wicket. For example, I would like to add active to the li tag from Java.
<li>
<a wicket:id="home" href="#">
<i class="icon-home"></i>
<span>Home</span>
</a>
</li>
and the say add an Attribute to that parent without referencing it in code as a component.

I don't think this is possible, it would be completely against the modular nature of Wicket. (Not to mention the fact that pages are actually rendered as a stream, there's no DOM tree built.)
Components in Wicket shouldn't depend on what's outside of them. What if you want to change the logic of active/inactive controls? Or, in a more likely scenario, you just want to change the markup. Or if you just want to unit test your component without any surrounding markup.
Wicket was designed to avoid these "spooky actions at a distance", to create components that are genuinely testable on their own.
You need a component that encapsulates the entire list, which keeps track of which of its items is active (via its model). It might seem at first like a lot of work but when you look at the result, you'll realise how much easier it is to understand what's going on.

You can do it using javascript. In this example I overrided the renderHead() of the link, but it can also be done with a Behavior.
public class TestPage extends WebPage {
public TestPage(final PageParameters parameters) {
super(parameters);
add(new AjaxLink<Void>("link") {
boolean active = false;
#Override
public void onClick(AjaxRequestTarget target) {
active = !active;
target.add(this);
}
#Override
public void renderHead(IHeaderResponse response) {
super.renderHead(response);
String addOrRemove = (active) ? ".addClass('active')" : ".removeClass('active')";
response.render(OnDomReadyHeaderItem.forScript("$('#" + getMarkupId() + "').parent('li')" + addOrRemove + ";"));
}
});
}
}
<!DOCTYPE html>
<html xmlns:wicket="http://wicket.apache.org">
<head>
<style type="text/css">
li.active {background-color: red;}
</style>
</head>
<body>
<ul>
<li><a wicket:id="link">TOGGLE</a></li>
</ul>
</body>
</html>
Yes, it will couple the code to the markup, but this is not always a problem. If you feel you are copying and pasting this code over and over, consider creating a proper component :)

Related

Override CSS for specific Bootstrapvue Components

first Question here so please educate me if i'm doing this wrong.
So im working on an SPA that uses BootsrapVue and i created a view that uses a
<b-form-checkbox-group
v-model="anything"
:options="options"
:disabled="ifDisabled"
button-variant="outline-secondary"
buttons
>
when this gets rendered i get this html:
<fieldset data-v-3bacc3f3 class="form-group" id="__BVID__38">
<legend tabindex=-1" class="bv-no-focus-ring col-form-label pt-0" id="__BVID__38__label_">Selector</legend>
<div>
<div> data-v-3baac3f3 role="group" tabindex="-1" class="btn-group-toggle btn-group bv-no-focus-ring" id="__BVID__39">
<label class="btn btn-outline-secondary disabled atcive">
<input type="checkbox" name="buttons-1" disabled="disabled" class value="100" id="__BVID__39_BV_option_0">
<span>100</span>
...
now i've tried alot of stuff but cant figure out how i am able to override the scss styles for the options. Preferably only in this scope, but i cant even manage to do it globaly.
I'm even having trouble figuring out the right place where i should be looking to change css for :hover and :focus.
please help!
This works:
<style lang="scss">
.btn-group-toggle:not(#_) label {
/* general styles */
&.disabled {
}
&.focus {
}
&.active {
}
&:hover {
}
}
</style>
When adding scoped attribute to the <style> tag, you're largely at the hand of your installed pre-processor which might or might not be able to parse >>>, /deep/, ::v-deep or :deep(), depending on version.
To stay away from such issues, I use the suggestion made in Vue Loader's docs: I create a separate <style> tag for bootstrap-vue internals, without the scoped attribute and keep the rest of component style rules in a <style scoped>.
Working demo.

How to remove custom element while avoiding detached DOM trees?

I'm using Polymer to create custom elements (web components) and have run into a problem when removing them from the DOM. Say I have an element like this:
<link rel="import" href="../polymer/polymer.html">
<polymer-element name="demo-element">
<template>
<h1 on-tap="{{ titleTap }}">A custom demo element</h1>
</template>
<script>
Polymer('demo-element', {
titleTap: function() { // do something }
});
</script>
</polymer-element>
Then when removing the <demo-element></demo-element> from the DOM I will end up with a detached DOM tree with a reference to the H1 element (according to Chrome Devtools). It seems to me that it's the polymerWrapper that references it.
According to the documentation in Polymer API reference the framework should automatically handle the unbind. Is this not working or am I misunderstanding it?
Is this something that in the future will be handled by the browsers or will we need to depend on frameworks like Polymer to do keep our memory clean? (So what I'm asking is if there are any proposals or standards relating to this)

I am not able to run my apache wicket sample program

I am very new to java wicket. I don't understand how to run this code. My wicket program follows the structure below. My problem is that I am not able to run this. I am getting a 404 error.
This is my wicket code to get a hello world message.
HelloWorld.html:
<html xmlns:wicket>
<title>Hello World</title>
</head>
<body>
<span wicket:id="message" id="message">Message goes here</span>
</body>
</html>
</html>
HelloWorld.java:
package com.sensiple.wicket;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.basic.Label;
public class HelloWorld extends WebPage {
public HelloWorld() {
add(new Label("message", "Hello World!"));
}
}
This class is returning hello world which is to be printed in HelloWorld.html
HelloWorldApplication.java:
package com.sensiple.wicket;
import org.apache.wicket.protocol.http.WebApplication;
public class HelloWorldApplication extends WebApplication {
//what is the need of this constructor, need of this class in this program
public HelloWorldApplication() {
}
I need to know what is the use of getHomePage-method too, as I am not getting what is the use of one more class here which returns return type as HelloWorld. Hardly I am not able to run this code. I went through many resources which didn't help.
public Class<HelloWorld> getHomePage() {
System.out.println("initialized!!!!");
return HelloWorld.class;
}
}
To start answering your many questions:
Your program is most likely returning a 404 due to the malformed HTML in your HelloWord.html. Wicket required valis XHTML to work with.
The original signature of getHomePage() is public abstract Class<? extends Page> getHomePage(). You can implement it as you did as it fullfills the contract. The method returns the class that is used to render the homepage of your web application. That's the page that is shown at the base-url of your application without any mountpoints or parameters.
You don't need the default constructor to your WebApplication but you can implement one to do some of the initialisations needed for your application. It's run once at the start of your application (or in most cases your container).
Try using this html:
<!DOCTYPE html>
<html xmlns:wicket="http://wicket.apache.org">
<head>
<title>Hello World</title>
</head>
<body>
<span wicket:id="message"></span>
</body>
</html>
When your application is running, just call http://localhost:8080 (unless you changed the port) and wicket should redirect you to your HelloWorld page

How to use buttons with GWT's UiBinder?

In MyPanel.ui.xml:
<button class="btn" ui:field="myButton">Save</button>
In MyPanel.java:
public class MyPanel extends Composite {
...
#UiField ButtonElement myButtonUi;
...
public MyScreen() {
final HTMLPanel panel = uiBinder.createAndBindUi(this);
initWidget(panel);
Button myButton = Button.wrap(myButtonUi);
In MyEntryPoint.java:
if (....)
RootPanel.get().add(new MyPanel());
So I think I don't really understand how to use UiBinder.
It's my intention to use HTML with ui:field=".." so that the web-designer can set things like class="xx" on the UI fields. Most of the GWT documentation assumes you've got a Button not a ButtonElement. But if I use a Button I need to have a <g:Button> in the HTML document which means my web-designer can't set the class? I mean the point of UiBinder is to allow one to use normal HTML and integrate it with the GWT code?
When I do the above, on the wrap line, I get a NullPointerException in development mode from:
public static Button wrap(com.google.gwt.dom.client.Element element) {
// Assert that the element is attached.
assert Document.get().getBody().isOrHasChild(element);
In production mode it seems to work OK. In the debugger of development mode in Eclipse, when I right-click and "Inspect" the expression "Document.get().getBody()" Eclipse says "Cannot send a static message to a non class type object".
What should I do? Is the null pointer exception happening because I need to attach the element first? If so, how? (I am already calling createAndBindUi and the element passed to wrap is non-null).
So finally, here's the answer. I Edited it and deleted useless comments.
You can't use HTML in your ui.xml if your plan is to use UiBinder to wire a component from the ui.xml to your view's Java code. Instead of
<button class="btn" ui:field="myButton">Save</button>
use
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' xmlns:g='urn:import:com.google.gwt.user.client.ui'>
<g:Button styleName="btn" text="Save" ui:field="myButton"/>
Then in your view -java code- simply type
#UiField com.google.gwt.user.client.ui.Button myButton;
public MyScreen() {
final HTMLPanel panel = uiBinder.createAndBindUi(this);
initWidget(panel);
}
That's it.
The "styleName" attribute is enough for your designer to hook a CSS class. This other post might interest you. Designers will have to learn about what attributes are available on which components. Using UiBinder is not as straighforward as using HTML.
UiBinder is not for writing HTML but to write XML that can be understood by GWT and compiled to javascript (which in turn will produce the page's HTML). It's not like the JSP mechanism where you can insert plain HTML right away.
UiBinder is most helpful when you have to wire ui elements (widgets or composites from the ui.xml) with your Java view code (i.e. using the #UiField or #UiHandler annotations).
You can use HTML. The only restriction is that g:Button must be inside a container like g:HTMLPanel.
The good thing about g:HTMLPanel is that it can render HTML.
See the example below:
<g:HTMLPanel>
<div>
test
</div>
<table border="1">
<th>
button
</th>
<tr>
<td>
<g:Button styleName="{style.important}" ui:field="button"/>
</td>
</tr>
</table>
<div>
test
</div>
</g:HTMLPanel>

Testing Wicket panels with constructor arguments

I got a page with several panels that takes several parameters in their constructors.
One of them being a menu that takes a list for the different buttons in the menu.
I've tried to test it as components but get a null pointer exception. Using a dummy page and creating the panel on the dummy page works.
I'm not entirely happy with this approach since it introduces a lot of new code in my tests and more possibilities for errors.
Is there a better way of testing panels that takes arguments in their constructor?
Sure thing:
The code that gives an null pointer error:
public void testVisitPanel(){
VisitPanel v = new VisitPanel("visitPanel");
tester.startComponent(v);
tester.assertContains("DATE");
}
The panel
public VisitPanel(String id) {
super(id);
add( new Label("visitDate", "DATE"));
add( new Label("visitStage", "VISIT SIGNED"));
}
And the html
<!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"
xmlns:wicket="http://wicket.sourceforge.net/"
xml:lang="en"
lang="en">
<wicket:head>
</wicket:head>
<body>
<wicket:panel>
<span wicket:id="visitDate">VISIT DATE</span>
<span wicket:id="visitStage">STAGE</span>
</wicket:panel>
</body>
</html>
If you're using Wicket 1.4, you probably want wicketTester.startPanel.
What I do is create an implementation of ITestPanelSource in the test, doing something like:
private class TestPanelSource implements ITestPanelSource {
private static final long serialVersionUID = 1L;
public Panel getTestPanel(String panelId) {
return new MyPanel(panelId, myArg1, myArg2);
}
}
with the myArgN being fields in the test class (frequently mocks) that suit the constructor, and then call it in the test or in a setUp method with
wicketTester.startPanel(new TestPanelSource());
This is basically doing some of the DummyPage work for you, so it may not be that far from what you're doing now, but might at least save on implementation of dummy pages for test infrastructure.
In Wicket 1.5, this is deprecated in favor the component testing that you referenced in the question. That should also work, so it might be worthwhile to post some actual code that is giving you trouble with that technique.