3

I'm trying to emulate normal browser behaviour in my vaadin grid, which includes middle mouse click to open in a new tab:

addItemClickListener(e -> {
            boolean newTab = e.getMouseEventDetails().getButton() == MouseEventDetails.MouseButton.MIDDLE || e.getMouseEventDetails().isCtrlKey();
            //open in window or new tab
        }); 

However, the middle mouse button is not registered by vaadin. How could I get this to work?

F43nd1r
  • 7,690
  • 3
  • 24
  • 62

2 Answers2

3

That feature was included in vaadin-grid (which goes into Vaadin 10) and will not work in Vaadin 8.

For Vaadin 8, you can either intercept the event with some client-side extension, or use a ComponentRenderer for adding a Panel to each component (which works, but is not ideal because it degrades performance):

grid.addColumn(item->{
    Panel p = new Panel(item.getName());
    p.setStyleName(ValoTheme.PANEL_BORDERLESS);
    p.addClickListener(ev->{
        System.out.println(ev.getButtonName());             
    });
    return p;
}).setRenderer(new ComponentRenderer());

A client-side extension, on the other hand, allows listening to javascript events (such as MouseEvent) and triggering a server event in response. Creating a extension is quite a complex topic (since it uses a part of the API that is normally hidden from the developer) but it allows direct access to rendered DOM, which is not possible otherwise.

The following resources from the documentation may give you a starting point: Creating a component extension (which describes a simple extension with Java code only) and Integrating JavaScript Components and Extension (which explains how to add native JavaScript code to your extension).

Javier
  • 12,100
  • 5
  • 46
  • 57
  • Vaadin 10 isn't stable yet, so I'd like to stay with 8. Using a ComponentRenderer makes the grid unusably slow loading. How would one catch a middle click in a clientside extension? – F43nd1r Jan 15 '18 at 22:44
  • I tried to expand a bit on client-side extensions, which is a broad topic. – Javier Jan 15 '18 at 23:26
  • I've posted my solution below, but as this answer is more generic and probably more helpful to others, I'm going to accept it. – F43nd1r Jan 16 '18 at 02:16
  • now that vaadin 10 is out, how would a solution in vaadin 10 look like? – F43nd1r Jul 13 '18 at 20:54
1

How I solved the problem in my specific case:

Server side:

public class MyGrid<T> extends Grid<T> {
    public MyGrid(String caption, DataProvider<T, ?> dataProvider) {
        super(caption, dataProvider);
        MiddleClickExtension.extend(this);
    }

    public static class MiddleClickExtension<T> extends AbstractGridExtension<T> {
        private MiddleClickExtension(MyGrid<T> grid) {
            super.extend(grid);
            registerRpc((rowKey, columnInternalId, details) -> grid.fireEvent(
                    new ItemClick<>(grid, grid.getColumnByInternalId(columnInternalId), grid.getDataCommunicator().getKeyMapper().get(rowKey), details)),
                    MiddleClickGridExtensionConnector.Rpc.class);
        }

        public static void extend(MyGrid<?> grid) {
            new MiddleClickExtension<>(grid);
        }

        @Override
        public void generateData(Object item, JsonObject jsonObject) {
        }

        @Override
        public void destroyData(Object item) {
        }

        @Override
        public void destroyAllData() {
        }

        @Override
        public void refreshData(Object item) {
        }
    }
}

Client side:

@Connect(MyGrid.MiddleClickExtension.class)
public class MiddleClickGridExtensionConnector extends AbstractExtensionConnector {
    @Override
    protected void extend(ServerConnector target) {
        getParent().getWidget().addDomHandler(event -> {
            if (event.getNativeButton() == NativeEvent.BUTTON_MIDDLE) {
                event.preventDefault();
                CellReference<JsonObject> cell = getParent().getWidget().getEventCell();
                getRpcProxy(Rpc.class).middleClick(cell.getRow().getString(DataCommunicatorConstants.KEY), getParent().getColumnId(cell.getColumn()),
                        MouseEventDetailsBuilder.buildMouseEventDetails(event.getNativeEvent(), event.getRelativeElement()));
            }
        }, MouseDownEvent.getType());
    }

    @Override
    public GridConnector getParent() {
        return (GridConnector) super.getParent();
    }

    public interface Rpc extends ServerRpc {
        void middleClick(String rowKey, String columnInternalId, MouseEventDetails details);
    }
}
F43nd1r
  • 7,690
  • 3
  • 24
  • 62