Style individual cells in CellTable using CSSResources - java

Basically I want to implement something similar to the the cell-coloring which is defined in the GWT documentation
However I don't want to specify the style directly on the DIV element but want to assign an obfuscated stylename from my custom CSSResource which I defined for my CellTable.
Here is some code:
I defined a custom Resources interface for my CellTable:
public interface CellTableResources extends Resources {
#Source({CellTable.Style.DEFAULT_CSS,CellTableStyle.STYLE})
CellTableStyle cellTableStyle();
public interface CellTableStyle extends Style {
String STYLE = "CellTable.css";
public Sring coloredCell();
}
}
I pass it to the constructor of my CellTable:
CellTable<XY> table = new CellTable<XY>(15,cellTableResources);
This is how my custom cell looks like.
public class ColorCell extends AbstractCell<String> {
interface Templates extends SafeHtmlTemplates {
#SafeHtmlTemplates.Template("<div class=\"{0}\">{1}</div>")
SafeHtml cell(String classname, SafeHtml value);
}
private static Templates templates = GWT.create(Templates.class);
#Override
public void render(Context context, String value, SafeHtmlBuilder sb) {
if (value == null) {
return;
}
// how can I access the CSSResources which I pass to the CellTable
CellTableResources ressources = ?
String className = ressources.cellTableStyle().coloredCell();
SafeHtml safeValue = SafeHtmlUtils.fromString(value);
SafeHtml rendered = templates.cell(className, safeValue);
sb.append(rendered);
}
}
How can I access my CellTableRessources that I passed to my CellTable in my custom cell?
Here is the important part:
// how can I access the CSSResources which I pass to the CellTable
CellTableResources ressources = ?
String className = ressources.cellTableStyle().coloredCell();
The only solution I come up with is to pass the CellTableRessources to the constructor of my AbstractCell.
Isn't there a more elegant way (I already have passed it to the CellTable).
I think the main question is:
"How can I access CellTable variables from a Cell or Column?"

The problem with a 'more elegant way' is that it implies that CellTable's own styles will be useful elsewhere, which they probably won't. Even if they provided a getter for style, that would return an instance of type Style, which you would then have to cast to your own style.
It is best to consider this to be your style, which presents a few options:
Keep a reference around so you can access it from within your cell
GWT.create a new copy of the client bundle within your cell and call ensureInjected() - it will only actually inject it once, so this really isn't a problem, just a good practice, esp if someone decides to use your cell without the style on the table itself.
And last, break out the styles needed for the cell into their own clientbundle/cssresource, and make them part of the cell itself. This lets you completely break apart the dependency of the cell on even being put in a celltable (as opposed to a celllist or cellbrowser, etc).
The only tricky part is if the styles on the cell do depend on the styles in the table, in which case this annoying dependency you are dealing with is a good thing - it is requiring you to be aware of that dependency in the styles themselves. If you go for the third (I see this as the cleanest) option but still have this dependency, you can go a step further - declare a style/clientbundle in your cell, but extend it like you are doing to the CellTable's ClientBundle - and since these are interfaces, you can make one bundle that extends both of these, and is supplied to each table and cell.

Related

Can two exported classes in different packages interact without making their members public?

I stumbled across this issue while working on a library and have been trying to find a solution for hours now. I'm not sure if this is even possible or not. I have a module, com.gui, which contains a package called com.gui.components, com.gui.constraints and com.gui.animation. I want to implement text-based components and set up a package called com.gui.text.
I have a Font class inside of that package (com.gui.text) which should be public so the user can pass it into one of the text components. However, I'm struggling with how I transfer data like the texture id over to the text component without making the variable public (or implement a public getter). I messed around with not exporting the text package and extending the Font class inside of the text component class but this seemed like a suboptimal solution and I don't really like the feel of it.
Here is the hierarchy of my project visually:
src/com.gui
--component -> exported
----UITextComponent
--text
----mesh
------Texture
----font -> exported
------Font // contains a Texture object which should stay invisible to the user
--XXX // other packages
Am I missing anything obvious here or is this impossible to do currently?
If you want to go crazy you can do the following (this is not recommended)
in your Font class have a method like this:
public class Font {
private String textureId;
...
public void setTextureId(Texture texture) throws Exception {
if (texture == null) return;
Field field = texture.getClass().getDeclaredField("textureId");
if (field == null) return;
field.setAccessible(true);
textureId = String.valueof(texture.get(font));
}
}
Again this is not the recommended way but it is a way to get what you want with the layout you have. Also you'd have to add some more validation checks.

Pass a render function via property definition of custom control

I have built a custom control which renders an arraylist of java objects via a repeat control. Via the property definition I can provide which fields from the underlying java object I want to display. In the back-end I read this value e.g. via
obj[compositeData.columnField1]
This works well with static data, but sometimes I want to format the before rendering e.g. when the field contains a notesname and I only want to display the commonname.
I am wondering how I could set up something like that.
Now I am only passing the field name, which will be picked up by the cc to read the value.
E.g. for the jQuery DataTables plugin you can define a render function for a column and use the data variable of that column within that render function (e.g. build an anchor link or button in that column).
Can I provide something similar for SSJS e.g. I pass the render function as text (or object?) and in the back-end it will be transformed to ssjs.
Functions in JavaScript are first class citizens on objects. Presume you created a JS object with all the rendering functions and stored it in one of the scopes. E.g. viewScope.renderFunctions. Then hand over the name of the render function and inside use something like:
var renderfunc = viewScope.renderFunctions[funcname];
var result = renderfunc(rawdata);
return result;
That should do the trick
I found an answer here on stackoverflow. The eventhandler for my button looks as followed:
<xp:eventHandler event="onclick" submit="true"
refreshMode="partial" refreshId="pnlContainer"
action="#{javascript:if (compositeData.actionButton.action) if (!compositeData.actionButton.action.call()) return;}">
</xp:eventHandler>
For my custom control I have set up a property:
<property>
<property-name>action</property-name>
<property-class>javax.faces.el.MethodBinding</property-class>
<property-extension>
<designer-extension>
<editor>com.ibm.workplace.designer.ide.xfaces.internal.editors.MethodBindingEditor</editor>
</designer-extension>
</property-extension>
<description>ssjs that action button must perform</description>
</property>
Make sure the class and editor are as above.
Then the property on the xpage containing the custom control contains the ssjs:
action="#{javascript:removeSelected}"
This is a function that resides in a SSJS script library. The key here is not to provide ANY parameters of parantheses (!!!)
The SSJS function is as followed:
function removeSelected(){
var accessList = sessionScope.get("removalList");
var nsf_committee = datasources["COM1_DB_FILEPATH"];
var db:NotesDatabase = session.getDatabase(session.getServerName(), nsf_committee);
for (var i = 0; i < accessList.length; i++) {
var doc:NotesDocument = db.getDocumentByUNID(accessList[i]);
if (null != doc){
doc.remove(true);
accessList.remove(accessList[i]);
}
}
}
(here I remove documents from the database. the unid id's reside in a an arraylist. the array list is set via a checkbox group for each row in my repeat control.)
Considering you would likely want to re-use the component in many contexts of your app I would approach the problem with an helper class and interface
public class FieldManager {
public static interface FieldDetail {
String getName();
void getAction();
}
private List<FieldDetail> fieldDetails = new List<FieldDetail>();
public FieldManager() {
}
public FieldManager(List<FieldDetail> fieldDetails) {
this.fieldDetails.addAll(fieldDetails);
}
public void addFieldDetail(FieldDetail fieldDetail) {
this.fieldDetails.add(fieldDetail);
}
public List<FieldDetail> getFieldDetails() {
return fieldDetails;
}
}
With this succinct definition you could now be able to implement the FieldDetail interface with a generic class or alternative specialized classes.
Then in the custom control you set a property as value or whatever, the <property-class> tag will be FieldManager and in the custom control you would know how everything plays out because the class FieldManager and the FieldDetail are the contract for you.
<xp:repeat disableOutputTag="true"
value="#{compositeData.value.fieldDetails}" var="fieldDetail">
<xp:link text="#{fieldDetail.name}">
<xp:eventHandler event="onclick" submit="true"
refreshMode="partial" refreshId="pnlContainer"
action="#{fieldDetail.action}">
</xp:eventHandler>
</xp:link>
</xp:repeat>
Or whatever your code might be. Anyway, that's the gist of it.

SmartGWT switch CSS class at runtime

I would like to know if and how it is possible working on SmartGWT to change the class associated to an element at runtime.
Take for example the underlying code that renders contents inside a div, I would like to know if and how I can modify at runtime the css class associated to the div.
HTMLFlow productInfo = new HTMLFlow(productInfoHtml);
productInfo.setStyleName("loginProductInfo");
productInfo.setHeight(13);
productInfo.setMargin(5);
Note: I'm using Smart GWT version 4.0
I have not used SmartGWT, but if HTMLFlow is a widget you can use GQuery for changing classes on fly, or css' rules.
Something like:
if (something) {
GQuery.$(productInfo).css("width", "70px");
else{
GQuery.$(productInfo).css("width", "30px");
}
About the css classes:
if (something) {
GQuery.$(loginProductInfo).removeClass("loginProductInfo");
} else {
GQuery.$(loginProductInfo).addClass("secondLoginProductInfoCss");
}
In fact, the solution is simpler than I had thought.
It is sufficient to keep a reference to the object of which you want to change the css class, then invoke again the method setStyleName.
Keep a reference to the widget (in our case productInfo) as a field of the original class, then change the css assignment when necessary.
So in the end the object productInfo becomes a field in the main class and then we can change the css assignment simply by invoking again the method setStyleName passing the new css class.
The object productInfo becomes a field in the main class
protected HTMLFlow productInfo = new HTMLFlow();
The code of the question example is modified as in the snippet
productInfo.setContents(productInfoHtml);
productInfo.setStyleName("login-product-info");
productInfo.setHeight(16);
productInfo.setWidth100();
Now I can change the css class assigned to the widget productInfo when the event onMouseOver occurs on the object forgot.
forgot.addMouseOverHandler(new MouseOverHandler() {
#Override
public void onMouseOver(MouseOverEvent event) {
productInfo.setStyleName("my-new-style");
}
});

how to refer to the property of bean used in BeanEditForm (tapestry5) in Java?

I've got in my .tml file something like this:
<t:beaneditform t:id="adForm" object="editableAd"
reorder="actiontype,shops,movies,streams,widgets" ....
My question is how to access (refer) actionType, which is an Enum (and in fact SELECT) in .java file? I just need to handle event when user changes the value of this select (dropdown), obviously before submitting the form itself.
If something like this would work for me...
#OnEvent(component = "adForm.actionType", value=EventConstants.VALUE_CHANGED)
public void actionTypeValueChanged(String value) {
log.info("value is: " + value);
}
To be updated with the changed value in a Select html component on the client side, have a tapestry select component in your template file with a t:zone attribute (i.e. in your case it could point to any dummy zone, this is only needed to be set correctly if you need to update a zone when a value is changed)
Also set the t:value attribute to your enum variable in your page\component java file, usually this variable will be annotated with tapestry's #Property.
Example:
<t:select t:id="myEnumVariable" t:zone="dummyZone" t:value="myEnumVariable"/>
myEnumVariable is used to refer to your class's variable AND to act as an ID (i.e. the actual string myEnumVariable is used as an id), this is not necessary, but it's more readable and maintainable that way)
public class MyClass{
#Property
private MyEnum myEnumVariable;
#OnEvent(component = "myEnumVariable", value=EventConstants.VALUE_CHANGED)
public void actionTypeValueChanged(**MyEnum** newValue) {
this.myEnumVariable = newValue; // <<<<<<
log.info("value is: " + myEnumVariable );
}
}
If you don't mind using the ChenilleKit framework for tapestry you could try using the
framework's OnEvent mixin.
You 'll find the example on the link I share but basically you add two attributes the select tag:
<t:select t:id="myselect" ... t:mixins="ck/OnEvent" t:event="change" />
then you add the event handler on your java class:
#OnEvent(component="myselect", value='change')
public void onChangeDoSomething(String value) {
hope that helps, by the way I think Muhammad's answer is equally correct (and doesn't requires the use of an extra framework).

Wicket AJAX + OnComponentTag

HI guys,
I wanted to add an AJAX Event to my Homepage, but it doesn't work! I figured out, that if I delete the onComponentTag function it works well. I have no clue why this happend, maybe you can help me!
Thats my Code:
final TextField<String> searchInput = new TextField<String>("searchInput", model) {
#Override
protected void onComponentTag(final ComponentTag tag) {
super.onComponentTag(tag);
tag.put("id", this.getId());
if (params.getString("search") != null) {
tag.put("value", params.getString("search"));
}
}
};
searchInput.add(new AjaxFormComponentUpdatingBehavior("onfocus") {
#Override
protected void onUpdate(final AjaxRequestTarget target) {
System.out.print("never saw that message :(");
searchInput.setDefaultModelObject("");
target.addComponent(searchInput);
}
});
Thx a lot for helping me!
CU
Firstly, you don't need to be overriding onComponentTag() at all. As seanizer states, if your really need to specify a markup ID yourself, use setMarkupId(id). You should understand why it is recommended that Wicket manages component IDs.
Secondly, the value attribute that you are adding is unnecessary - Wicket adds this automatically for this component. The value assigned is the value of the component's model object. See the source for TextField.onComponentTag().
Thirdly, again as seanizer states, components that are to be updated by ajax need to output their markup IDs - Wicket's ajax implementation uses the ID as the selector for the element. Additionally, all Wicket ajax behaviours that extend AbstractDefaultAjaxBehavior automatically set outputMarkupId(true) on the component they are bound to (see the source for AbstractDefaultAjaxBehavior.onBind()). This includes AjaxFormComponentUpdatingBehavior.
So:
String id = "searchInput";
final TextField<String> searchInput = new TextField<String>(id, model);
searchInput.setMarkupId(id);
searchInput.add(new AjaxFormComponentUpdatingBehavior("onfocus") {
#Override
protected void onUpdate(final AjaxRequestTarget target) {
System.out.print("never saw that message :(");
searchInput.setDefaultModelObject("");
target.setOutputMarkupId(true);
target.addComponent(searchInput);
}
});
Finally, I'd question what you're actually trying to achieve with this behaviour. I don't see any reason to round-trip this event to the server. Surely some client-side JS is more appropriate?
tag.put("id", this.getId());
is not the way to do it in wicket.
instead, use
component.setOutputMarkupId(true)
(either in your component constructor or in your behavior's bind() method) to make wicket write the id, and if you absolutely need to control what the id is (which is almost never the case) you can do
component.setMarkupId("myId")
also, you probably shouldn't assign the tag value yourself, use a model (model handling is extremely smart in wicket, read more about models). There are valid uses for onComponentTag, but they are way beyond what you are doing. Let wicket do what wicket does best and everything will be fine.
EDIT:
OK, some more clarification
have a look at the source code of AjaxFormComponentUpdatingBehavior, especially the part where the javascript event handler is generated.
protected final CharSequence getEventHandler()
{
return generateCallbackScript(
new AppendingStringBuffer("wicketAjaxPost('")
.append(getCallbackUrl(false)).append(
"', wicketSerialize(Wicket.$('"
+ getComponent().getMarkupId() + "'))"));
}
as you can see, wicket uses getMarkupId() to determine the actual id. The id you set using tag.put(id) is totally unknown to wicket and hence the behavior cannot work.
The standard thing to do is setOutputMarkupId(true). This is the only proper way to tell wicket to render the id (other than setOutputMarkupPlaceholder(true), which internally calls the former method). That way you make sure that the id wicket writes is the id wicket knows about. If this doesn't render the id, you are probably breaking some default behavior by overwriting onComponentTag.
Have a look at the source code of Component, especially at onComponentTag(), the method you are overriding:
protected void onComponentTag(final ComponentTag tag) {
// if(setOutputMarkupId(true) was set)
if (getFlag(FLAG_OUTPUT_MARKUP_ID)) {
// set id attribute
tag.put(MARKUP_ID_ATTR_NAME, getMarkupId());
}
}
[The comments are mine. BTW, this is the source of an ancient version, but I didn't find any current source online, and the functionality hasn't changed.]
Now if, as in your case, you want to set the component id manually, you must use
component.setMarkupId("myId")
and of course
setOutputMarkupId(true)
as well. If that doesn't work, go to the wicket JIRA site and file a bug. But I doubt it, this is standard functionality that works for thousands of users.

Categories

Resources