/*******************************************************************************
* Copyright (c) 2012-2017 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.ide.ui.popup;
import org.eclipse.che.ide.util.dom.Elements;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.event.dom.client.KeyCodes;
import elemental.dom.Element;
import elemental.events.Event;
import elemental.events.EventListener;
import elemental.events.KeyboardEvent;
public class PopupKeyDownListener implements EventListener {
/**
* The related opopup widget.
*/
private final PopupWidget<?> popupWidget;
/**
* The list element (contains the items).
*/
private final Element listElement;
public PopupKeyDownListener(final PopupWidget<?> popupWidget, final Element listElement) {
this.popupWidget = popupWidget;
this.listElement = listElement;
}
@Override
public void handleEvent(final Event evt) {
if (evt instanceof KeyboardEvent) {
final KeyboardEvent keyEvent = (KeyboardEvent) evt;
switch (keyEvent.getKeyCode()) {
case KeyCodes.KEY_ESCAPE:
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
@Override
public void execute() {
popupWidget.hide();
}
});
break;
case KeyCodes.KEY_DOWN:
focusNext();
break;
case KeyCodes.KEY_UP:
focusPrevious();
break;
case KeyCodes.KEY_HOME:
focusFirst();
break;
case KeyCodes.KEY_END:
focusLast();
break;
case KeyCodes.KEY_ENTER:
evt.preventDefault();
evt.stopImmediatePropagation();
validateItem();
break;
default:
}
}
}
/**
* Focus the next item in the list, or the first item if we are already at the last.
* In the case the list doesn't currently have focus, focus the first element.
*/
private void focusNext() {
final Element current = Elements.getDocument().getActiveElement();
if (current.getParentElement().isEqualNode(listElement)) {
final Element next = current.getNextElementSibling();
if (next != null) {
next.focus();
} else {
focusFirst();
}
} else {
// we don't actually have focus, focus the first element
focusFirst();
}
}
/**
* Focus the previous item in the list, or the last item if we are already at the first.
* In the case the list doesn't currently have focus, focus the first element.
*/
private void focusPrevious() {
final Element current = Elements.getDocument().getActiveElement();
if (current.getParentElement().isEqualNode(listElement)) {
final Element prev = current.getPreviousElementSibling();
if (prev != null) {
prev.focus();
} else {
focusLast();
}
} else {
// we don't actually have focus, focus the first element
focusFirst();
}
}
/**
* Focus the first item in the list (if any).
*/
private void focusFirst() {
if (this.listElement.hasChildNodes()) {
this.listElement.getFirstElementChild().focus();
}
}
/**
* Focus the last item in the list (if any).
*/
private void focusLast() {
if (this.listElement.hasChildNodes()) {
this.listElement.getLastElementChild().focus();
}
}
/**
* Activates the currently selected item.
*/
private void validateItem() {
final Element current = Elements.getDocument().getActiveElement();
if (current.getParentElement().isEqualNode(listElement)) {
this.popupWidget.validateItem(current);
}
}
}