With the API of the Application User Interface web application, you can fully customize the content of the application; you add new components as well as modify or remove the existing ones.
The API allows you to extend applications classes and override their methods so you can keep what is already provided or implement the classes anew.
It is exposed in the <YOUR_APP>.core and <YOUR_APP>.connectors package of the <YOUR_APP>-vaadin project:
AppLspsUI
class in the core package. It represents the root component of the application.The AppLspsUI class holds the root component of the gui and provides functions required by the entire application, including ThemeManager and Navigator. Its init() method creates the content root layout and the connector between LSPS forms and your application, called the AppConnector, and calls the initLayout() method which assembles the screen content.
Generally, it is not recommended to reimplement the AppLspsUi from scratch since the class is responsible for connection to the LSPS Server, authentication and other basic functionalities. You will rather override its methods so it uses your customized resources, such as a custom navigator.
If you still decide to implement LspsUI anew, make sure it meets the following requirements:
@Widgetset
("com.whitestein.lsps.vaadin.widgets.WidgetSet")
public class LspsUI extends UI implements ErrorHandler { ...
login.jsp
and in the WEB-INF/web.xml
of the webapp project.AppAppLayout is responsible for the menu and other components that are always visible.
Note: If you are reimplementing the AppLayout, your implementation must
- implement com.whitestein.lsps.human.app.ui.AppLayout and
- extend a vaadin Component.
You can extend this class to add a new component to it, such as a footer or header: modify the AppAppLayout class:
com.vaadin.ui.CssLayout.addComponent()
method to add your component. private Component header;
@Override
public void attach() {
super.attach();
if (header == null) {
header = new AppHeader();
addComponent(header, 0);
}
}
Implement the component: consider adding a style class to the component with the addStyleName()
call so you can add the style to scss.
Example header implementation
public class AppHeader extends CustomComponent {
public AppHeader() {
//csslayout renders as a div:
CssLayout hl = new CssLayout();
setCompositionRoot(hl);
hl.addComponent(new Label("My Company"));
hl.addComponent(new Label("My Company Address"));
hl.addComponent(getLogo());
//add style to header:
addStyleName("my-custom-header");
}
protected Image getLogo() {
String basepath = VaadinService.getCurrent()
.getBaseDirectory().getAbsolutePath();
//Image as a file resource
FileResource resource = new FileResource(new File(basepath +
"/WEB-INF/images/lsps_logo.png"));
//Show the image in the application
Image image = new Image("Image from file", resource);
return image;
}
}
A View is used as the content of the AppLayout, which is different for different URLs: this is the mechanism used to display To-Dos, Documents, and Run Model content. To create a custom view, you need to create a class with the GUI and register the URL of the view with the navigator.
Important: Before you create a custom view, consider using Documents: with documents and only adding a link to the document to the navigation menu using the addDocumentsMenuItem() call. Like this, your page is delivered with your model, not as part of the application, and created with a graphical form editor.
To create a new view and register its URL with the navigator, do the following:
public class MyAppView extends DefaultAppView { public MyAppView() { AppInjector.injector.inject(this); layout = new VerticalLayout(); layout.setSpacing(false); layout.setMargin(false); layout.setSizeFull(); layout.addComponent(new Label("Hello")); setCompositionRoot(layout); setSizeFull(); title = new Label("My View"); } } }
@Override
protected void createNavigator(ViewDisplay display) {
//create navigator with your custom navigator:
Navigator navigator = new AppAppNavigator(getUI(), display);
navigator.addViewChangeListener(new PageTitleFromAppView());
}
@Override
public AppAppNavigator getNavigator() {
return (AppAppNavigator) super.getNavigator();
}
public String myViewId() { return "myview"; }
protected Class<? extends AppView> myAppViewClass() { return MyAppView.class; }
@Override
protected void addAllViews() {
super.addAllViews();
addView(myViewId(), myAppViewClass());
}
This is also the way how the create a custom Welcome page, which is displayed when you click the logo with the difference that you need to override the openHomePage method:
@Override
public void openHomePage() {
navigateTo(getNavigator().myViewId());
// navigateTo(getNavigator().todoListViewId());
}
To add or remove items in the navigation menu, do the following:
@Override
protected Component createMainMenu() {
return new AppMainMenu(CONTENT_AREA_ID);
}
AppMainMenu
.closeOnTapAreaId
parameter that calls the DefaultMainMenu constructor. public AppMainMenu(String closeOnTapAreaId) { super(closeOnTapAreaId); }
private AppNavigator getNavigator() { LspsUI ui = (LspsUI) UI.getCurrent(); return ui.getNavigator(); }
if
statement with the respective navigation menu item.private void addMyViewMenuItem(NavigationMenu navigationMenu) { navigationMenu.addViewMenuItem("nav.myview", getNavigator().myViewId(), VaadinIcons.LIST, null); } //you need to add a getter for a Navigator: //here we use a custom AppNavigator to get the View id: private AppAppNavigator getNavigator() { LspsUI ui = (LspsUI) UI.getCurrent(); return (AppAppNavigator) ui.getNavigator(); }
addMyViewMenuItem(navigationMenu);When adding items, consider whether the user permissions need to be taken into account: if this is required, use the respective methods, such as:
hasRight()
hasRightToOpenDocument()
(false if user has no right to access given document as defined by the document access expression)Example custom MainMenu implementation
public class AppMainMenu extends DefaultMainMenu { public AppMainMenu(String closeOnTapAreaId) { super(closeOnTapAreaId); } @Override @SuppressWarnings("unused") protected NavigationMenu createMenu() { NavigationMenu navigationMenu = new NavigationMenu(new UserMenu()); LspsUI ui = (LspsUI) UI.getCurrent(); UserInfo user = ui.getUser(); //removing To-Do List: /*if (user.hasRight(HumanRights.READ_ALL_TODO) || user.hasRight(HumanRights.READ_OWN_TODO)) { addTodoListMenuItem(navigationMenu); }*/ if (user.hasRight(HumanRights.ACCESS_DOCUMENTS)) { addDocumentsMenuItem(navigationMenu); } if (user.hasRight(EngineRights.READ_MODEL) && user.hasRight(EngineRights.CREATE_MODEL_INSTANCE)) { addRunModelMenuItem(navigationMenu); } //adding custom navigation item: if (user.hasRight(EngineRights.READ_MODEL) && user.hasRight(EngineRights.CREATE_MODEL_INSTANCE)) { addMyMenuItem(navigationMenu); } if (hasRightToOpenDocument("custom_todo_list_ui::todoItemsList")) { navigationMenu.addDocumentItem("nav.mytodoitems", "custom_todo_list_ui::todoItemsList", null, VaadinIcons.ABACUS, null, null); } //link to custom view: addMyViewMenuItem(navigationMenu); return navigationMenu; } private void addMyMenuItem(NavigationMenu navigationMenu) { navigationMenu.addViewMenuItem("nav.myview", getNavigator().myViewId(), VaadinIcons.LIST, null); } private AppNavigator getNavigator() { LspsUI ui = (LspsUI) UI.getCurrent(); return ui.getNavigator(); } }
To set the page which is loaded after the user has logged in, modify the openHomePage()
method of your LspsUI class, by default the AppLspsUI class:
public void openHomePage() { navigateTo(<VIEW>.ID); // for example: navigateTo(getNavigator().documentsViewId()); }
public void openHomePage() { openDocument("<FULLY_QUALIFIED_DOCUMENT_NAME>", null); //for example: openDocument("module::docMainScreen", null); }
To change the logo of the area where you enter your credentials, proceed as follows:
... var storage = window.localStorage; var theme = "my-theme";
&.login-page form table
.Example login customization
@mixin _login {
&.login-page {
background-color: white;
background-image: url("../img/logo_splash.png");
background-position: center bottom;
background-repeat: no-repeat;
background-size: 300px auto;
}
&.login-page #loginHeader {
background: none !important;
}
&.login-page #username {
background: yellow !important;
}
&.login-page #password {
background: blue !important;
}
&.login-page .loginform table {
background: none;
}
&.login-page .login-button {
background: red;
margin-right: 47px;
color: grey;
}
}
The information for the dialog is pulled from the app-version.properties file which is bound to the maven build properties.
Note: On SDK Embedded Server the properties are not resolved since the application is not deployed as an EAR.
To modify the login page, logout page, and the page displayed when login action failed, modify the login.jsp
, login_failed.jsp
, and logout.jsp
in the <app>-vaadin-war project of your application.
To customize the Welcome Page of your application, create a new custom view and set the view as your application's home page.
To provide a new locale setting and localization, do the following:
Create a properties file with the name localization_<LANGUAGE_CODE>.properties with the translations in <YOUR_APP>-vaadin/src/main/resources/com/whitestein/lsps/vaadin/webapp/`. The language code is based on the java.util.Locale class.
Use one of the <YOUR_APP>-vaadin/src/main/resources/com/whitestein/lsps/vaadin/webapp/localization.properties
file as a template for your properties file.
@Override protected Collection<StringOption> allLanguages() { ArrayList<StringOption> langs = new ArrayList<>(super.allLanguages()); langs.add(new StringOption("it_IT", "Italiano")); return langs; }
public class AppAppNavigator extends DefaultAppNavigator { public AppAppNavigator(UI ui, ViewDisplay display) { super(ui, display); } @Override protected Class<? extends AppView> appSettingsViewClass() { return AppAppSettingsView.class; } }
@Override protected void createNavigator(ViewDisplay display) { Navigator navigator = new AppAppNavigator(getUI(), display); navigator.addViewChangeListener(new PageTitleFromAppView()); }
To customize the Application Setting section of the Settings view, you need to override createOtherSettingsSidebar
method of the AppSettingsView class.
If you need to to remove or change the User Settings part or the Substitution Setting, implement a custom Setting view.
To customize the Settings view, do the following:
@Override protected void createNavigator(ViewDisplay display) { Navigator navigator = new AppAppNavigator(getUI(), display); }
public class AppAppNavigator extends DefaultAppNavigator { public AppAppNavigator(UI ui, ViewDisplay display) { super(ui, display); } @Override protected Class<? extends AppView> appSettingsViewClass() { //not yet existing class: return AppAppSettingsView.class; } }
@Override protected SettingComponent createOtherSettingsSidebar() { VerticalSettingsComponent result = new VerticalSettingsComponent(); result.addSettingComponent(createLanguageSettings()); //removing theme settings: //result.addSettingComponent(createThemeSettings()); result.addSettingComponent(createLayoutsSettings()); //adding custom setting: result.addSettingComponent(createSoundSettingComponent()); return result; } private SettingComponent createSoundSettingComponent() { //not yet existing class: return new SoundSettingsComponent(); }
setCompositionRoot()
call. public class SoundSettingsComponent extends CustomComponent implements SettingComponent { private final LspsUI ui; private Boolean soundSetting; private CheckBox soundSettingCheck; private Cookie soundCookie; private String NAME_COOKIE = "l-sound-cookie"; public SoundSettingsComponent() { ui = LspsUI.getCurrent(); setCaption("Sound"); soundSetting = getCurrentSoundSetting(); soundSettingCheck = new CheckBox(); ... setCompositionRoot(soundSettingCheck); }
validate()
and save()
method:false
the settings are not saved.validate()
call returns true
. @Override public boolean validate() { if (getCurrentSoundSetting()) { //adds a validation message to the component: soundSettingCheck.setComponentError(new UserError("This setting cannot be true.")); return false; } else { return true; } } @Override public void save() { Cookie soundCookie = new Cookie(NAME_COOKIE, soundSetting.toString()); VaadinService.getCurrentResponse().addCookie(soundCookie); }
Important: We strongly recommend to use JavaScript sparingly and exclusively with the aim to change the presentation layer of your application. It is not commended to manipulate your business data with JavaScript.
To add a JavaScript to your custom application, do the following:
<YOUR_APP>-vaadin-war/src/main/webapp/VAADIN/js/
directory.AppLspsUI
class, as follows: http://localhost:8080/myproject/VAADIN/js/test.js