ClientBundle use case issues

130 views
Skip to first unread message

Vitrums

unread,
Nov 23, 2011, 4:01:41 PM11/23/11
to google-we...@googlegroups.com
Let's say I've inherited "clean" theme

<inherits name='com.google.gwt.user.theme.clean.Clean'/>
 
and further I made a decision to improve a bandwidth aspect of my project, so I need to obtain a workaround to use solely chosen styles derived manually from the com/google/gwt/user/theme/clean/clean.css. In a simplified approach the easiest sufficient way would have been something like allocating the style scraps right inside my own project's stylesheets, i.e. to append them to com/myorg/myproject.css. But according to this article: Bandwidth Sensitive Applications it's also common to add the following into your project configuration file myproject.gwt.css:

<inherits name='com.google.gwt.user.theme.clean.CleanResources'/>
 
for resources autogeneration purposes. Once I managed to obtain some sort of stable scratch prototype of myClean.css, it would be fair to assume that on compilation I will not have to accomplish any manual copy/past routine like one as allocating myClean.css under <webapplication-directory>/war/myproject/gwt/clean/ folder, since it's where images/ directory containing all the clean theme resources lives. But both ways whether to add an <inherits ... directive at the project config file, or injecting myClean.css via the <link ... tag inside my host page, will not save me from necessity of making those manual actions.

One very different approach is to use ClientBundle facility. I couldn't figure out how to inject more or less big scraps of myClean.css unless I declare the corresponding resources accessor as @CssRerourses.NotStrict. Hence my code would have looked like following:

interface MyCleanResources extends ClientBundle {
MyCleanResources INSTANCE =  GWT.create(MyCleanResources.class);
@CssResource.ImportedWithPrefix("do-not-want-any-prefix")
interface Styles extends CssResource {
/* Definition of some strict class */
String foo();

@ClassName("gwt-MenuItem")
String gwtMenuItem();
}
@Source("css/myClean.css")
@CssResource.NotStrict
Styles css();
}

Suppose I've also got some rules into myClean.css:
.foo { }
 
/**
 * Copyright 2008 Google Inc.
 */
.gwt-MenuBar .gwt-MenuItem {
  cursor: default;
  font-family: Arial Unicode MS, Arial, sans-serif;
}

Here I can do a bunch of things:
1) Inject resources:

MyCleanResources.INSTANCE.css().ensureInjected();

and then write something like:

navigationBlock.addStyleName(MyCleanResources.INSTANCE.css().foo());
menuItem123.addStyleName(MyCleanResources.INSTANCE.css().gwtMenuItem()); 

but not the following:

navigationBlock.addStyleName(MyCleanResources.INSTANCE.css().gwtMenuBar());

since it's not strictly declared in Styles interface

2) Import:

java:
interface MyprojectResources extends ClientBundle {
MyprojectResources INSTANCE =  GWT.create(MyprojectResources.class);
interface Styles extends CssResource {
/* Definition of some strict MyprojectResources.Styles class */
@ClassName("foo")
String foo();
}
@Source("css/myproject.css")
@Import({MyCleanResources.Styles.class})
Styles css();
}

myproject.css:
.foo .do-not-want-any-prefix-gwtMenuItem {
 font-family: Verdana;
}

and use

navigationBlock.addStyleName(MyprojectResources.INSTANCE.css().foo());

but not the following:

navigationBlock.addStyleName(MyprojectResources.INSTANCE.css().gwtMenuItem());

Hence, there're few issues I'm not capable to deal with:
1) In a case of import how can I get gwtMenuItem class at the runtime any other way then hardcoding it as a string literal? I really wan't to get strict obfuscated classes throughout my project as much as possible.

2) If I inject myClean.css, all the resources (like background style's url) will be assigned to the webapplication root directory, e.g.:

localhost:8888/myproject/war/images instead of localhost:8888/myproject/war/myproject/gwt/clean/images

which is not what I need. How can anyone deal with this paths issue, when he injects an external stylesheet in a manner I've shown here.

3) I really can't get it, why would anyone want to enumerate .css files into @Source annotation (unless we need to decrease a number of browser http round-trip requests, i guess). Though isn't it more accurate to associate any CssResource accessor with only one appropriate single source every time we need to include some additional stylesheet? Therefore they'll be injected at the runtime by a measure of user's actions progress.

Please help me out providing some examples of ClientBundle advanced commonplace usage, because I think I'm greatly confused.

p.s. I don't use UIBinder facility. Please, leave this scope unmentioned in your replies.

Vitrums

unread,
Nov 24, 2011, 6:24:42 PM11/24/11
to google-we...@googlegroups.com
Hence, found only one solution by my own means:

I. Have different stylesheet files logically separated.

tables.css:
.old-fashion-table { }
 
lists.css:
.lovely-list { }

II. For each stylesheet define one CssResource descendant interface with predefined @ImportedWithPrefix annotation.

@ImportedWithPrefix("tables")
interface TablesStyles extends CssResource {
    @ClassName("old-fashion-table")
    String oldFashionTable();
}
 
@ImportedWithPrefix("lists")
interface ListsStyles extends CssResource {
    @ClassName("lovely-list")
    String lovelyList();
}

III. For each MyStyles interface define a strict accessor

@Source("tables.css")
TablesStyles tablesCss();
 
@Source("lists.css")
ListsStyles listsCss();

IV. When you need to refer to some class from tables.css or from lists.css from inside your other.css, just import MyStyles and refer to classes within them using appropriate prefixes 

other.css:
.some-wierd-widget .tables-old-fashion-table { }
.some-wierd-widget .lists-lovely-list { }

java:
@ImportedWithPrefix("other")
interface OtherStyles extends CssResource {
    @ClassName("some-wierd-widget")
    String someWierdWidget();
}

@Source("other.css")
@Import({TablesStyles.class, ListsStyles.class})
OtherStyles otherCss();

V. Run-time. Inject all the accessors and refer to imported classes by an according base class accessor

MyResources.INSTANCE = GWT.create(MyResources.class);
 
MyResources.INSTANCE.tablesCss().ensureInjected();
MyResources.INSTANCE.listsCss().ensureInjected();
MyResources.INSTANCE.otherCss().ensureInjected();
...
myLovelyWidget.addStyleName(MyResources.INSTANCE.otherCss().someWierdWidget());
descendantOfMyLovelyWidget.addStyleName(MyResources.INSTANCE.tablesCss().oldFashionTable());
descendantOfMyLovelyWidget.addStyleName(MyResources.INSTANCE.listsCss().lovelyList());

It's just my vision of how it works. Correct me if I'm misspaterning or do some even more crazy stuff =\
Reply all
Reply to author
Forward
0 new messages