diff options
author | Teemu Suo-Anttila <teemusa@vaadin.com> | 2015-09-15 13:43:32 +0300 |
---|---|---|
committer | Johannes Dahlström <johannesd@vaadin.com> | 2015-09-15 13:41:34 +0000 |
commit | 5a876aba43f3fdb3020a559e8929aa9667c25161 (patch) | |
tree | d8b78ec6e0610d6b04f60902ec10ee11eb4030b2 | |
parent | c522410a1404015bcd4c0278b7e7a71c43a68266 (diff) | |
download | vaadin-framework-5a876aba43f3fdb3020a559e8929aa9667c25161.tar.gz vaadin-framework-5a876aba43f3fdb3020a559e8929aa9667c25161.zip |
Add basic tab navigation with focus handling in Editor (#16841)
Change-Id: I89ca61020092cafd3390273ae90736bd6856c8a6
-rw-r--r-- | client/src/com/vaadin/client/widget/grid/DefaultEditorEventHandler.java | 87 | ||||
-rw-r--r-- | client/src/com/vaadin/client/widgets/Grid.java | 64 |
2 files changed, 123 insertions, 28 deletions
diff --git a/client/src/com/vaadin/client/widget/grid/DefaultEditorEventHandler.java b/client/src/com/vaadin/client/widget/grid/DefaultEditorEventHandler.java index a5b0b5e961..d607701d19 100644 --- a/client/src/com/vaadin/client/widget/grid/DefaultEditorEventHandler.java +++ b/client/src/com/vaadin/client/widget/grid/DefaultEditorEventHandler.java @@ -16,6 +16,7 @@ package com.vaadin.client.widget.grid; import com.google.gwt.core.client.Duration; +import com.google.gwt.dom.client.BrowserEvents; import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.ui.Widget; @@ -36,8 +37,9 @@ import com.vaadin.client.widgets.Grid.EditorDomEvent; public class DefaultEditorEventHandler<T> implements Editor.EventHandler<T> { public static final int KEYCODE_OPEN = KeyCodes.KEY_ENTER; - public static final int KEYCODE_MOVE = KeyCodes.KEY_ENTER; + public static final int KEYCODE_MOVE_VERTICAL = KeyCodes.KEY_ENTER; public static final int KEYCODE_CLOSE = KeyCodes.KEY_ESCAPE; + private static final int KEYCODE_MOVE_HORIZONTAL = KeyCodes.KEY_TAB; private double lastTouchEventTime = 0; private int lastTouchEventX = -1; @@ -122,11 +124,13 @@ public class DefaultEditorEventHandler<T> implements Editor.EventHandler<T> { } /** - * Moves the editor to another row if the received event is a move event. - * The default implementation moves the editor to the clicked row if the - * event is a click; otherwise, if the event is a keydown and the keycode is - * {@link #KEYCODE_MOVE}, moves the editor one row up or down if the shift - * key is pressed or not, respectively. + * Moves the editor to another row or another column if the received event + * is a move event. The default implementation moves the editor to the + * clicked row if the event is a click; otherwise, if the event is a keydown + * and the keycode is {@link #KEYCODE_MOVE_VERTICAL}, moves the editor one + * row up or down if the shift key is pressed or not, respectively. Keydown + * event with keycode {@link #KEYCODE_MOVE_HORIZONTAL} moves the editor left + * or right if shift key is pressed or not, respectively. * * @param event * the received event @@ -148,11 +152,53 @@ public class DefaultEditorEventHandler<T> implements Editor.EventHandler<T> { return true; } - else if (e.getTypeInt() == Event.ONKEYDOWN - && e.getKeyCode() == KEYCODE_MOVE) { + else if (e.getTypeInt() == Event.ONKEYDOWN) { - editRow(event, event.getRowIndex() + (e.getShiftKey() ? -1 : +1), - event.getFocusedColumnIndex()); + int rowDelta = 0; + int colDelta = 0; + + if (e.getKeyCode() == KEYCODE_MOVE_VERTICAL) { + rowDelta += (e.getShiftKey() ? -1 : +1); + } else if (e.getKeyCode() == KEYCODE_MOVE_HORIZONTAL) { + colDelta = (e.getShiftKey() ? -1 : +1); + } + + final boolean changed = rowDelta != 0 || colDelta != 0; + + if (changed) { + editRow(event, event.getRowIndex() + rowDelta, + event.getFocusedColumnIndex() + colDelta); + + // FIXME should be in editRow + event.getGrid().fireEvent(new EditorMoveEvent(cell)); + } + + return changed; + } + + return false; + } + + /** + * Moves the editor to another column if the received event is a move event. + * By default the editor is moved on a keydown event with keycode + * {@link #KEYCODE_MOVE_HORIZONTAL}. This moves the editor left or right if + * shift key is pressed or not, respectively. + * + * @param event + * the received event + * @return true if this method handled the event and nothing else should be + * done, false otherwise + */ + protected boolean handleBufferedMoveEvent(EditorDomEvent<T> event) { + Event e = event.getDomEvent(); + final EventCellReference<T> cell = event.getCell(); + + if (e.getType().equals(BrowserEvents.KEYDOWN) + && e.getKeyCode() == KEYCODE_MOVE_HORIZONTAL) { + + editRow(event, event.getRowIndex(), event.getFocusedColumnIndex() + + (e.getShiftKey() ? -1 : +1)); // FIXME should be in editRow event.getGrid().fireEvent(new EditorMoveEvent(cell)); @@ -234,14 +280,25 @@ public class DefaultEditorEventHandler<T> implements Editor.EventHandler<T> { final Editor<T> editor = event.getEditor(); final boolean isBody = event.getCell().isBody(); + final boolean handled; if (event.getGrid().isEditorActive()) { - return (!editor.isBuffered() && isBody && handleMoveEvent(event)) - || handleCloseEvent(event) - // Swallow events if editor is open and buffered (modal) - || editor.isBuffered(); + handled = handleCloseEvent(event) + || (!editor.isBuffered() && isBody && handleMoveEvent(event)) + || (editor.isBuffered() && isBody && handleBufferedMoveEvent(event)); } else { - return event.getGrid().isEnabled() && isBody + handled = event.getGrid().isEnabled() && isBody && handleOpenEvent(event); } + + if (handled) { + // Prevent any defaults for handled events. + event.getDomEvent().preventDefault(); + } + + // Buffered mode should swallow all events, if not already handled. + boolean swallowEvent = event.getGrid().isEditorActive() + && editor.isBuffered(); + + return handled || swallowEvent; } }
\ No newline at end of file diff --git a/client/src/com/vaadin/client/widgets/Grid.java b/client/src/com/vaadin/client/widgets/Grid.java index e9ee7d71b2..e7f41fa923 100644 --- a/client/src/com/vaadin/client/widgets/Grid.java +++ b/client/src/com/vaadin/client/widgets/Grid.java @@ -1232,7 +1232,7 @@ public class Grid<T> extends ResizeComposite implements * @param <T> * the row type of the grid */ - public static class Editor<T> { + public static class Editor<T> implements DeferredWorker { public static final int KEYCODE_SHOW = KeyCodes.KEY_ENTER; public static final int KEYCODE_HIDE = KeyCodes.KEY_ESCAPE; @@ -1488,14 +1488,37 @@ public class Grid<T> extends ResizeComposite implements "Cannot edit row: editor is not enabled"); } if (state != State.INACTIVE) { - if (isBuffered()) { + if (isBuffered() && this.rowIndex != rowIndex) { throw new IllegalStateException( "Cannot edit row: editor already in edit mode"); } } + if (columnIndex >= grid.getVisibleColumns().size()) { + throw new IllegalArgumentException("Edited column index " + + columnIndex + + " was bigger than visible column count."); + } - this.rowIndex = rowIndex; + if (this.rowIndex == rowIndex && focusedColumnIndex == columnIndex) { + // NO-OP + return; + } + + if (focusedColumnIndex != columnIndex + && columnIndex >= grid.getFrozenColumnCount()) { + // Scroll to new focused column. + grid.getEscalator().scrollToColumn(columnIndex, + ScrollDestination.ANY, 0); + } this.focusedColumnIndex = columnIndex; + + if (this.rowIndex == rowIndex) { + updateHorizontalScrollPosition(); + focusColumn(focusedColumnIndex); + // No need to request anything from the editor handler. + return; + } + this.rowIndex = rowIndex; state = State.ACTIVATING; final Escalator escalator = grid.getEscalator(); @@ -1705,7 +1728,6 @@ public class Grid<T> extends ResizeComposite implements protected void showOverlay() { // Ensure overlay is hidden initially hideOverlay(); - DivElement gridElement = DivElement.as(grid.getElement()); TableRowElement tr = grid.getEscalator().getBody() @@ -1776,14 +1798,7 @@ public class Grid<T> extends ResizeComposite implements }, FocusEvent.getType())); } - if (i == focusedColumnIndex) { - if (editor instanceof Focusable) { - ((Focusable) editor).focus(); - } else if (editor instanceof com.google.gwt.user.client.ui.Focusable) { - ((com.google.gwt.user.client.ui.Focusable) editor) - .setFocus(true); - } - } + focusColumn(focusedColumnIndex); } else { cell.addClassName(NOT_EDITABLE_CLASS_NAME); cell.addClassName(tr.getCells().getItem(i).getClassName()); @@ -1885,6 +1900,23 @@ public class Grid<T> extends ResizeComposite implements Unit.PX); } + private void focusColumn(int colIndex) { + if (colIndex < 0 || colIndex >= grid.getVisibleColumns().size()) { + // NO-OP + return; + } + + Widget editor = getWidget(grid.getVisibleColumn(colIndex)); + if (colIndex == focusedColumnIndex) { + if (editor instanceof Focusable) { + ((Focusable) editor).focus(); + } else if (editor instanceof com.google.gwt.user.client.ui.Focusable) { + ((com.google.gwt.user.client.ui.Focusable) editor) + .setFocus(true); + } + } + } + private boolean buttonsShouldBeRenderedBelow(TableRowElement tr) { TableSectionElement tfoot = grid.escalator.getFooter().getElement(); double tfootPageTop = WidgetUtil.getBoundingClientRect(tfoot) @@ -2150,6 +2182,11 @@ public class Grid<T> extends ResizeComposite implements public EventHandler<T> getEventHandler() { return eventHandler; } + + @Override + public boolean isWorkPending() { + return saveTimeout.isRunning() || bindTimeout.isRunning(); + } } public static abstract class AbstractGridKeyEvent<HANDLER extends AbstractGridKeyEventHandler> @@ -7738,7 +7775,8 @@ public class Grid<T> extends ResizeComposite implements @Override public boolean isWorkPending() { return escalator.isWorkPending() || dataIsBeingFetched - || autoColumnWidthsRecalculator.isScheduled(); + || autoColumnWidthsRecalculator.isScheduled() + || editor.isWorkPending(); } /** |