Discussion:
value function in GSS and math formulas
vitrums
2018-05-06 06:05:17 UTC
Permalink
I've been struggling forever with a simple task of using size properties of
an image as a constant in my ClientBundle managed .css file. Every time I
have to calculate an offset based on some image width or height, I'm forced
to involve ugly *@eval*. And with GSS things haven't become easier. My hope
is that it was just me being blind in a search for a decent TOC of either
GSS or full syntax of first generation CssResource-style .css files.

Here's a snippet:

@def POPUP_LOGGER_TOP_TAILS_HEIGHT value('popupLoggerTopTails.getHeight',
'px');
@def POPUP_LOGGER_RED_BUTTON_HEIGHT value('popupLoggerRedButton.getHeight',
'px');
@def TOP_PANEL_BUTTON_AREA_MARGIN_TOP divide(add(
POPUP_LOGGER_TOP_TAILS_HEIGHT, POPUP_LOGGER_RED_BUTTON_HEIGHT), 2);

I get this error: popup-logger.gss[line: 54 column: 42]: Size must be a
CssNumericNode with a unit or 0; was: popupLoggerTopTails().getHeight() +
"px"

Obviously I'm using *value* wrong. Here's an excerpt from CssResource.java:

- value("bundleFunction.someFunction[.other[...]]" [, "suffix"])
substitute the value of a sequence of named zero-arg function invocations.
An optional suffix will be appended to the return value of the function.
The first name is resolved relative to the bundle interface passed to
com.google.gwt.core.client.GWT.create(Class)
<eclipse-javadoc:%E2%98%82=vit-gwt-core-client/C:%5C/Users%5C/vitru%5C/.m2%5C/repository%5C/com%5C/google%5C/gwt%5C/gwt-user%5C/2.8.2%5C/gwt-user-2.8.2.jar%3Ccom.google.gwt.resources.client(CssResource.class%E2%98%83CssResource%E2%98%82com.google.gwt.core.client.GWT%E2%98%82create%E2%98%82Class>.
An example:

.bordersTheSizeOfAnImage {
border-left: value('leftBorderImageResource.getWidth', 'px') solid blue;
}


Now when it comes to GSS and the math functions:

Each of these functions can take a variable number arguments. Arguments may
be purely numeric or CSS sizes with units (though mult() and divide() only
allow the first argument to have a unit).

So technically this divide(add("15px", "10px"), 2) should work.

But instead of "15px" I get this this: *popupLoggerTopTails().getHeight() +
"px". *Looks like a waste of opportunity. Completely unusable and
counterintuitive design. It's not a *value* function. It's a *string
concatenation* function. To become a *value* function it has to be already
evaluated to "15px" at this point.

But I'm sure it's just yet another time when I got confused due to a lack
of accessible use case examples. This code snippet
at http://www.gwtproject.org:

@def SPRITE_WIDTH value('imageResource.getWidth', 'px') .selector { width:
SPRITE_WIDTH; }

is literally the best example we ever had, which ironically contains a
missing ";" after ")" syntax error.
--
You received this message because you are subscribed to the Google Groups "GWT Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit+***@googlegroups.com.
To post to this group, send email to google-web-***@googlegroups.com.
Visit this group at https://groups.google.com/group/google-web-toolkit.
For more options, visit https://groups.google.com/d/optout.
vitrums
2018-05-07 02:14:31 UTC
Permalink
I can't get my mind around the fact that *value* function and *eval* are
always runtime substitutions for *ImageResource*, when it's clearly said in
http://www.gwtproject.org/doc/latest/DevGuideClientBundle.html for *@eval*

-

If the user-defined function can be statically evaluated by the
compiler, then the implementation of the specific CssResource should
collapse to just a string literal.

One of the major optimizations provided by ClientBundle is an image bundle
generation, and it's done at compile time. Also any ClientBundle is a
subject of GWT.create(...) call. My point is that there's no runtime
information required here. And yet for

@def MY_CONSTANT 5px;
@def TOP_PANEL_BUTTON_AREA_MARGIN_TOP eval(
"net.vit.gwt.dev.ui.popuplogger.client.PopupLoggerImpl.evalTopPanelButtonAreaMarginTop()"
);

I get only

Java expression : net.vit.gwt.dev.ui.popuplogger.client.PopupLoggerImpl.
evalTopPanelButtonAreaMarginTop()

I'm not sure at which point the call to *evalTopPanelButtonAreaMarginTop()* is
done and why so late. But it precludes from mixing *value* or *eval* in GSS
formulas. Therefore I have to either rely on CSS3 *calc()* funcion, or do
everything in static methods like *evalTopPanelButtonAreaMarginTop()*.

-----------------------------------------------------------------------------

So the task is still the same: *derive an offset, based on the information
about image(s) size and other ready-to-use constants when
CssResource.ensureInjected() is called. *

Let's say I need to declare a class *.inner* in *my.gss*, for which
*margin-top:* property would be equal to *(<height of image A> - <**height **of
image B>)/2 + constant*. I declare a static method:

*lib.MyWidgetImpl.java:*
public static String evalMarginTop() {
int val = (*resource*.imageA().getHeight() - *resource*.imageB().getHeight
()) / 2 + *css*.myConstant();
return val + "px";
}

Now where do I get *resource* and *css *from? Well, I believe I'm forced to
statically inject them. I didn't manage to find a better solution for my
GIN controlled client lib. These are the miniumum requirements:

*lib.MyWidgetImpl.java:*
@Inject static MyWidgetResources resources;
@Inject static MyWidgetCss css;

*lib/myWidget.gss*:
@def MY_CONSTANT 5px;
@def MARGIN_TOP eval("lib.MyWidgetImpl.evalMarginTop()");

.inner {
margin-top: MARGIN_TOP;
}

*lib.MyWidgetCss.java:*
@ImportedWithPrefix("myWidget")
public interface MyWidgetCss extends CssResource, SharedCss {
String DEFAULT_PATH = "lib/my.gss";
...
int myConstant();
}

*lib.MyWidgetResource.java:*
public interface MyWidgetResources extends ClientBundle {
@Source("lib/imageA.png")
ImageResource imageA();

@Source("lib/imageB.png")
ImageResource imageB();

@Source({MyWidgetCss.DEFAULT_PATH, SharedCss.DEFAULT_PATH});
MyWidgetCss myWidgetCss();
}

*Application:*

*blah.AppResource.java:*
public interface AppResource extends ClientBundle, MyWidgetResource,...other
bundles {
...
}

*blah.AppModule.java:*
@Override
protected void configure() {
bind(MyWidgetResource.class).to(AppResource.class).in(Singleton.class);
requestStaticInjection(MyWidgetImpl.class);
}

@Provides
@Singleton
public MyWidgetCss getMyWidgetCss(MyWidgetResource resources) {
return resources.MyWidgetCss();
}

I don't want to statically inject resources and request static injection
for each and every ui class in my application, for which I have a GSS file
with runtime evaluation. I want to inject resources in constructor. Why
does it have to be so ugly in order to make my GIN controlled client lib
work?
--
You received this message because you are subscribed to the Google Groups "GWT Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit+***@googlegroups.com.
To post to this group, send email to google-web-***@googlegroups.com.
Visit this group at https://groups.google.com/group/google-web-toolkit.
For more options, visit https://groups.google.com/d/optout.
Loading...