summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTeemu Suo-Anttila <teemusa@vaadin.com>2015-09-15 13:43:32 +0300
committerJohannes Dahlström <johannesd@vaadin.com>2015-09-15 13:41:34 +0000
commit5a876aba43f3fdb3020a559e8929aa9667c25161 (patch)
treed8b78ec6e0610d6b04f60902ec10ee11eb4030b2
parentc522410a1404015bcd4c0278b7e7a71c43a68266 (diff)
downloadvaadin-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.java87
-rw-r--r--client/src/com/vaadin/client/widgets/Grid.java64
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();
}
/**