Custom Layouts, using regular CSS

Hello, guys. This is a topic already covered in older posts but I am opening a new one to see if I can put things more clearly. I also believe this is the kind of thing many others would like to use more in their applications, so it is a nice discussion to start.

I have an Vaadin 7 app created through the maven-archetype-application. It generates a custom theme called mytheme, that I am using to (try to) work with custom layouts. This is the structure right now (image attached too):

  • /webapp/VAADIN/themes/mytheme
  • /webapp/VAADIN/themes/mytheme/styles.css (I am NOT using SASS, only plain CSS)
  • /webapp/VAADIN/themes/mytheme/img: some images used in the CSS rules
  • /webapp/VAADIN/themes/mytheme/js: 2 javascript files
  • /webapp/VAADIN/themes/mytheme/layouts: two files, index.xml and inner_page.xml

In the CSS, references to images are done like this:
./img/image.png
, since the CSS file is in the same level as the img folder. In the HTML templates, references are made like this:
…/js/script.js
and
…/styles.css
, which to me sounds OK. Like:

[code]

[/code]In the CSS, I am doing like this:

@charset "utf-8"; @import "../reindeer/legacy-styles.css"; And then the rules come. Regular CSS rules. Like:

[code]
html {
font-size: 62.5%;
}

body {
font-size: 1.6em;
line-height: 1;
text-align: center;
}
[/code]I am compiling the project in Eclipse using Run As > Maven install and compilation runs OK. Then I run in a Tomcat bundle using Run As > Run on Server. And I get a result like in the
image2.png
attached, which is far distant from the page I was expecting. It doesn’t work … do you have any idea of the appropriate structure to follow in order to use custom layouts in Vaadin 7? What am I doing wrong?

Thanks so much in advance!

Regards,
Pedro
13533.png
13534.png

Hi, all.

Maybe it is useful to others. I finally could work with custom layouts. The scenario is:

  • HTML and CSS is created by a UX designer. This way, I can test flow and L&T statically, if I want
  • My intention is to put focus in the code (insert components in place holders, handle events generated by them)

So, what I did is:

  1. Generated a maven project using the
    vaadin-archetype-application
    archetype

  2. Deleted
    files styles.scss and mytheme.scss

  3. Removed ALL generated content from styles.css
    , saved what the designer sent me instead
  4. Saved all image resources used in the CSS rules in a folder /img, in the custom theme base folder
  5. Created a folder called
    layouts
    (


    MUST be this name


    ), saved the HTML templates inside it
  6. Made sure all references to CSS are OK in the pages/templates
  7. Made sure all references to image resources in the CSS are OK, also (they should be like url(img/picture.png))

Java side:

  • Created a custom component, and a custom layout inside it. Like this:

[code]
public class CustomView extends CustomComponent implements View {

private static final long serialVersionUID = 8958800667561242409L;

[color=#0000FF]


private CustomLayout mainLayout;

[/color]
private NativeButton doLogin;
private NativeButton doClean;
private TextField username;
private PasswordField password;

public CustomView () {}

@SuppressWarnings("serial")
public CustomView build() {
    
    username = new TextField();
    username.addStyleName("login_input_text");
    username.setInputPrompt("Your username here");
    
    username.addFocusListener(new FocusListener() {
        @Override
        public void focus(FocusEvent event) {
            Notification.show("Component has been focused");
        }
    });
    
    password = new PasswordField();
    password.setInputPrompt("Your password here");
    password.addStyleName("login_input_password");
    
    doLogin = new NativeButton();
    doClean = new NativeButton();
    
    doLogin.addClickListener(new ClickListener() {
        @Override
        public void buttonClick(ClickEvent event) {
            UI.getCurrent().getNavigator().navigateTo("home");
        }
    });
    doLogin.addStyleName("login_submit");
    
    doClean.addClickListener(new ClickListener() {
        @Override
        public void buttonClick(ClickEvent event) {
            Notification.show("Clean button clicked.");
        }
    });
    doClean.addStyleName("login_clear");
    
    [b]

mainLayout = new CustomLayout(“index”);
[/b]
mainLayout.addComponent(username, "

login_name

");
mainLayout.addComponent(password, “login_pass”);
mainLayout.addComponent(doLogin, “login_submit”);
mainLayout.addComponent(doClean, “login_clear”);

    setCompositionRoot(mainLayout);
    return this;
}

@Override
public void enter(ViewChangeEvent event) {
}

}
[/code]The main point here is:

  • The string you use in the CustomLayout instantiation MUST BE THE NAME of the HTML file
  • By convention, Vaadin looks for the HTML tempalte in
    layouts
    folder under the custom theme base folder (this is the reason this folder MUST BE entitled
    layouts
    )
  • Do not forget to apply the CSS rules to the components you create and introduce in the HTML place holders (a.k.a. div tags with location attribute defined)
  • Make sure you are using exactly the SAME VALUE to the location attribute in the HTML div and when you add the component to the custom layout instance

So, in the HTML you may have something like:

<label for ="login_name"> <div location="login_name" ></div> <!-- <input type ="text" value="" id="[color=#FF0000] [b] login_name [/b] [/color]" /> --> </label> Important point about CSS: if it does not start with this:

[code]
@charset “utf-8”;
[b]
@import “…/reindeer/legacy-styles.css”;

.v-app {
background: white;
}
[/b]

… and then the rules the designer provided to you :slight_smile:
[/code]However, at least to me, it does
NOT
work. Anyway, this is in the Book of Vaadin as well.

To compile the project, I always:

  1. Do a Project > Clean in the project
  2. Do a Run as > Maven clean as well
  3. Do a Run as > Maven install

​​And that’s it. Works pretty good to me.
I hope it helps people having troubles with custom layouts. Documentation does not say too much, and all this tutorial came from my attempts on putting it to run.

Cheers,
Pedro

hi pedro,

this helped!

the only thing that doesn’t work this way is javascript.

i’ve created a file “/VAADIN/themes/mytheme/js/files/functions.js”

and i’m calling it in the layout.html file, placed in “/VAADIN/themes/mytheme/layouts/” via:

“”

i get acces to images which are placed under “/VAADIN/themes/mytheme/img/” by “” but regarding scripts… no chance :frowning:

if i look at the html source code in the browser my scripts are missing

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=10;chrome=1" />
<style type="text/css">
html,body {
    height: 100%;
    margin: 0;
}
</style>
<link rel="shortcut icon" type="image/vnd.microsoft.icon"
    href="./../VAADIN/themes/wowipro/favicon.ico" />
<link rel="icon" type="image/vnd.microsoft.icon"
    href="./../VAADIN/themes/wowipro/favicon.ico" />
</head>
<body scroll="auto" class=" v-generated-body">
    <div id="WPro-1100615037" class=" v-app wpro">
        <div class=" v-app-loading"></div>
        <noscript>You have to enable javascript in your browser to
            use an application built with Vaadin.</noscript>
    </div>
    <iframe tabindex="-1" id="__gwt_historyFrame"
        style="position: absolute; width: 0; height: 0; border: 0; overflow: hidden"
        src="javascript:false"></iframe>
    <script type="text/javascript" src="./../VAADIN/vaadinBootstrap.js"></script>
    <script type="text/javascript">
        //<![CDATA[
        if (!window.vaadin)
            alert("Failed to load the bootstrap javascript: ./../VAADIN/vaadinBootstrap.js");
        if (typeof window.__gwtStatsEvent != 'function') {
            vaadin.gwtStatsEvents = ;
            window.__gwtStatsEvent = function(event) {
                vaadin.gwtStatsEvents.push(event);
                return true;
            };
        }
        vaadin
                .initApplication(
                        "WowiPro-1100615037",
                        {
                            "authErrMsg" : {
                                "caption" : "Authentication problem",
                                "message" : "Take note of any unsaved data, and <u>click here<\/u> to continue."
                            },
                            "comErrMsg" : {
                                "caption" : "Communication problem",
                                "message" : "Take note of any unsaved data, and <u>click here<\/u> to continue."
                            },
                            "debug" : true,
                            "heartbeatInterval" : 300,
                            "serviceUrl" : "./..",
                            "sessExpMsg" : {
                                "caption" : "Session Expired",
                                "message" : "Take note of any unsaved data, and <u>click here<\/u> to continue."
                            },
                            "standalone" : true,
                            "theme" : "wowipro",
                            "vaadinDir" : "./../VAADIN/",
                            "versionInfo" : {
                                "vaadinVersion" : "7.1.13"
                            },
                            "widgetset" : "com.vaadin.DefaultWidgetSet"
                        });
        //]]>
    </script>
</body>
</html>

thanks!!

Hey,

Reading one old post in the forum, I saw
Marko Grönroos
recommending to use the end tag instead of the short way. So, instead of [color=#FF0000]
[b]

[/b]
[/color]. Seems that it worked to the guy looking for help in that regard.
If you want to follow the thread of this post, reach it
here
.
Hope it helps.

Cheers,
Pedro

i never used the short way :slight_smile:

Hum, it is true. :stuck_out_tongue:

I never had to use scripts loaded in the page directly.

I know from documentation that there is an API for Javascript execution, but never had to use it in such a situation (in the load of the page). However, I will have to use it now, in a project I am working on. So, if I have any updates on my attempts to get it working, I will surely post here and share with the community. Just like I did for the very first message in this post.

Hope I can help you soon.

Best regards,
Pedro

okay… i get some javascript file to load by doing the following:

[code]
@WebServlet(value = “/*”, asyncSupported = true)
@VaadinServletConfiguration(productionMode = false, ui = WProUI.class)
public static class Servlet extends VaadinServlet
{
@Override
protected void servletInitialized() throws ServletException
{
super.servletInitialized();
getService().addSessionInitListener(new SessionInitListener()
{
@Override
public void sessionInit(SessionInitEvent event)
{
event.getSession().addBootstrapListener(new BootstrapListener()
{

                            @Override
                            public void modifyBootstrapFragment(BootstrapFragmentResponse response)
                            {
                                // TODO Auto-generated method stub

                            }

                            @Override
                            public void modifyBootstrapPage(BootstrapPageResponse response)
                            {
                                Element h = response.getDocument().getElementsByTag("head").get(0);
                            
                                Element s1 = response.getDocument().createElement("script");
                                s1.attr("type", "text/javascript");
                                s1.attr("src", "../VAADIN/themes/wpro/js/jquery.collapsible.min.js");
                                h.appendChild(s1);                                   
                            }
                        });
            }
        });    
    }      
}

[/code]it really loads the “jquery.collapsible.min.js” file, i can see it in the sourcecode in the browser.

BUT…

if i try another js file (the one that actually makes use of the jquery.collapsible.min.js) by adding this into modifyBootstrapPage:
Element s2 = response.getDocument().createElement("script"); s2.attr("type", "text/javascript"); s2.attr("src", "../VAADIN/themes/wowipro/js/functions.js"); h.appendChild(s2); the functions.js file is loaded and displayed in the sourcecode, but it’s empty :((

this is the code inside functions.js:

[code]
$(function() {

//===== collapsible nav buttons =====//

$('.collapsible').collapsible({
    cookieName: 'navButton',
    cssOpen: 'opened',
    cssClose: 'closed',
    speed: 300
});

});
[/code]it doesn’t matter if i load s1 before s2… functions.js is always empty in the browser.

damn… problem after problem :slight_smile:

Hi, St. St.,

Here, I am using the same approach you posted above. Instead of "
…/VAADIN/themes/…
" I am using a single dot, to search for the VAADIN folder starting from the current directory. When I go to
Tools > Web Developer > Page Source
in Firefox, I click on the links for the two scripts added and the content shown to me is exactly the same of the JS files. So, it is loaded.

[code]

html, body {height:100%;margin:0;}

[b]
[color=#0000FF]

[/color]
[/b]

[/code]When I click the links to the javascript files, they are there. They are found. When you say the script is empty for you, what exactly you mean?

When I was using
…/VAADIN/…
, it was giving me an HTML snippet witn an error status. Here is the code:

[code]
@WebServlet(value = “/*”, asyncSupported = true)
@VaadinServletConfiguration(productionMode = false, ui = MyVaadinUI.class, widgetset = “com.avaya.dr.AppWidgetSet”)
public static class Servlet extends VaadinServlet {

    @Override
    protected void servletInitialized() throws ServletException {
        super.servletInitialized();
        getService().addSessionInitListener(new SessionInitListener() {
            
            @Override
            public void sessionInit(SessionInitEvent event) throws ServiceException {
                event.getSession().addBootstrapListener(new BootstrapListener() {
                    
                    @Override
                    public void modifyBootstrapPage(BootstrapPageResponse response) {
                        Element head = response.getDocument().getElementsByTag("head").get(0);
                        
                        // Adding scripts to the head
                        Element jquery = response.getDocument().createElement("script");
                        jquery.attr("type", "text/javascript");
                        jquery.attr("src", "[color=#0000FF]


./VAADIN/themes/mytheme/js/jquery-1.9.1.min.js

[/color]");
head.appendChild(jquery);

                        Element custom = response.getDocument().createElement("script");
                        custom.attr("type", "text/javascript");
                        custom.attr("src", "[color=#0000FF]


./VAADIN/themes/mytheme/js/script.js

[/color]");
head.appendChild(custom);
}

                    @Override
                    public void modifyBootstrapFragment(BootstrapFragmentResponse response) {}
                });

[/code]And, because I am adding the scripts programatically, I also removed them from the HTML template.
It is not working, I don’t get the expected behavior … I am investigating why. But now I suppose it is something with the logic in my script. I will keep investigating but, based on my post, do you think your problem can be fixed? Let me know what you think about it. :slight_smile:

Best regards,
Pedro

Pedro !!
I Owe you a party!! Let me know when you visit India !! :slight_smile:
I was about to turn mad when custom layout using HTML,CSS was not working after 3 days of struggle & a Demo by next week!
Able to get the required page now ( though 90%)
But Thankyou so soo much!!

Suresh.S

I am happy it works for you, Suresh!
Thanks for letting me know. :slight_smile:

Cheers,
Pedro

Pedro…
Having another situation… :frowning:
Can you tell me how can i fix the below:
1) Loaded a HTML
2) got input value & processed the result
3) how can i just update the existing HTML template with result value now… :-((

Attached a part of screen for reference…

Fingers crossed :frowning: (
17432.png

Got IP value and processed
Need to update the values in the bottom part…

Hum, I don’t know exactly the scenario but …

Debugging the application you see the values in the server side? I mean: you load the HTML adding the components to the place holders you defined in the template, right? Then, you handle the click of the button, process the request and update the values of components you need to update in the view (labels, text fields, etc). Ok? Debugging the application, can you confirm the components were updated and contain the values you need/want?

You could try 2 things (it really depends on how dynamic the behavior is there in your app, so I am giving the 2 that worked to me):

You could use

UI.getCurrent().access(new Runnable () { public void run() { // you do whatever you need here, updating the components in the server side UI.getCurrent().push(); } } * I use this one when I have a page displayed and want to update some fields that were updated by another background process runing periodically. But I also need to confess I never used this with custom layouts, although I think there’d not be behavioral differences between the 2 approaches (via template or via full java code).

or you could update the components in the UI with the results of the processing you are performing, then mark them as dirty to force the method beforeClientResponse() is invoked.

Should work. Good luck.

Thankyou very much Pedro !! “Vaadin certified professional” :wink:
Option 2 worked :slight_smile:

Do you’ve any working sample…

  1. I get an input useing customLayout
  2. processing the data
  3. displaying the result

Now : 4) need to create a pie chart
5) Need to embed that in the Already loaded custom layout…

Unfortunately I don’t have any working sample I could share with you.
The application I am developing using Vaadin is private, cannot share. So, the samples above are like snippets that can help to understand the subject.

But as far as I understood your last post, it is like:

  • You already have steps 1 to 3 working.
  • You need to make 4 and 5 work now.

‘Embedding’ the component (chart) in the view to me would sound like:

  • Declaring the place holder in the template (div location=“my_chart”)
  • Configuring this element behavior in the CSS in such a way the dimensions of the chart are correctly set
  • Injecting the element in the template through the Java code, exactly as it was made for all other components
  • Playing with the visibility of the component (the chart), showing when it is the case and hiding when it is the case too.

Or, instead of playing directly with the chart in the layout, you could inject in this place holder a layout manager (such as horizontal layout or vertical layout) and adding the chart in this ‘inner’ layout. So, the chart would take the whole area of ths layout (setSizeFull). Should work if classes in the CSS and configuration in the Java side (immediate to true, size full to the chart, correct dimensions to the vertical/horizontal layout, etc) are provided and are correct.

Does it help? Would work to me, so I am sharing the way I am used to do.

Cheers,
Pedro