--- /dev/null
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.connectors;
+
+import com.google.gwt.event.dom.client.HasAllFocusHandlers;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.client.ui.ConnectorFocusAndBlurHandler;
+import com.vaadin.shared.data.selection.SelectionModel;
+
+/**
+ * Abstract class for listing widget connectors that contains focusable children
+ * to track their focus/blur events.
+ *
+ * @author Vaadin Ltd
+ *
+ * @param <WIDGET>
+ * widget type which has to allow to register focus/blur handlers
+ * @param <SELECTIONMODEL>
+ * the client-side selection model type
+ */
+public abstract class AbstractFocusableListingConnector<WIDGET extends Widget & HasAllFocusHandlers, SELECTIONMODEL extends SelectionModel<?>>
+ extends AbstractListingConnector<SELECTIONMODEL> {
+
+ private ConnectorFocusAndBlurHandler handler;
+
+ @Override
+ protected void init() {
+ handler = ConnectorFocusAndBlurHandler.addHandlers(this);
+ }
+
+ @Override
+ public void onUnregister() {
+ super.onUnregister();
+ handler.removeHandlers();
+ handler = null;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public WIDGET getWidget() {
+ return (WIDGET) super.getWidget();
+ }
+}
import java.util.function.BiConsumer;
import com.google.gwt.aria.client.Roles;
-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.FocusHandler;
-import com.google.gwt.event.dom.client.HasAllFocusHandlers;
-import com.google.gwt.event.shared.HandlerRegistration;
-import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FocusWidget;
import com.google.gwt.user.client.ui.HasEnabled;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.ApplicationConnection;
import com.vaadin.client.WidgetUtil;
-import com.vaadin.client.widgets.ChildFocusAwareFlowPanel;
+import com.vaadin.client.widgets.FocusableFlowPanelComposite;
import com.vaadin.shared.Registration;
import com.vaadin.shared.ui.ListingJsonConstants;
* @author Vaadin Ltd.
* @since 8.0
*/
-public class VCheckBoxGroup extends Composite implements Field, ClickHandler,
- com.vaadin.client.Focusable, HasEnabled, HasAllFocusHandlers {
+public class VCheckBoxGroup extends FocusableFlowPanelComposite implements
+ Field, ClickHandler, com.vaadin.client.Focusable, HasEnabled {
public static final String CLASSNAME = "v-select-optiongroup";
public static final String CLASSNAME_OPTION = "v-select-option";
*/
public ApplicationConnection client;
- /**
- * Widget holding the different options (e.g. ListBox or Panel for radio
- * buttons) (optional, fallbacks to container Panel)
- * <p>
- * For internal use only. May be removed or replaced in the future.
- */
- private ChildFocusAwareFlowPanel optionsContainer;
-
private boolean htmlContentAllowed = false;
private boolean enabled;
private List<BiConsumer<JsonObject, Boolean>> selectionChangeListeners;
public VCheckBoxGroup() {
- optionsContainer = new ChildFocusAwareFlowPanel();
- initWidget(optionsContainer);
- optionsContainer.setStyleName(CLASSNAME);
+ getWidget().setStyleName(CLASSNAME);
optionsToItems = new HashMap<>();
selectionChangeListeners = new ArrayList<>();
}
public void buildOptions(List<JsonObject> items) {
Roles.getGroupRole().set(getElement());
int i = 0;
- int widgetsToRemove = optionsContainer.getWidgetCount() - items.size();
+ int widgetsToRemove = getWidget().getWidgetCount() - items.size();
if (widgetsToRemove < 0) {
widgetsToRemove = 0;
}
List<Widget> remove = new ArrayList<>(widgetsToRemove);
- for (Widget widget : optionsContainer) {
+ for (Widget widget : getWidget()) {
if (i < items.size()) {
updateItem((VCheckBox) widget, items.get(i), false);
i++;
}
private void remove(Widget widget) {
- optionsContainer.remove(widget);
+ getWidget().remove(widget);
optionsToItems.remove(widget);
}
if (requireInitializations) {
widget.addStyleName(CLASSNAME_OPTION);
widget.addClickHandler(this);
- optionsContainer.add(widget);
+ getWidget().add(widget);
}
optionsToItems.put(widget, item);
}
}
public void setTabIndex(int tabIndex) {
- for (Widget anOptionsContainer : optionsContainer) {
+ for (Widget anOptionsContainer : getWidget()) {
FocusWidget widget = (FocusWidget) anOptionsContainer;
widget.setTabIndex(tabIndex);
}
@Override
public void focus() {
- optionsContainer.focus();
+ getWidget().focus();
}
public boolean isHtmlContentAllowed() {
.remove(selectionChanged);
}
- @Override
- public HandlerRegistration addFocusHandler(FocusHandler handler) {
- return optionsContainer.addFocusHandler(handler);
- }
-
- @Override
- public HandlerRegistration addBlurHandler(BlurHandler handler) {
- return optionsContainer.addBlurHandler(handler);
- }
}
import java.util.Objects;
-import com.google.gwt.user.client.ui.Composite;
-import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.event.dom.client.HasAllFocusHandlers;
import com.google.gwt.user.client.ui.ListBox;
+import com.vaadin.client.widgets.FocusableFlowPanelComposite;
/**
* The client-side widget for the {@code NativeSelect} component.
*
* @author Vaadin Ltd.
*/
-public class VNativeSelect extends Composite {
+public class VNativeSelect extends FocusableFlowPanelComposite
+ implements HasAllFocusHandlers {
private final ListBox listBox = new ListBox();
* Creates a new {@code VNativeSelect} instance.
*/
public VNativeSelect() {
- FlowPanel panel = new FlowPanel();
- panel.add(listBox);
- initWidget(panel);
+ getWidget().add(listBox);
}
/**
import com.google.gwt.event.shared.HandlerRegistration;
import com.vaadin.client.annotations.OnStateChange;
-import com.vaadin.client.connectors.AbstractListingConnector;
+import com.vaadin.client.connectors.AbstractFocusableListingConnector;
import com.vaadin.client.data.DataSource;
import com.vaadin.client.ui.VNativeSelect;
import com.vaadin.shared.Range;
* @since 8.0
*/
@Connect(com.vaadin.ui.NativeSelect.class)
-public class NativeSelectConnector
- extends AbstractListingConnector<SelectionModel.Single<?>> {
+public class NativeSelectConnector extends
+ AbstractFocusableListingConnector<VNativeSelect, SelectionModel.Single<?>> {
private HandlerRegistration selectionChangeRegistration;
private Registration dataChangeRegistration;
selectionChangeRegistration = null;
}
- @Override
- public VNativeSelect getWidget() {
- return (VNativeSelect) super.getWidget();
- }
-
@Override
public void setDataSource(DataSource<JsonObject> dataSource) {
if (dataChangeRegistration != null) {
import java.util.List;
import com.vaadin.client.communication.StateChangeEvent;
-import com.vaadin.client.connectors.AbstractListingConnector;
+import com.vaadin.client.connectors.AbstractFocusableListingConnector;
import com.vaadin.client.data.DataSource;
-import com.vaadin.client.ui.ConnectorFocusAndBlurHandler;
import com.vaadin.client.ui.VCheckBoxGroup;
import com.vaadin.shared.data.selection.MultiSelectServerRpc;
import com.vaadin.shared.data.selection.SelectionModel;
@Connect(CheckBoxGroup.class)
// We don't care about the framework-provided selection model at this point
-public class CheckBoxGroupConnector
- extends AbstractListingConnector<SelectionModel<?>> {
-
- private ConnectorFocusAndBlurHandler handler;
+public class CheckBoxGroupConnector extends
+ AbstractFocusableListingConnector<VCheckBoxGroup, SelectionModel<?>> {
@Override
protected void init() {
super.init();
getWidget().addSelectionChangeHandler(this::selectionChanged);
- handler = ConnectorFocusAndBlurHandler.addHandlers(this);
- }
-
- @Override
- public void onUnregister() {
- super.onUnregister();
- handler.removeHandlers();
- handler = null;
}
private void selectionChanged(JsonObject changedItem, Boolean selected) {
getWidget().buildOptions(items);
}
- @Override
- public VCheckBoxGroup getWidget() {
- return (VCheckBoxGroup) super.getWidget();
- }
-
@Override
public CheckBoxGroupState getState() {
return (CheckBoxGroupState) super.getState();
--- /dev/null
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.widgets;
+
+import com.google.gwt.event.dom.client.BlurHandler;
+import com.google.gwt.event.dom.client.FocusHandler;
+import com.google.gwt.event.dom.client.HasAllFocusHandlers;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.user.client.ui.Composite;
+
+/**
+ * Focusable composite whose widget is {@link ChildFocusAwareFlowPanel} (flow
+ * panel that tracks focus/blur events from its children).
+ *
+ * @author Vaadin Ltd
+ *
+ */
+public abstract class FocusableFlowPanelComposite extends Composite
+ implements HasAllFocusHandlers {
+
+ private final ChildFocusAwareFlowPanel panel;
+
+ /**
+ * Creates a new instance.
+ */
+ protected FocusableFlowPanelComposite() {
+ panel = new ChildFocusAwareFlowPanel();
+ initWidget(panel);
+ }
+
+ @Override
+ protected final ChildFocusAwareFlowPanel getWidget() {
+ return (ChildFocusAwareFlowPanel) super.getWidget();
+ }
+
+ @Override
+ public HandlerRegistration addFocusHandler(FocusHandler handler) {
+ return panel.addFocusHandler(handler);
+ }
+
+ @Override
+ public HandlerRegistration addBlurHandler(BlurHandler handler) {
+ return panel.addBlurHandler(handler);
+ }
+}
import java.util.Collection;
+import com.vaadin.event.FieldEvents.BlurEvent;
+import com.vaadin.event.FieldEvents.BlurListener;
+import com.vaadin.event.FieldEvents.BlurNotifier;
+import com.vaadin.event.FieldEvents.FocusAndBlurServerRpcDecorator;
+import com.vaadin.event.FieldEvents.FocusEvent;
+import com.vaadin.event.FieldEvents.FocusListener;
+import com.vaadin.event.FieldEvents.FocusNotifier;
import com.vaadin.server.data.DataSource;
+import com.vaadin.shared.Registration;
import com.vaadin.shared.data.DataCommunicatorConstants;
import com.vaadin.shared.ui.nativeselect.NativeSelectState;
*
* @see com.vaadin.ui.ComboBox
*/
-public class NativeSelect<T> extends AbstractSingleSelect<T> {
+public class NativeSelect<T> extends AbstractSingleSelect<T>
+ implements FocusNotifier, BlurNotifier {
/**
* Creates a new {@code NativeSelect} with an empty caption and no items.
*/
public NativeSelect() {
- addDataGenerator((item, json) -> json.put(
- DataCommunicatorConstants.DATA, String.valueOf(item)));
+ registerRpc(new FocusAndBlurServerRpcDecorator(this, this::fireEvent));
+ addDataGenerator((item, json) -> json
+ .put(DataCommunicatorConstants.DATA, String.valueOf(item)));
setSelectionModel(new SimpleSingleSelection());
}
setDataSource(dataSource);
}
+ @Override
+ public Registration addFocusListener(FocusListener listener) {
+ addListener(FocusEvent.EVENT_ID, FocusEvent.class, listener,
+ FocusListener.focusMethod);
+ return () -> removeListener(FocusEvent.EVENT_ID, FocusEvent.class,
+ listener);
+ }
+
+ @Override
+ @Deprecated
+ public void removeFocusListener(FocusListener listener) {
+ removeListener(FocusEvent.EVENT_ID, FocusEvent.class, listener);
+ }
+
+ @Override
+ public Registration addBlurListener(BlurListener listener) {
+ addListener(BlurEvent.EVENT_ID, BlurEvent.class, listener,
+ BlurListener.blurMethod);
+ return () -> removeListener(BlurEvent.EVENT_ID, BlurEvent.class,
+ listener);
+ }
+
+ @Override
+ @Deprecated
+ public void removeBlurListener(BlurListener listener) {
+ removeListener(BlurEvent.EVENT_ID, BlurEvent.class, listener);
+ }
+
@Override
protected NativeSelectState getState() {
return getState(true);
--- /dev/null
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.tests.components.nativeselect;
+
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUIWithLog;
+import com.vaadin.ui.NativeSelect;
+
+/**
+ * @author Vaadin Ltd
+ *
+ */
+public class NativeSelectFocusBlur extends AbstractTestUIWithLog {
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ NativeSelect<Integer> select = new NativeSelect<>();
+ select.setItems(IntStream.range(1, 10).mapToObj(Integer::valueOf)
+ .collect(Collectors.toList()));
+
+ addComponent(select);
+ select.addFocusListener(event -> log("Focus Event"));
+ select.addBlurListener(event -> log("Blur Event"));
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.tests.components.nativeselect;
+
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.openqa.selenium.Keys;
+
+import com.vaadin.testbench.TestBenchElement;
+import com.vaadin.testbench.customelements.NativeSelectElement;
+import com.vaadin.testbench.elements.LabelElement;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+/**
+ * @author Vaadin Ltd
+ *
+ */
+public class NativeSelectFocusBlurTest extends MultiBrowserTest {
+
+ @Test
+ public void focusBlurEvents() {
+ openTestURL();
+
+ NativeSelectElement nativeSelect = $(NativeSelectElement.class).first();
+ nativeSelect.click();
+
+ // Focus event is fired
+ Assert.assertTrue(logContainsText("1. Focus Event"));
+
+ List<TestBenchElement> options = nativeSelect.getOptions();
+ options.get(1).click();
+ // No any new event
+ Assert.assertFalse(logContainsText("2."));
+
+ // click on log label => blur
+ $(LabelElement.class).first().click();
+ // blur event is fired
+ Assert.assertTrue(logContainsText("2. Blur Event"));
+
+ nativeSelect.click();
+ // Focus event is fired
+ Assert.assertTrue(logContainsText("3. Focus Event"));
+
+ options.get(1).sendKeys(Keys.ARROW_UP, Keys.ENTER);
+ // No any new event
+ Assert.assertFalse(logContainsText("4."));
+ }
+}