diff options
author | Johannes Dahlström <johannes.dahlstrom@vaadin.com> | 2012-02-16 15:15:28 +0000 |
---|---|---|
committer | Johannes Dahlström <johannes.dahlstrom@vaadin.com> | 2012-02-16 15:15:28 +0000 |
commit | b85cc4e7915de55f04809627a628dd0d41792960 (patch) | |
tree | 7ddc6a027515b9ce3d967bf4e9e36b728ba7c8c0 /src | |
parent | 296138490ec5472d7ef062a56873cb290292551f (diff) | |
download | vaadin-framework-b85cc4e7915de55f04809627a628dd0d41792960.tar.gz vaadin-framework-b85cc4e7915de55f04809627a628dd0d41792960.zip |
Patch for #5100 - TabSheet keyboard navigation
- The active tab button in the tab bar is now focusable by clicking or via tabulator
- When the focus is in the tab bar, the tab can be changed with left and right arrow keys
- Delete key closes the active focused tab if closable
- TODO: programmatic control on server side, configurable keyboard shortcuts
svn changeset:23052/svn branch:6.8
Diffstat (limited to 'src')
-rw-r--r-- | src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java | 126 | ||||
-rw-r--r-- | src/com/vaadin/ui/TabSheet.java | 37 |
2 files changed, 154 insertions, 9 deletions
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java b/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java index 38140988ad..2a12238c4b 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java @@ -12,8 +12,19 @@ import com.google.gwt.dom.client.DivElement; import com.google.gwt.dom.client.Style; import com.google.gwt.dom.client.TableCellElement; import com.google.gwt.dom.client.TableElement; +import com.google.gwt.event.dom.client.BlurEvent; +import com.google.gwt.event.dom.client.BlurHandler; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.event.dom.client.FocusEvent; +import com.google.gwt.event.dom.client.FocusHandler; +import com.google.gwt.event.dom.client.HasBlurHandlers; +import com.google.gwt.event.dom.client.HasFocusHandlers; +import com.google.gwt.event.dom.client.HasKeyDownHandlers; +import com.google.gwt.event.dom.client.KeyCodes; +import com.google.gwt.event.dom.client.KeyDownEvent; +import com.google.gwt.event.dom.client.KeyDownHandler; +import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.user.client.Command; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Element; @@ -21,8 +32,10 @@ import com.google.gwt.user.client.Event; import com.google.gwt.user.client.ui.ComplexPanel; import com.google.gwt.user.client.ui.SimplePanel; import com.google.gwt.user.client.ui.Widget; +import com.google.gwt.user.client.ui.impl.FocusImpl; import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.client.BrowserInfo; +import com.vaadin.terminal.gwt.client.Focusable; import com.vaadin.terminal.gwt.client.Paintable; import com.vaadin.terminal.gwt.client.RenderInformation; import com.vaadin.terminal.gwt.client.RenderSpace; @@ -30,8 +43,10 @@ import com.vaadin.terminal.gwt.client.TooltipInfo; import com.vaadin.terminal.gwt.client.UIDL; import com.vaadin.terminal.gwt.client.Util; import com.vaadin.terminal.gwt.client.VCaption; +import com.vaadin.terminal.gwt.client.VConsole; -public class VTabsheet extends VTabsheetBase { +public class VTabsheet extends VTabsheetBase implements Focusable, + FocusHandler, BlurHandler, KeyDownHandler { private static class VCloseEvent { private Tab tab; @@ -54,7 +69,8 @@ public class VTabsheet extends VTabsheetBase { * Representation of a single "tab" shown in the TabBar * */ - private static class Tab extends SimplePanel { + private static class Tab extends SimplePanel implements HasFocusHandlers, + HasBlurHandlers, HasKeyDownHandlers { private static final String TD_CLASSNAME = CLASSNAME + "-tabitemcell"; private static final String TD_FIRST_CLASSNAME = TD_CLASSNAME + "-first"; @@ -94,6 +110,9 @@ public class VTabsheet extends VTabsheetBase { .getApplicationConnection()); add(tabCaption); + addFocusHandler(getTabsheet()); + addBlurHandler(getTabsheet()); + addKeyDownHandler(getTabsheet()); } public boolean isHiddenOnServer() { @@ -136,6 +155,9 @@ public class VTabsheet extends VTabsheetBase { * true if the Tab is the first visible Tab */ public void setStyleNames(boolean selected, boolean first) { + // TODO #5100 doesn't belong here + td.setAttribute("tabindex", selected ? "0" : "-1"); + setStyleName(td, TD_FIRST_CLASSNAME, first); setStyleName(td, TD_SELECTED_CLASSNAME, selected); setStyleName(td, TD_SELECTED_FIRST_CLASSNAME, selected && first); @@ -143,7 +165,10 @@ public class VTabsheet extends VTabsheetBase { } public void onClose() { + VConsole.log("OnClose"); + closeHandler.onClose(new VCloseEvent(this)); + VConsole.log("End OnClose"); } public VTabsheet getTabsheet() { @@ -179,6 +204,25 @@ public class VTabsheet extends VTabsheetBase { tabCaption.setWidth(tabCaption.getRequiredWidth() + "px"); } + public HandlerRegistration addFocusHandler(FocusHandler handler) { + return addDomHandler(handler, FocusEvent.getType()); + } + + public HandlerRegistration addBlurHandler(BlurHandler handler) { + return addDomHandler(handler, BlurEvent.getType()); + } + + public HandlerRegistration addKeyDownHandler(KeyDownHandler handler) { + return addDomHandler(handler, KeyDownEvent.getType()); + } + + public void focus() { + td.focus(); + } + + public void blur() { + td.blur(); + } } private static class TabCaption extends VCaption { @@ -296,7 +340,6 @@ public class VTabsheet extends VTabsheetBase { } return width; } - } static class TabBar extends ComplexPanel implements ClickHandler, @@ -362,6 +405,7 @@ public class VTabsheet extends VTabsheetBase { Widget caption = (Widget) event.getSource(); int index = getWidgetIndex(caption.getParent()); getTabsheet().onTabSelected(index); + getTabsheet().focus(); } public VTabsheet getTabsheet() { @@ -483,7 +527,6 @@ public class VTabsheet extends VTabsheetBase { currentFirst.recalculateCaptionWidth(); return nextVisible; } - } public static final String CLASSNAME = "v-tabsheet"; @@ -494,11 +537,15 @@ public class VTabsheet extends VTabsheetBase { // Can't use "style" as it's already in use public static final String TAB_STYLE_NAME = "tabstyle"; + private static final FocusImpl focusImpl = FocusImpl.getFocusImplForPanel(); + private final Element tabs; // tabbar and 'scroller' container private final Element scroller; // tab-scroller element private final Element scrollerNext; // tab-scroller next button element private final Element scrollerPrev; // tab-scroller prev button element + private Tab focusedTab; + /** * The index of the first visible tab (when scrolled) */ @@ -536,6 +583,12 @@ public class VTabsheet extends VTabsheetBase { } if (client != null && activeTabIndex != tabIndex) { tb.selectTab(tabIndex); + + if (focusedTab != null) { + focusedTab.blur(); + tb.getTab(tabIndex).focus(); + } + addStyleDependentName("loading"); // run updating variables in deferred command to bypass some FF // optimization issues @@ -581,6 +634,9 @@ public class VTabsheet extends VTabsheetBase { public VTabsheet() { super(CLASSNAME); + addHandler(this, FocusEvent.getType()); + addHandler(this, BlurEvent.getType()); + // Tab scrolling DOM.setStyleAttribute(getElement(), "overflow", "hidden"); tabs = DOM.createDiv(); @@ -694,8 +750,13 @@ public class VTabsheet extends VTabsheetBase { updateOpenTabSize(); } - iLayout(); + // If a tab was focused before, focus the new active tab + if (focusedTab != null && tb.getTabCount() > 0) { + focusedTab = tb.getTab(activeTabIndex); + focusedTab.focus(); + } + iLayout(); // Re run relative size update to ensure optimal scrollbars // TODO isolate to situation that visible tab has undefined height try { @@ -923,9 +984,9 @@ public class VTabsheet extends VTabsheetBase { updateOpenTabSize(); VTabsheet.this.removeStyleDependentName("loading"); if (previousVisibleWidget != null) { - DOM.setStyleAttribute( - DOM.getParent(previousVisibleWidget.getElement()), - "visibility", ""); + // DOM.setStyleAttribute( + // DOM.getParent(previousVisibleWidget.getElement()), + // "visibility", ""); previousVisibleWidget = null; } } @@ -1214,4 +1275,53 @@ public class VTabsheet extends VTabsheetBase { } } + public void onBlur(BlurEvent event) { + focusedTab = null; + // TODO Auto-generated method stub + VConsole.log("BLUR " + event); + } + + public void onFocus(FocusEvent event) { + // TODO Auto-generated method stub + VConsole.log("FOCUS " + event); + if (event.getSource() instanceof Tab) { + focusedTab = (Tab) event.getSource(); + } + } + + public void focus() { + if (focusedTab == null) { + focusedTab = tb.getTab(activeTabIndex); + focusedTab.focus(); + } + } + + public void blur() { + if (focusedTab != null) { + focusedTab.blur(); + focusedTab = null; + } + } + + public void onKeyDown(KeyDownEvent event) { + if (event.getSource() instanceof Tab) { + VConsole.log("KEYDOWN"); + int keycode = event.getNativeEvent().getKeyCode(); + if (keycode == KeyCodes.KEY_LEFT) { + int newTabIndex = activeTabIndex == 0 ? tb.getTabCount() - 1 + : activeTabIndex - 1; + onTabSelected(newTabIndex); + activeTabIndex = newTabIndex; + } else if (keycode == KeyCodes.KEY_RIGHT) { + int newTabIndex = (activeTabIndex + 1) % tb.getTabCount(); + onTabSelected(newTabIndex); + activeTabIndex = newTabIndex; + } else if (keycode == KeyCodes.KEY_DELETE) { + VConsole.log("INDEX=" + activeTabIndex); + focusedTab.onClose(); + removeTab(activeTabIndex); + } + VConsole.log("tabindex -> " + activeTabIndex); + } + } } diff --git a/src/com/vaadin/ui/TabSheet.java b/src/com/vaadin/ui/TabSheet.java index a13c336943..1275eda69f 100644 --- a/src/com/vaadin/ui/TabSheet.java +++ b/src/com/vaadin/ui/TabSheet.java @@ -14,6 +14,10 @@ import java.util.HashSet; import java.util.Iterator; import java.util.Map; +import com.vaadin.event.FieldEvents.BlurEvent; +import com.vaadin.event.FieldEvents.BlurListener; +import com.vaadin.event.FieldEvents.FocusEvent; +import com.vaadin.event.FieldEvents.FocusListener; import com.vaadin.terminal.ErrorMessage; import com.vaadin.terminal.KeyMapper; import com.vaadin.terminal.PaintException; @@ -21,6 +25,7 @@ import com.vaadin.terminal.PaintTarget; import com.vaadin.terminal.Resource; import com.vaadin.terminal.gwt.client.ui.VTabsheet; import com.vaadin.terminal.gwt.server.CommunicationManager; +import com.vaadin.ui.Component.Focusable; import com.vaadin.ui.themes.Reindeer; import com.vaadin.ui.themes.Runo; @@ -55,7 +60,8 @@ import com.vaadin.ui.themes.Runo; */ @SuppressWarnings("serial") @ClientWidget(VTabsheet.class) -public class TabSheet extends AbstractComponentContainer { +public class TabSheet extends AbstractComponentContainer implements Focusable, + FocusListener, BlurListener { /** * List of component tabs (tab contents). In addition to being on this list, @@ -95,6 +101,8 @@ public class TabSheet extends AbstractComponentContainer { */ private CloseHandler closeHandler; + private int tabIndex; + /** * Constructs a new Tabsheet. Tabsheet is immediate by default, and the * default close handler removes the tab being closed. @@ -363,6 +371,10 @@ public class TabSheet extends AbstractComponentContainer { target.addAttribute("hidetabs", true); } + if (tabIndex != 0) { + target.addAttribute("tabindex", tabIndex); + } + target.startTag("tabs"); Collection<Component> orphaned = new HashSet<Component>(paintedTabs); @@ -1226,4 +1238,27 @@ public class TabSheet extends AbstractComponentContainer { return components.indexOf(tab.getComponent()); } + public void blur(BlurEvent event) { + // TODO Auto-generated method stub + + } + + public void focus(FocusEvent event) { + // TODO Auto-generated method stub + } + + @Override + public void focus() { + super.focus(); + } + + public int getTabIndex() { + return tabIndex; + } + + public void setTabIndex(int tabIndex) { + this.tabIndex = tabIndex; + requestRepaint(); + } + } |