Loading...
Important Notice - Forums is archived

To simplify things and help our users to be more productive, we have archived the current forum and focus our efforts on helping developers on Stack Overflow. You can post new questions on Stack Overflow or join our Discord channel.

Product icon
TUTORIAL

Vaadin lets you build secure, UX-first PWAs entirely in Java.
Free ebook & tutorial.

Replacing client-side vaadin widget?

Guttorm Vik
6 years ago Nov 08, 2015 11:57pm
Henri Kerola
6 years ago Nov 10, 2015 5:18am
Guttorm Vik
6 years ago Nov 10, 2015 10:59am

Nice, thank you for that.

Now I have created an adjusted VPopupCalendar version in the regular way.

My version fixes two things:
1) It now checks the key modifiers, so it only opens on Alt-Down and not on (anything)-Down
2) It opens relative to the textfield instead of the button, so that I can have the button on the right hand side

My gwt.xml:

<replace-with class="com.ec.ptsmc.widgetset.client.MyVPopupCalendar">
        <when-type-is class="com.vaadin.client.ui.VPopupCalendar" />
    </replace-with>

MyVPopupCalendar:
Most of the code is copied from the vaadin version.
openCalendarPanel is only overridden so that I can provide my own PopupPositionCallback.
openCalendarPanel is where I needed the workaround provided by Henri to access a private instance variable in the parent class.

package com.ec.ptsmc.widgetset.client;

import java.util.Date;

import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.PopupPanel.PositionCallback;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.ComputedStyle;
import com.vaadin.client.VConsole;
import com.vaadin.client.ui.VPopupCalendar;

public class MyVPopupCalendar extends VPopupCalendar {

    @Override
    public void onBrowserEvent(com.google.gwt.user.client.Event event) {
        if (DOM.eventGetType(event) == Event.ONKEYDOWN
                && event.getKeyCode() == getOpenCalenderPanelKey()) {
            
            if((event.getAltKey() || event.getMetaKey()) && !event.getCtrlKey() && !event.getShiftKey()) {
                openCalendarPanel();
                event.preventDefault();
            }
            
        }
        else {
            super.onBrowserEvent(event);
        }
    }

    public native boolean isOpen() /*-{
        return this.@com.vaadin.client.ui.VPopupCalendar::open;
    }-*/;

    public native void setOpen() /*-{
        this.@com.vaadin.client.ui.VPopupCalendar::open = true;
    }-*/;

    /**
     * Opens the calendar panel popup
     */
    public void openCalendarPanel() {

        if (!isOpen() && !readonly && isEnabled()) {
            setOpen();

            if (getCurrentDate() != null) {
                calendar.setDate((Date) getCurrentDate().clone());
            } else {
                calendar.setDate(new Date());
            }

            // clear previous values
            popup.setWidth("");
            popup.setHeight("");
            popup.setPopupPositionAndShow(new PopupPositionCallback());
        } else {
            VConsole.error("Cannot reopen popup, it is already open!");
        }
    }

    private class PopupPositionCallback implements PositionCallback {

        @Override
        public void setPosition(int offsetWidth, int offsetHeight) {
            
            Widget relativeTo = MyVPopupCalendar.this.text;
            
            final int width = offsetWidth;
            final int height = offsetHeight;
            final int browserWindowWidth = Window.getClientWidth()
                    + Window.getScrollLeft();
            final int windowHeight = Window.getClientHeight()
                    + Window.getScrollTop();
            int left = relativeTo.getAbsoluteLeft();

            // Add a little extra space to the right to avoid
            // problems with IE7 scrollbars and to make it look
            // nicer.
            int extraSpace = 30;

            boolean overflow = left + width + extraSpace > browserWindowWidth;
            if (overflow) {
                // Part of the popup is outside the browser window
                // (to the right)
                left = browserWindowWidth - width - extraSpace;
            }

            int extraHeight = 2;
            ComputedStyle style = new ComputedStyle(popup.getElement());
            int[] margins = style.getMargin();

            int top = relativeTo.getAbsoluteTop() + relativeTo.getOffsetHeight() + extraHeight;
            int desiredPopupBottom = top + height + margins[0] + margins[2];

            if (desiredPopupBottom > windowHeight) {
                
                // Move popup above instead
                top -= height + relativeTo.getOffsetHeight() + margins[0] + margins[2] + extraHeight;
                
            }

            popup.setPopupPosition(left, top);

            doSetFocus();
        }

        private void doSetFocus() {
            /*
             * We have to wait a while before focusing since the popup needs to
             * be opened before we can focus
             */
            Timer focusTimer = new Timer() {
                @Override
                public void run() {
                    setFocus(true);
                }
            };

            focusTimer.schedule(100);
        }
    }
}

And finally my adjustments to the scss:
This adjusts the placement in the Valo theme like we use it.
The constants should probably refer to some valo variables to be more generic.

// Override position of datefield icon to be on the right

    .v-datefield [class*="textfield"] {
        padding-left: 6px;
        padding-right: 26px;    
    }
    
    .v-datefield [class*="button"] {
        position: absolute;
        top: 1px;
        right: 1px;
        left:initial;
        border:none;
        border-left: 1px solid #8498bc;
        border-radius:initial;  
    }
Henri Kerola
6 years ago Nov 10, 2015 5:55pm