How to create a Zul template of a button and then apply it - zk

The example provided in the zkessentials book is too simplistic yet the documentation goes way overboard (in my opinion).
What I'd like to do is create a template with just a button and pass it it's style class and it's label value.
The example in the book shows a ten-line Zul and then says you have to declare its a template but does not mention where nor does it mention how to pass values to the template.
The other examples introduce #{define(left)} and #{insert(left)} which obviously with no explanation makes it pretty difficult to make it out if I can just pass values there or if it's doing some matching.
Thanks for your help.

Maybe you just want to make a predefined class who extends button.
public class MyButton extends Button implements BeforeCompose {
#Override
public void beforeCompose() {
setLabel("new Button");
setStyle("...");
// and more settings you want to set as default
}
}
Now you have this class you can use it in 3 different ways.
First of all :
<button use="my.path.MyButton"/>
Second :
<?component name="mybutton" class="my.path.MyButton"?>
<mybutton />
Thirth :
Add this in lang-addon.xml :
<component>
<component-name>mybutton</component-name>
<extends>button</extends>
<component-class>my.path.MyButton</component-class>
</component>
and usage in zul :
<mybutton />

Related

Magento: How to add the widget button to the WYSIWYG Products Editor

I want to allow adding the Catalog Product Link widget in the description field of a product (so I can easily link to other products in the description). I've already extended Mage_Catalog_Model_Product by creating a file like:
class mymodule_Catalog_Model_Product extends Mage_Catalog_Model_Product
{
/**
* Add getDescription function that interprets widget or static blocks
* within product descriptions
*/
public function getDescription() {
$processor = Mage::getModel('widget/template_filter');
$html = $processor->filter($this->getData('description'));
return $html;
}
}
Now it works fine if I type something like
{{widget type="catalog/product_widget_link" anchor_text="my text" template="catalog/product/widget/link/link_inline.phtml" id_path="product/1234"}}
into the description field -- it creates a link to the product Id 1234.
But I want to add the actual Catalog Product Link widget button in the WYSIWYG editor for editing a product. The button is already in the CMS editor, but I am missing what I need to modify in order to add this widget to the Admin interface for editing a product. Can someone help me out?
For anybody stumbling across this later on like myself, you can use the cms_wysiwyg_config_prepare event to set this to true.
E.G:
in config.xml
<events>
<cms_wysiwyg_config_prepare>
<observers>
<webtise_widgets>
<class>webtise_widgets/observer</class>
<method>cmsWysiwygConfigPrepare</method>
</webtise_widgets>
</observers>
</cms_wysiwyg_config_prepare>
</events>
In your observer
<?php class Webtise_Widgets_Model_Observer{
public function cmsWysiwygConfigPrepare(Varien_Event_Observer $observer){
$observer->getEvent()->getConfig()->setAddWidgets(true);
}
}
I was able to do this by overriding the core file
app/code/local/Mage/Adminhtml/Block/Catalog/Helper/Form/Wysiwyg/Content.php
and setting
$config['add_widgets'] = true;
Now the widget button shows up in all WYSIWIG editors in the admin interface.

dynamic value to uibinder in gwt

I am new to GWT and trying to making a page which is trying to inherit a composite widget but the value of the composite widget is dynamic.
My main page is somehting like:
.....
.....
<g:Button>Open composite widget</g:button>
.....
.....
which is opening an another popup panel which is something like:
.....
<table>
<tr><td>Top: <myCompany:userMeasurementUnit/> </td></tr>
<tr><td>Bottom: <myCompany:userMeasurementUnit/> </td></tr>
<tr><td>Left: <myCompany:userMeasurementUnit/> </td></tr>
<tr><td>Right: <myCompany:userMeasurementUnit/> </td></tr>
</table>
the above should show us
top (cm)
bottom (cm)
left (cm)
right (cm)
But I don't know how to pass the values from main page to custom widget i.e usermeasurementunit
<myCompany:userMeasurementUnit/>
My usermeasurementunit is something like:
UIBinder:
<htmlpanel tag="span" ui:field="unit"/>
and the composit widget is
usermeasurementunit extends Composite {
public usermeasurementunit(){
initwidget...
}
public onload() {
...
}
}
Now I want to pass any measurement unit cm or inches or meters upon clicking button. I tried it using the event bus but it didnt help because when I click the button popuppanel is not on the screen and its not catching the event. If any one of you can help me regarding this I would be really thankful as I am really struggling with this thing.
kind regards
First of all, you need to understand the object instantiation flow in GWT.
They call it "delayed binding", not "dynamic binding".
Uibinder xml file is a layout template. And the JAva source bean behind it is known in general programming terms as the "code-behind".
The role or purpose of the uibinder layout template is to off-load the laying-out (on the internet many non-English speaking programmers write "lay-outing" which, though syntax-wise amusing, is the same thing) so that the code-behind could be focused on controlling the layout's responses.
It's akin to the MVP attitude. View implementation separated from presentation control. You can write the code-behind error free without even knowing exactly the positions where those fields are laid out. You could even simply supply a template where the ui elements are not properly laid out so as to concentrate on your code-behind first. Perhaps after that. one uibinder template for mobile while another for desktop - but they can share the same code-behind.
The values displayed effected by the uibinder template is determined once-and-for-all during uibind. There is no dynamic binding of a uibinder field to the ever changing value of an object/variable declared in the code-behind.
To dynamically change/propagate the values of a uibinder field after uibind, you have to deliberately set its value in the code-behind or write a listener to detect its change.
public class Graceland {
#UiField
Label pressure;
#UiField
Button reset;
public void setPressure(int value) {
pressure.setText(value);
}
#UiHandler("reset")
void nameDoesNotMatter(ClickEvent ev) {
pressure.setText(default);
}
}
GWT.create() generates the Java source for the template during compile time. GWT.create is not a run-time function.
#UiField and #UiHandler are bound to the uifield in the template during uibind.
The role of uibind() is mostly not run-time but compile time too. Though, its finality is realised during run-time, all the javascript code and respective values to construct the objects are generated during compile time and executed once and only once during uibind at run-time.
Therefore, the intention is not to be able to completely replace the dynamic role of the code-behind but simply to free it from the task of laying-out, so that we the programmer could have a clean piece of code-behind being smudged as little as possible with the spaghetti source of the layout.
However, if you wish to "dynamically" affect the value of a uibinder field during bind time,then Ui:with is your friend.
package z.mambazo;
public class Graceland {
....
String initialPressure(){
/* "dynamically" obtain the pressure from the
* pressure gauge in the petroleum distillation stack
* during uibind
*/
}
}
Graceland.ui.xml:
<ui:UiBinder blah...blah>
<ui:with type="z.mambazo" field="zulu"/>
<g:VerticalPanel>
<g:Label
ui:field="pressure"
text="the temperature is :{zulu.initialPressure}"/>
</g:VerticalPanel>
</ui:UiBinder>
The ui:with bean does not have to be the template's code-behind. Either the ui:with bean has an no-argument constructor or you have to supply ui:with tag with attributes corresponding to the constructor arguments.
You have to take note that in order to use ui:with, the init value must be declared in the value attribute not in the tag text.
<g:Label
ui:field="pressure"
text="the temperature is : {zulu.initialPressure}"/>
Not
<g:Label ui:field="pressure">
the temperature is : {zulu.initialPressure}
</g:Label>
The second way, would simply reproduce the text as is.
However, you could also do it this way:
<g:HtmlPanel>
the temperature is :
<g:Label ui:field="pressure"
text="{zulu.initialPressure}"/>
</g:HtmlPanel>
Also, be reminded that all GWT UI Java code, even the interim generated ones, are all translated into browser Javascript. So, whatever class you reference with ui:with must be in Java source code not Java byte code. And those source code must not at any time down the calling chain call byte code.
What you need are shared resources. Here is an example:
MeasurementConstants.java:
package com.acme.client;
public class MeasurementConstants {
private final String measurementUnit;
public MeasurementConstants(String measurementUnit) {
this.measurementUnit = measurementUnit;
}
public String measurementUnit() {
return measurementUnit;
}
}
UiBinderMeasurement.java:
package com.acme.client;
import com.google.gwt.core.client.GWT;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiFactory;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Widget;
public class UiBinderMeasurement extends Composite {
private static UiBinderI18nUiBinder uiBinder = GWT
.create(UiBinderI18nUiBinder.class);
private MeasurementConstants constants;
interface UiBinderI18nUiBinder extends UiBinder<Widget, UiBinderMeasurement> {
}
public UiBinderMeasurement(MeasurementConstants constants) {
this.constants = constants;
initWidget(uiBinder.createAndBindUi(this));
}
#UiFactory
public MeasurementConstants getConstants() {
return constants;
}
}
UiBinderMeasurement.ui.xml:
<!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">
<ui:with type="com.acme.client.MeasurementConstants" field="constants"></ui:with>
<g:HTMLPanel>
<table>
<tr><td><g:Label text="Top ({constants.measurementUnit}):" /> </td></tr>
<tr><td><g:Label text="Bottom ({constants.measurementUnit}):" /> </td></tr>
<tr><td><g:Label text="Left ({constants.measurementUnit}):" /> </td></tr>
<tr><td><g:Label text="Right ({constants.measurementUnit}):" /> </td></tr>
</table>
</g:HTMLPanel>
</ui:UiBinder>
Now you can call it like this:
new UiBinderMeasurement(new MeasurementConstants("cm"))

calling a child page component from parent page component in wicket

I have a problem which I tried to explained in the Image.I hope that will help all to understand what I need.
My Base Page is like this (menuNavPanel is the tree panel):
<div class="colContainer">
<div class="leftColumn" >
<div wicket:id="menuNavPanel"></div>
</div>
<div class="rightColumn">
<wicket:child/>
</div>
</div>
And Ny BIA Page which is a child of Base Page is like this:
<wicket:extend>
<div wicket:id="bodyPanel"></div>
</wicket:extend>
in my Tree Panel, when I click on a node the code is this:
#Override
protected void onNodeLinkClicked(AjaxRequestTarget target, TreeNode node) {
super.onNodeLinkClicked(target, node);
DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode)node;
Unit unitObject =(Unit) treeNode.getUserObject();
// I want to call bodyPanel fo child page passing the unitObject param
}
Now, How can I call bodyPanel fo child page passing the unitObject param from the tree panel of the parent page?
Am I been able to express my problem? Hoping to get some help :)
Instead of doing the override method, upgrade to Wicket 1.5 and utilize the new event bus to communicate between your components. You can create a custom, type-safe, event that is specific to your component's use case: for example "ItemAddedToShoppingCart" or "GlobalThermoNuclearWarStarted".
The linked article in the 1.5 migration guide provides enough information on how to set up things.
I'm not sure I understand que question correctly. Your BasePage defines a left column with the TreePanel and lets subclasses expand themselves inside the right column div. You usually put a BodyPanel inside BasePages's subclasses. And now you want to invoke a BodyPanel's method on some event on the TreePanel.
You could do it with an overridable method on BasePage, which would be called in TreePanel through getPage(). Your child pages would override that method, and its implementation would call the BodyPanel they're holding.
public class BasePage ... {
// Hook
public void treePanelSelected(Object someObject) { }
...
}
public class ChildPage extends BasePage ... {
BodyPanel bodyPanel;
#Override
public void treePanelSelected(Object someObject) {
bodyPanel.selectionChanged/(someObject);
}
...
}
public class TreePanel ... {
...
#Override
protected void onNodeLinkClicked(AjaxRequestTarget target, TreeNode node) {
super.onNodeLinkClicked(target, node);
DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode)node;
Unit unitObject =(Unit) treeNode.getUserObject();
((BasePage)getPage()).treePanelSelected(unitObject);
}
}
From my ignorance on your specific needs and details of implementation, I don't see why is subclassing the BasePage necessary. You could add the BodyPanel right there in the BasePage and control it from the same class.
Thanks all, After reviewing all the nice options I finally opted out for the event bus way defined by martijn. What I did is I have created an event payload and connected the panels for the talking. I also needed to pass the selected Id / entity to the receiving panel.
Is there a way to set a compound property model of the receiving panel according to the model of the tree element so that I don't need to do the model manually ?
I did like this for the time being:
public class TreeNodeClickUpdate {
private final AjaxRequestTarget target;
private final long selectedId;
/**
* Constructor
*
* #param target
* #param selectedId
*/
public TreeNodeClickUpdate(AjaxRequestTarget target, long selectedId)
{
this.target = target;
this.selectedId = selectedId;
}
/** #return ajax request target */
public AjaxRequestTarget getTarget()
{
return target;
}
public long getSelectedId() {
return selectedId;
}
}
On the sender side I've done like this:
send(getPage(), Broadcast.BREADTH,
new TreeNodeClickUpdate(target, unitObject.getId()));
And on the receiving end I got it like this:
#Override
public void onEvent(IEvent<?> event) {
super.onEvent(event);
if (event.getPayload() instanceof TreeNodeClickUpdate)
{
TreeNodeClickUpdate update = (TreeNodeClickUpdate)event.getPayload();
setSelectedId(update.getSelectedId()); //sets to id field of panel
update.getTarget().add(this);
}
}
and for just as an example in my receiving panel, to get the value I have created a label like this:
label = new Label("label",new PropertyModel<BiaHomePanel>(this,"selectedId"));
Later, in reality I want to get information from the entity and show in form. Is there a nice way to pass models in a better way or I should pass as a parameter in event payload.
There are two ways to do this. One is cleaner, but requires more code. The other is quick and dirty.
Method 1: (Good)
Since your parent page is being extended, you can provide an abstract method in the parent like
protected abstract WebMarkupContainer getBodyPanel();
that is implemented in your child page and returns the appropriate panel. Then, you can call that method from the panel in your parent page. This is similar to the overrideable method suggested by the other user.
Method 2: (Bad)
The Wicket Component Hierarchy is shared between the parent and child pages. So, if you make sure that your bodyPanel has a unique wicketId and is added directly to the root of the page, you can probably just call
get("bodyPanelId");
and it will return the proper panel.
When I was facing the problem, I thought of two ways to solve this (pre 1.5):
a) implement a variation of the observer pattern to notify other component of events like outlined here: Realising complex cross-component ajax actions in wicket - The observer way
b) using wicket visitors to traverse the component tree doing the same.
I decided to go for variant a) but this introduces coupling from your component to your page-implementation which leads to problems when testing panels on their own. So maybe b) might be the better idea but since my application is running quite smoothly with a) implemented and the next big step will be switching over to 1.5 and the event bus, I haven't yet tried b).

GWT: how to embed widgets in Anchor with UIBinder

I'd like to use the following in UIBinder, so that I can programmatically set the href of the link in my code.
<g:HTMLPanel>
<g:Anchor ui:field="link">
<g:InlineLabel ui:field="firstName"/>
<g:InlineLabel ui:field="lastName"/>
</g:Anchor>
</g:HTMLPanel>
When I try this I get:
ERROR: Found widget in an HTML context Element <g:InlineLabel ui:field='firstName'> (:7).
How can I embed widgets inside an anchor? Previously I've resorted to using:
<a id="myAnchor">
etc...
</a>
And then manipulating the DOM in my code to set the HREF, but that's ugly. Is there a better way?
The class below acts exactly like a SimplePanel (i.e., you can put an widget in it), but uses an "a" instead of a "div". If you need more widgets just put another panel in it.
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.ui.SimplePanel;
public class Link extends SimplePanel {
public Link() {
super(DOM.createAnchor());
}
private void setHref(String href) {
getElement().setAttribute("href", href);
}
private String getHref() {
return getElement().getAttribute("href");
}
public void setTarget(String frameName) {
getElement().setAttribute("target", frameName);
}
}
It is better to use a Panel (Flow or Horizontal) and add click handlers to the panel to simulate a link. Anchor, Button and similar widgets will not allow child tags inside them.

GWT - Two Question on Hyperlink - Manage its History token parameter + insert it in a span

I need to manage a Hyperlink object in GWT. What i need is :
1 - add it into a span (like InlineLabel)
I tried Hyperlink affitta_3_span_1=new Hyperlink(result.get(i)[0], "");, but it create somethings like this :
<div class="affitta_3_span_1">
t1
</div>
in fact i need this :
<span class="affitta_3_span_1">
t1
</span>
2 - manage Hyperlink History token
I put my internal links such Hyperlink affitta_3_span_1=new Hyperlink(result.get(i)[1], "article/"+result.get(i)[0]) but i don't know how to get the parameter on token when they call the onValueChange() function. How can I do it?
Cheers
Use an Anchor. The output is just an <a> tag that has no <div> or <span> around it, but if you need a <span> you can add it with an HTML panel.
To set a URL that history can access, just put a # at the beginning. Something like
myAnchor.setText(result.get(i)[1]);
myAnchor.setUrl("#article/"+result.get(i)[0]);
Now, when you click myAnchor, onValueChange will be passed the token "article/whatever". The unfortunate side effect is that your urls look like http://example.com/#article/whatever, but that's the only way to get the token to the History object with just GWT.
For the first question, use an Anchor since it's inlined.
For the second one, you need to 'listen' to history change events by extending ValueChangeHandler and calling History.addValueChangeHandler(this); in your class. For example,
class MyClass implements ValueChangeHandler<String> {
public MyClass {
...
History.addValueChangeHandler(this);
}
#Override
public void onValueChange(ValueChangeEvent<String> event) {
String token = event.getValue();
if (token.equals("foo")) {
// go to one page
} else if token.equals("bar")) {
// go to another page
}
}
}
If you only need a ClickHandler on your link and no history support, you can use the Anchor widget, which is based on an <a> tag that has display: inline by default.