How to declare dependent style names with UiBinder

2019-01-13 15:59发布

问题:

I have a simple UiBinder widget containing a TextArea:

<!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:TextArea visibleLines="3" />
</ui:UiBinder>

I want to control the background color of this textarea for writeable and read only states. GWT uses the "-readonly" style name decorator to achieve this. So I try 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">

    <ui:style>
        .textBoxStyle {
            background-color:yellow;
        }
        .textBoxStyle-readonly {
            background-color:lightgray;
        }
    </ui:style>

    <g:TextArea styleName="{style.textBoxStyle}" visibleLines="3" />
</ui:UiBinder>

Obviously this won't work because style names are obfuscated for CssResources resulting in something like this:

.G1x26wpeN {
    background-color:yellow
 }
.G1x26wpeO {
    background-color: lightgray;
}

The result HTML for writeable textarea looks like this:

<textarea tabindex="0" class="G1x26wpeN" rows="3"/>

The read only textarea looks like this:

<textarea tabindex="0" class="G1x26wpeN G1x26wpeN-readonly" readonly="" rows="3"/>

How do I declare the style so GWT will obfuscate the primary part but not the "-readonly" decdorator?

I know that I can disable the obfuscation for the entire style name. But I'd like to keep the obfuscation while making use of the decorators.

回答1:

At this moment (GWT 2.4) it is not supported, and it's not clear if/when it will be supported, see issue 4746 in the GWT issue tracker.

The workaround is to add @external, which disables obfuscation for those styles. In this case that would be:

@external textBoxStyle, textBoxStyle-readonly;


回答2:

If you want to use this style for all your read-only TextAreas then I'd suggest just modifying the .gwt-TextArea-readonly style in your GWT theme CSS file.
Otherwise, I can only think of adding your custom style programmatically when you set the TextArea read-only.

PS: from the docs:

<set-configuration-property name="CssResource.obfuscationPrefix" value="empty" />` can be used for minimal-length selector names, but this is only recommended when the GWT module has total control over the page. 

I recommend using this (with "empty" or "X" or other unused prefix) for much shorter class names - because at default settings you don't gain that much through obfuscation (textBoxStyle - 12chars, G1x26wpeN - 9chars, X0 - 2 chars ;)).



回答3:

Why don't you try sth like this

public class MyFoo extends Widget {
  interface MyStyle extends CssResource {
    String normal();
    String readonly();
  }

  @UiField MyStyle style;

  /* ... */

  void setEnabled(boolean enabled) {
    getElement().addStyle(enabled ? style.normal() : style.readonly());
    getElement().removeStyle(enabled ? style.readonly() : style.normal());
  }
}

this would allow you change style if a text box is "normal" or readonly...

And off course, in the UiBinder you should have sth like

<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'>

  <ui:style type='com.my.app.MyFoo.MyStyle'>
    .redBox { background-color:pink; border: 1px solid red; }
    .normal { color:black; }
    .readonly { color:gray; }
  </ui:style>

  <div class='{style.redBox} {style.normal}'>I'm a red box widget.</div>

</ui:UiBinder>


回答4:

Try Now This One I Hope You will get it.
With the <ui:style> element, you can define the CSS for your UI right where you need it
Note: <ui:style> elements must be direct children of the root element

    <!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:TextArea visibleLines="3" />
    </ui:UiBinder>

<!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:style field='MyStyle'>
        .textBoxStyle {
            background-color:yellow;
        }
        .textBoxStyle-readonly {
            background-color:lightgray;
        }
    </ui:style>

    <g:TextArea name="myText" styleName="{MyStyle.textBoxStyle}" visibleLines="3" />
</ui:UiBinder>


回答5:

Isn't there a typo in your UIBinder?

You have:

    <g:TextArea styleName="{style.textBoxStyle}" visibleLines="3" />

.. but I think you need to be using "stylePrimaryName", ie.

    <g:TextArea stylePrimaryName="{style.textBoxStyle}" visibleLines="3" />

But I guess this question has been answered really already..



回答6:

Here's something valuable I figured out by putting together info from other posts in this thread especially...

If you use @external, you can override gwt styles. The problem is that is this change gets applied globally! It is possible, however, to extend & override select attributes without effecting every instance of a widget type. (This like the programmatic styling method of creating a css class with a gwt class name + a suffix and using addStyleDependantName().)

Here is an example of using UIBinder + a CssResource to extend a gwt style. I left out the CssResource part, but you'll get the idea...

In your xxxx.ui.xml file, expose the gwt style, but don't mess with it!

<ui:style>
    @external .gwt-Button; .gwt-Button {}
</ui:style>

Then, style a widget it by specifying 2 (or more) styles in the styleName attribute. I.e. the gwt style, and the one (or more) from your resource.

<g:Button ui:field="submitButton_" text="Submit" styleName="{style.gwt-Button} {res.loginStyles.submitButtonStyle}" />

Here's the css class:

.submitButtonStyle{
   margin: 3px 5px 5px 0px;
}

In this case, I defined a button that is styled in the standard method (easily changed via module inheritance) but with a specific margin that will remain fixed. This didn't mess up the global style, it didn't require defining all the attributes manually, and allowed for swapping the global styling at will with clean.css, dark.css, etc.