LSPS documentation logo
LSPS Documentation
Customizing Content

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:

  • The main class of the Application User Interface is the AppLspsUI class in the core package. It represents the root component of the application.
  • The components that remain the same throughout the application in your browser are governed by the AppAppLayout class: The class holds the menu to the Views of Documents, To-Dos, and Models, etc. By extending the class, you can implement your own custom menu or add custom layout parts that are always visible, such as, headers.
  • You can create custom views if required.

Customizing AppLspsUI

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:

  • It returns an instance of LspsUIBase.
  • It declares the LSPS widget set for the Vaadin servlet.
    @Widgetset("com.whitestein.lsps.vaadin.widgets.WidgetSet")
    public class LspsUI extends UI implements ErrorHandler { ...
  • It provides an implementation of LspsAppConnector, interface that defines the binding contract between the LSPS vaadin renderer and the rest of the application.
  • It provides an implementation of LspsFormConnector, interface for a connector of forms and views.
  • I t uses JAAS for user authentication: The setting is available in the login.jsp and in the WEB-INF/web.xml of the webapp project.

Customizing AppAppLayout

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:

  1. In your AppLayout class, by default the AppAppLayout, override the attach() method. Call the attach method of the parent AppLayout and then use the 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);
      }
    }
  2. In the <YOUR_APP>.core package of the vaadin project, create a class with the Vaadin component. Consider extending the CustomComponent.
  3. 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;
     
      }
    }

Adding a Custom View

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:

  1. In the <YOU_APP>.core package, create your View class that extends DefaultAppView. If this is inconvenient or impossible, extend View or Component. Implement the view constructor.
    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");
        }
      }
    }
  2. Create and integrate your custom Navigator class:
    1. Make the class extend the DefaultAppNavigator class and name it AppAppNavigator.
    2. In the AppLspsUI class, modify the createNavigator() method to use your navigator class.
      @Override protected void createNavigator(ViewDisplay display) {
          //create navigator with your custom navigator:
          Navigator navigator = new AppAppNavigator(getUI(), display);
          navigator.addViewChangeListener(new PageTitleFromAppView());
       
      }
    3. Override the getNavigator() method to return your navigator as well.
      @Override public AppAppNavigator getNavigator() {
          return (AppAppNavigator) super.getNavigator();
        }
      
  3. Make the navigator resolve URLs with the ID of your view to the class of with your View:
    1. Define the id of your view (it will be used in the URL to indicate that we want to navigate to the view)
      public String myViewId() {
        return "myview";
      }
    2. Make it return the class of your view, when it is requested.
      protected Class<? extends AppView> myAppViewClass() {
        return MyAppView.class;
      }
    3. Override the addAllViews() method and add the view with the ID and class to the Navigator.
      @Override protected void addAllViews() {
        super.addAllViews();
        addView(myViewId(), myAppViewClass());
      }
  4. Consider adding a component that will link to your view, for example an item to the main menu.

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());
  }

Customizing the Navigation Menu

To add or remove items in the navigation menu, do the following:

  1. Make your AppLayout use a custom MainMenu:
    1. Open your AppLayout implementation (the AppAppLayout by default) in the core package of the vaadin project.
    2. Adapt the createMainMenu() method so it returns your MainMenu implementation.
      @Override protected Component createMainMenu() {
        return new AppMainMenu(CONTENT_AREA_ID);
      }
  2. In the <YOU_APP>.core package of the <YOUR_APP>-vaadin project, create the implementation of the custom MainMenu class that extends the DefaultMainMenu class, in the example, AppMainMenu.
  3. To allow closing of the menu, when the user taps out of the menu on their mobile device, create the constructor with the closeOnTapAreaId parameter that calls the DefaultMainMenu constructor.
      public AppMainMenu(String closeOnTapAreaId) {
        super(closeOnTapAreaId);
      }
    
  4. Copy the implementation of the DefaultMainMenu.getNavigator() method:
      private AppNavigator getNavigator() {
        LspsUI ui = (LspsUI) UI.getCurrent();
        return ui.getNavigator();
      }
  5. Copy the implementation of the DefaultMainMenu.createMenu() method to the custom MainMenu implementation (AppMainMenu) and adapt it:
    • To remove items from the menu, comment out the if statement with the respective navigation menu item.
    • To add your items to the menu, do the following:
      1. Create a private method that adds the 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();
          } 
      2. Add the custom menu item to the createMenu() method.
        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:
        • User's hasRight()
        • Document's hasRightToOpenDocument() (false if user has no right to access given document as defined by the document access expression)
      3. Add the localization property to the localization.properties file in the <YOUR_APP>-vaadin project.
        nav.myview = My View

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();
  }
}

Setting the Home Page

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:

  • sets to a view:
    public void openHomePage() {
      navigateTo(<VIEW>.ID);
      // for example: navigateTo(getNavigator().documentsViewId());
    }
  • sets to a document:
    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:

  1. If you have not done so yet, create a custom theme.
  2. In the login.jsp file, set your theme as the default theme.
    ...
        var storage = window.localStorage;
        var theme = "my-theme";
  3. Create the rules for the login header:
    1. Create a file for the rule in the sass directory of your theme, for example *_login.scss*.
    2. In the file, define a mixin with the rules.
      • The upper part of the login has the loginHeader id.
      • The lower part with credential input has the selector &.login-page form table.
  4. Run Sass compiler and check the login page.

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;
    }
}

Customizing Content of the About Dialog

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.

Customizing the Login and Logout Page

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.

Customizing the Welcome Page

To customize the Welcome Page of your application, create a new custom view and set the view as your application's home page.

Adding a Locale

To provide a new locale setting and localization, do the following:

  1. 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.

  2. Add the language option to the language picker on the Settings screen:
    1. In the <YOUR_APP>.core package or the vaadin project, create the AppAppSettingsView class that extends the AppSettingsView class and add the locale to the allLanguages() method.
      @Override
      protected Collection<StringOption> allLanguages() {
        ArrayList<StringOption> langs = new ArrayList<>(super.allLanguages());
        langs.add(new StringOption("it_IT", "Italiano"));
        return langs;
      }
      
    2. Extend the Navigator so the user is navigated to your SettingView: create a Navigator that returns the implementation of the Settings view you have just created: override the appSettingsViewClass so it returns your AppAppSettingsView.
      public class AppAppNavigator extends DefaultAppNavigator {
       
        public AppAppNavigator(UI ui, ViewDisplay display) {
          super(ui, display);
        }
       
        @Override
        protected Class<? extends AppView> appSettingsViewClass() {
          return AppAppSettingsView.class;
        }
      }
      
    3. Extend your AppLspsUI to use your Navigator.
      @Override
      protected void createNavigator(ViewDisplay display) {
        Navigator navigator = new AppAppNavigator(getUI(), display);
        navigator.addViewChangeListener(new PageTitleFromAppView());
      }
      

Customizing the Settings View

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:

  1. In the vaadin project in the core package, make AppLspsUI to use a custom vaadin Navigator:
    1. Override the createNavigator() method of the AppLspsUI class.
      @Override
      protected void createNavigator(ViewDisplay display) {
        Navigator navigator = new AppAppNavigator(getUI(), display);
      }
      
    2. Create the AppAppNavigator class and override the appSettingsViewClass() method so it returns your AppAppSettingsView class.
      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;
        }
      }
      
  2. Create the settings view class that extends AppSettingsView and override the createOtherSettingsSidebar() method: make it return the relevant setting components. Remove the respective addSettingComponent() calls and add new ones as required.
    @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();
      }
    
  3. Implement the classes of any new settings components you added. Make the class extend the CustomComponent class and implement SettingComponent:
    1. Create the setting content as a Vaadin component.
    2. Make the component the root of the of the SettingComponent with the 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);
        }
      
  4. If required, implement the validate() and save() method:
    • validate is called when the user clicks the Save button. If it returns false the settings are not saved.
    • The save() method is called after the 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);
        }
      

Importing JavaScript

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:

  1. Add your JavaScript file to the <YOUR_APP>-vaadin-war/src/main/webapp/VAADIN/js/ directory.
  2. Annotate the LspsUI implementation of your custom application, by default the AppLspsUIclass, as follows:
    @com.vaadin.annotations.JavaScript({ "vaadin://js/<YOUR_JS>.js" })
  3. Build and deploy the application.
  4. Check if the script is available under http://localhost:8080/myproject/VAADIN/js/test.js