Allow different GWT visual themes for different users - gwt
My question is this: how do you allow a different GWT visual theme depending on the user that logs in?
I would like to decide which theme to use when the customer logs in (that is before the GWT app gets loaded, so I am pretty sure it should be possible).
I have attempted to use class replacement based on a custom-property, but that failed because only the last inherited module's set of images become visible, even though I can select the right css file... I have searched everywhere and can't find the answer!
Thank you for your suggestion Thomas, but the problem with this solution is that you're assuming the CSS stylesheet is available for me to add to a ClientBundle (I tried that but unless you copy the css file and accompanying pics to your project, you can't do that). The themes come from external GWT modules. And I would like to keep it this way for modularity (it would be painful to import a whole bunch of resources into my project every time we needed a new theme).
The work-around I came up with was to write the injection code myself (just inject a link tag in the HTML head) at run-time.
For completeness, here's the code to do it:
protected void doInjection(String cssFilePath) {
// <link type="text/css" rel="stylesheet" href="sol.css">
Element headEl = Document.get().getElementsByTagName("head").getItem(0);
HeadElement head = HeadElement.as(headEl);
LinkElement link = Document.get().createLinkElement();
link.setType("text/css");
link.setRel("stylesheet");
link.setHref(GWT.getModuleBaseURL() + cssFilePath);
head.appendChild(link);
}
And you call this method with something like this:
doInjection("gwt/standard/standard.css");
Then, inherit all Resources modules from your project's GWT module file. For example:
<inherits name='com.google.gwt.user.theme.standard.StandardResources'/>
<inherits name='com.google.gwt.user.theme.dark.DarkResources'/>
Inheriting the *Resources version of the Module avoids automatically injecting the style-sheet.
To decide which theme to use, I created a custom GWT property in the module file, based on the value of this property, I replace a default Java class (which would just insert the default theme) with a different Java class (which subclasses the default class) if a different theme should be used. This has the added bonus that I can include my own ResourceBundle resources within each theme, because the replacement Java class used with a theme, besides injecting the right css file, can also provide alternative Resources to my GWT code.
EDIT
I would like to add one important note:
The solution described above works quite well. But if your app uses different Locales or other GWT properties, this approach may cause the number of compilation permutations to explode! With only 6 different themes and 3 different Locales, on top of the standard 6 different browser versions you normally have, the GWT compiler will create 6 x 3 x 6 = 108 different compilations!! This is pretty crazy!!
A better solution, which I decided to follow after all, is to set an attribute into the HttpSession once the user logs in, and then based on the value of this attribute, load the appropriate css file (first thing in the onModuleLoad() of my entry-point class). The only difference from the solution described above is on how you select the theme.
I use a different approach, which mostly relies on the power of CSS with a single line of GWT code to switch themes.
First, define the themes that you want to apply. I use an enum.
public enum Theme {
DARK,
BRIGHT;
}
public static String getDefault() {
return BRIGHT.name();
}
Now, when you launch an app, apply a default theme (Theme.getDefault()). When a user selects a different theme, apply it:
public static void setTheme(String theme) {
/*
* Setting style on Body element allows us to "theme" the RootPanel as well.
*/
Document.get().getBody().setClassName(theme);
}
When you apply a new theme, the look of your app will instantly change without reloading the page.
Finally, define all theme elements that you need in your CSS file:
.DARK {background: #000; color: #CCC}
.BRIGHT {background: #ebebeb; color: #000}
.gwt-DialogBox {border-radius: 6px}
.DARK .gwt-DialogBox {border: 3px solid #555}
.BRIGHT .gwt-DialogBox {border: 3px solid #CCC}
Notice that you only add a theme selector in front of rules that are different for different themes.
I would try the following general approach:
Define one CSS file for each of the visual themes.
Put them all in a ClientBundle as described here.
Hold off injecting the themed CSS until you've authenticated the user. You can inject the general CSS you need for displaying the login screen.
Then inject the themed CSS depending on the user using the CssResource's ensureInjected() method.
Related
Can't use css in codename one
Css error in codename one i'm having issues with the css and when i run the simulator the css is not working.
The # selector type isn't supported in Codename One. You need to apply CSS explicitly to UIIDs. The CSS selectors in general for Codename One are far simpler than the full CSS see https://www.codenameone.com/manual/css.html Just write the UIID of the component you want to style without the # character e.g. Button { color: pink; }
Liferay 7 Themes and AUI
I am having an issue with Liferay 7 Themes and AUI. First, it is my understanding each Liferay page is divided into sections, as defined here: - https://dev.liferay.com/es/develop/tutorials/-/knowledge_base/6-2/setting-up-custom-css And I must wrap any custom css with the appropriate wrapper, as defined in the above link. Any css defined in the theme applies to the appropriate section of the page, for all pages in the web application. I can also create custom wrappers within the theme, which individual portlets may reference using the 'com.liferay.portlet.css-class-wrapper' annotation. I can therefore change the AUI Button's appearance by creating a css class and referring to it as follows: < aui:button cssClass="btn-lg".../> But it is less clear to me how I can apply custom css to AUI Data tables. Guidance is certainly appreciated.
You can use theme contributors. And there create a .scss file and put customized styles for datatable there like : .yui3-datatable{ & thead{ backgournd-color: red; } }
You can also use 'your-theme/css/custom.csss' to override default style with your custom styles.
not able to register two plugins of touch-ui rte dialog
I am using the steps given in the URL to make a color-picker rte plugin http://experience-aem.blogspot.in/2015/01/aem-6-sp1-touchui-richtext-editor-color-picker-plugin.html and at the same time I am making another custom rte plugin to do some text modulation. But only one of them is working using rte.coralui2 as categories. and both icons are coming at the same location. If I disable one js then another is working. I have registered the plugin with different name and I have also used different variables. I am not able to make the rte plugin button at different location. Please suggest the possible solution.
it's possible you are overlaying rather than extending the rte.coralui2 category. I suspect your custom clientLibs are competing with each other and only one is available.
It seems like you are using the same steps provided in the blogpost for creating both the plugins and while doing that, you are using the below code twice with different icons : if(items.indexOf(ExperienceAEM.TCP_UI_SETTING) == -1){ items.splice(3, 0, ExperienceAEM.TCP_UI_SETTING); } So, maybe, the icons are being added at the same place and only one of them is shown. You should create ExperienceAEM.CuiToolbarBuilder Class only once and add both icons inside that class
gwtbootstrap always applies to all elements
I want to use GWT bootstrap for my application, so I added the jar to the classpath and inherited it in app.gwt.xml and it is working so far (I am new to Bootstrap). So far I haven't used UIBinders for the layout and if in any way possible would like to leave it that way as I have a very dynamic UI which is generated programmatically and I have little experience with UIBinders. However for the elements that I want to use from gwtbootstrap I have created UIBinders (such as headings and buttons). The problem is that not only the elements I create with UIBinders using the gwtbootstrap elements look like gwtbootstrap elements, but all elements on the page. A simple example: it makes no difference whatsoever if I create a Heading like this using a bootstrap element <b:Heading size="2">Hello GWT Bootstrap</b:Heading> or like this using standard HTML <h1>Hello GWT Bootstrap</h1> both look like a GWT Bootstrap heading. The same applies for all other elements, so any element on the page is styled by gwtbootstrap, even if I don't want it to and I can't find a way to control this.
That's because gwt-bootstrap injects the bootstrap.css into your GWT app and bootstrap.css defines default styles for standard HTML elements like <h1>, etc. If you don't want bootstrap to override the default styles there are several solutions: Modify the bootstrap.css in the gwt-bootstrap library file and remove the styles that you don't want Create a separate css file that sets the styles for the specific HTML elements back (using !important) Extends gwt-bootstraps CssResources and pass a custom css file. Solution 3 is probably the cleanest one.
How to prevent GWT onload flicker in the Web Application Starter Project?
I'm new to GWT, and I'm sure this is answered in SO somewhere but I've yet to find I downloaded the GWT 2.0 eclipse plugin, and was pleased to see it comes with a starter project. However, I was surprised that when running it, there is an unpleasent flickering... The text loads without the CSS first It takes a while untill the select box apears (If you don't see the flicker, try and press F5 to refresh) All mature GWT apps seem to have a loader before that but I didn't find an easy, standard way to add it. It seems this app loads in this order: (correct me please if I mixed it up, its only my guess) Basic layout HTML, All JavaScript, and CSS Runs the logic on the "onload" event (soonest time your compiled javaScript can start - ?) So I can't programmatically add a loading spinner before GWT was loaded, a bit of a catch 22 for me Am I missing something basic? is there a best practice way to add that initial spinner? I was thinking simply adding a div with an animated gif, and in the onload event - hide it. But I'm sure there is something better. Let me know if this is a duplicate question Update: found this related question, not answering mine though...
I've handled this problem before by not using the GWT module to load CSS, but loading it directly in the tag itself. If you do this, the browser will always load the CSS first, even before the GWT JS is loaded. This means you'll lose a bit of flexibility and speed, but its the only workaround I've used so far. EDIT: Extra info cause I want the bounty :D If you do not remove the <inherits name='com.google.gwt.user.theme.standard.Standard'/> from your module.gwt.xml file, then the GWT standard theme is loaded in the JS file that GWT creates. This JS file loads after the HTML page renders, and injects the CSS after load. Hence the flicker. To avoid the flicker, you can comment out that line and insert your own stylesheet into the <head> of your HTML file. This ensures your CSS loads before the HTML renders, avoiding any flicker. If you really want the GWT theme, you get it out of the source code. To use a spinner with GWT is quite easy. One simple way would be to keep it in a div with an id in the HTML file itself. Then, in the onModuleLoad(), simply hide that div by calling RootPanel.get("spinner").setVisible(false); That should show the spinner till GWT loads itself.
Here's what we do to implement a spinner. You put something like the following HTML just below the script line that loads your application (ie. the one with nocache.js). e.g.: <div id="loading"> <div id="loading-msg"> <img src="icons/loading-page.gif" lt="loading"> <span>Loading the application, please wait...</span> </div> </div> Then in your application EntryPoint you reach into the page using the DOM and remove that div. e.g. final RootPanel loading = RootPanel.get("loading"); if (loading != null) { DOM.removeChild(RootPanel.getBodyElement(), loading.getElement()); }
Ehrann: I'm afraid the practice mentioned in the above answers is the only way for now. GWT doesn't provide similar features to show/hide a "loading" frame "on the fly". I guess one of the reason is that this requirement is not so "common" for all GWT users, one person might want a very different style of the "loading" than others. So you have to do that by yourself. You can have a look at the GXT showcase page (based on GWT too): http://www.extjs.com/explorer/ for how they do that. For the source of it, download Ext GWT 2.1.0 SDK here: http://www.extjs.com/products/gxt/download.php and check the samples/explorer folder after extracting it. For details see the edit below: EDIT Check the source code for http://www.extjs.com/examples/explorer.html and you can see a div with id "loading". For each samples (extending Viewport), GXT.hideLoadingPanel(loadingPanelId) is called in onAttach() (the initialization), which hides the loading frame. Check source code of Viewport here Check source code of GXT.hideLoadingPanel here You can do it in a similar way.
You could put an HTML loading message in the host page (use style attributes or embed the style tag in the header to make sure that it's styled), and remove the message once your modules has loaded, e. g. Document.get().getBody() with .setInnerHTML("") or .removeChild(), and then present your application programmatically however you want.