I'm developing a Wicket 1.5 web application with many different components, and I'm interested to let the user choose between different themes (that means change the CSS styles of some components). So in some way I'll associate the chosen theme with the user session.
My question is, which is the best way to do this in Wicket?
Right now my components look like this:
public class SingleLayout extends Panel {
public static final CssResourceReference CSS = new CssResourceReference(SingleLayout.class, "SingleLayout.css");
public SingleLayout(...) {
super(...);
}
protected CssResourceReference getCssResourceReference() {
return CSS;
}
#Override
public void renderHead(IHeaderResponse response) {
super.renderHead(response);
response.renderCSSReference(getCssResourceReference());
}
}
My ideal solution 'theme system' would:
The components will have a CSS that works by default if the CSS of this component is not defined in the current theme.
The components will also work in other applications without this theme system.
I have not done this myself, but I would recomend to have a look at the Session in Wicket. In the Javadoc, it explains the resource loading. Part of the search allgorithm is the Style, which is obtained from the users session.
Idea behind it, that you provide provide a css for each style (what you call a theme). The fallback to the standart theme isinluded.
Hope that helps.
Bert
Related
I'm using Magnolia 5.4 and have developed an app following the documentation:
https://documentation.magnolia-cms.com/display/DOCS54/Apps
The app is being rendered correctly in the magnolia shell.
Opening the app shows a «Hello World» message as described in the documentation:
https://documentation.magnolia-cms.com/display/DOCS54/Programming+an+app#Programminganapp-MainSubApp
I've removed the unnecessary code and ended up with this:
public class HelloWorldMainSubAppViewImpl implements HelloWorldMainSubAppView {
private VerticalLayout layout = new VerticalLayout();
private Listener listener;
public HelloWorldMainSubAppViewImpl() {
layout.setMargin(true);
layout.setSpacing(true);
layout.addComponent(new Label("Hello World!"));
}
#Override
public Component asVaadinComponent() {
return layout;
}
}
Instead of using the Label component I would like to use a FreeMarker template where I define a custom view.
Having read through the documentation I haven't figured out yet how to do this.
Here is the solution to my problem, based on the previous work.
This is the «EmbeddedPageSubApp» approach as described under «Custom App»
Create a regular page somewhere in your navigation.
Open the Configuration app, go to /modules/<APP_NAME>/apps/<APP_NAME>/subApps/main and add a url property to the mainSubApp with an absolute path to the previously created page.
Change value of the class property /modules/<APP_NAME>/apps/<APP_NAME>/subApps/main to info.magnolia.ui.framework.app.embedded.EmbeddedPageSubAppDescriptor
Change the value of the subAppClass property to info.magnolia.ui.framework.app.embedded.EmbeddedPageSubApp
If you don't want that page to be visible restrict its access within 'superuser' group / role so that only administrators can use it.
This binds that with an iframe. You should choose a blank template since the navigation elements of the embedded page are visible within the app.
I might be wrong here but to my knowledge Freemarker is only used to create templates and unfortunately limited to it. https://documentation.magnolia-cms.com/display/DOCS60/Template+scripts
On the other hand, What you want to do is to develop your custom app and here is an example of how to do that.
https://documentation.magnolia-cms.com/display/DOCS54/My+first+content+app
Also, if you are motivated to move to latest Magnolia version, you can define your custom app pretty easily using Content Types.
Hope that helps,
Cheers,
My application consists of many parts and they are defined in application's e4xmi file. I want to hide and show them dynamically. I am using EpartService to do so in handlers, where I can inject it.
But I also want to control the show/hide of parts with something like life cycle manager, where I can not inject EPartService. Is there any way to achieve and fully control RCP application's life cycle?
There seems the exact same question here and void of solution:
https://www.eclipse.org/forums/index.php/t/595958/
I want to implement 'remember me like feature' where part having sign in screen is shown instead of other parts. Also after log out same sign-in part is to be shown. So I need to control life cycle of RCP app. But I cant inject EPartService before anything in Application's e4xmi is initiated.
If you are creating a class from something which is injected (such as the LifeCycle class) you can create your class with injection using ContextInjectionFactory:
#Inject
IEclipseContext context;
MyClass myClass = ContextInjectionFactory.make(MyClass.class, context);
Or if you just pass an IEclipseContext to the class you can get the part service using:
EPartService partService = context.get(EPartService.class);
Note: There is a separate instance of the part service for each part. Depending on what you are doing you may need to make sure you have the service for the active part.
If you are not locked in to using SWT, you could use the e(fx)clipse e4 renderer for JavaFX instead.
e(fx)clipse has more possibilities to control the lifecycle of the application. For example you can return a Boolean from #PostContextCreate to signal whether you want to continue the startup or not. You will not be able to use EPartService here though, but you can roll your own login dialog using dependency injection as greg-449 has described it in his answer.
public class StartupHook {
#PostContextCreate
public Boolean startUp(IEclipseContext context) {
// show your login dialog
LoginManager loginManager = ContextInjectionFactory.make(LoginManager.class, context);
if(!loginManager.askUserToLogin()) {
return Boolean.FALSE;
}
return Boolean.TRUE;
}
}
(You can also restart the application. Form
more details see http://tomsondev.bestsolution.at/2014/11/03/efxclipse-1-1-new-features-api-to-restart-your-e4-app-on-startup/).
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.
I want to wrap a CanvasElement (<canvas> in HTML) in a Canvas widget.
Many widgets (e.g. Label) have a static method SomeWidget.wrap(Element) for wrapping an existing DOM element.
I imagine Canvas does not feature such a method because not all browser support and therefore the user should be forced to go through createIfSupported().
Unfortunately the constructor in Canvas is private (protected would work), which means that Canvas can not be subclassed. (There isn't any constructor available in the derived class.)
Code snippets of createIfSupported and the constructor in the Canvas class:
public static Canvas createIfSupported() {
// check if canvas is supported; if it is not supported: return null
return new Canvas(element);
}
private Canvas(CanvasElement element) {
setElement(element);
}
I ended up copying the Canvas class and making the constructor public.
Is there a better way to do this?
If not, what is the reasoning behind it (besides that <canvas> might not be supported)?
I am using GWT version 2.4.0.rc1.
Thanks,
Julian
This question is old, but there is a solution in newer versions of GWT:
Canvas.wrap(canvasElement);
See javadocs.
I don't know in which version of GWT it was added, but It works on 2.7.0.
I'm currently building a GWT login screen and I managed to get a basic version of the login structure working.
I created the following pieces:
An entry point class (actually it was given).
A main application screen composite.
A login-screen composite.
I have the following logic in my entry point method:
MyApplication mainWindow = null;
public void onModuleLoad() {
LoginScreen loginScreen = new LoginScreen() {
#Override
public String onLogin(String username, String password) {
boolean passwordWasOk = rpcCheckUsernamePassword(username,password); // mechanism not important for this question
if (passwordWasOk) {
RootPanel.get().remove(0);
mainWindow = new MyApplication();
// Using root layout panel as main window is a layout type composite
RootLayoutPanel.get().add(mainWindow);
return null;
} else {
return "password was incorrect";
}
}
};
RootPanel.get().add(loginScreen);
}
So, I created a method in the LoginScreen composite that is called when the user clicks the 'Sign-In' button. If the onLogin method fails its validation of the username and password, then a narrative can be returned to the login composite so that it can update the user. The login screen will stay on the screen until the user uses a correct username/password combination.
My question is, is this the correct way to use composites? Where should my login logic ideally reside. Is a better alternative to inject some sort of login handler object in the constructor of the composite or via a setter or is the method I used quite normal?
As I'm planning to write quite a lot of code, I want to get the coding style correct from the outset.
Any feedback is greatly appreciated.
Thanks,
For complex projects you'd want to use the Model-View-Presenter (MVP) design pattern. It allows you to separate the rendering logic (views) from the business logic. To get you started, the official documentation has two articles about it plus there's that presentation by Ray Ryan that started the whole GWT + MVP = <3 haze :) After that I'd recommend browsing through MVP related questions on SO and GWT's Google Group.