@Override
    public void onBrowserEvent(final Context context, final Element parent, final Number value, final NativeEvent event,
                               final ValueUpdater<Number> valueUpdater) {
        super.onBrowserEvent(context, parent, value, event, valueUpdater);

        // Get the target element.
        final Element target = event.getEventTarget().cast();

        final String eventType = event.getType();
        if ("focus".equals(eventType)) {
            // Ignore change events that don't target the input.
            final InputElement input = getInputElement(parent);
            if (input == null || !input.isOrHasChild(target)) {
                return;
            }

            focusedKey = context.getKey();

        } else if ("blur".equals(eventType)) {
            // Ignore change events that don't target the input.
            final InputElement input = getInputElement(parent);
            if (input == null || !input.isOrHasChild(target)) {
                return;
            }

            focusedKey = null;

        } else if ("change".equals(eventType)) {
            // Ignore change events that don't target the input.
            final InputElement input = getInputElement(parent);
            if (input == null || !input.isOrHasChild(target)) {
                return;
            }

            // The input has changed so finish editing.
            finishEditing(parent, value, context.getKey(), valueUpdater);

        } else if ("keyup".equals(eventType)) {
            // Ignore key up events that don't target the input.
            final InputElement input = getInputElement(parent);
            if (input == null || !input.isOrHasChild(target)) {
                return;
            }

            // Record keys as they are typed.
            final Object key = context.getKey();
            ViewData vd = getViewData(key);
            if (vd == null) {
                vd = new ViewData(String.valueOf(value));
                setViewData(key, vd);
            }

            vd.setCurrentValue(input.getValue());

        } else {
            final Element upArrow = getByClassName(parent, "valueSpinner-arrowUp");
            final Element downArrow = getByClassName(parent, "valueSpinner-arrowDown");

            if (upArrow != null && upArrow.isOrHasChild(target)) {
                if (BrowserEvents.MOUSEOVER.equals(eventType)) {
                    upArrow.setClassName("valueSpinner-arrow valueSpinner-arrowUp valueSpinner-arrowUp--hover");

                } else if (BrowserEvents.MOUSEOUT.equals(eventType)) {
                    upArrow.setClassName("valueSpinner-arrow valueSpinner-arrowUp");
                    stopSpinning(context, parent, value, valueUpdater);

                } else if (BrowserEvents.MOUSEUP.equals(eventType)) {
                    upArrow.setClassName("valueSpinner-arrow valueSpinner-arrowUp valueSpinner-arrowUp--hover");
                    stopSpinning(context, parent, value, valueUpdater);

                } else if (BrowserEvents.MOUSEDOWN.equals(eventType)) {
                    upArrow.setClassName("valueSpinner-arrow valueSpinner-arrowUp valueSpinner-arrowUp--pressed");
                    ensureSpinner();

                    // Get the object that we are going to use to apply
                    // value constraints.
                    HasSpinnerConstraints constraints = this;
                    if (value instanceof HasSpinnerConstraints) {
                        constraints = (HasSpinnerConstraints) value;
                    }

                    final InputElement input = getInputElement(parent);
                    if (input == null) {
                        spinner.start(constraints, true, 0, input);
                    } else {
                        final String constrainedValue = constrainValue(constraints, input.getValue());
                        spinner.start(constraints, true, Long.parseLong(constrainedValue), input);
                    }
                }
            } else if (downArrow != null && downArrow.isOrHasChild(target)) {
                if (BrowserEvents.MOUSEOVER.equals(eventType)) {
                    downArrow.setClassName("valueSpinner-arrow valueSpinner-arrowDown valueSpinner-arrowDown--hover");

                } else if (BrowserEvents.MOUSEOUT.equals(eventType)) {
                    downArrow.setClassName("valueSpinner-arrow valueSpinner-arrowDown");
                    stopSpinning(context, parent, value, valueUpdater);

                } else if (BrowserEvents.MOUSEUP.equals(eventType)) {
                    downArrow.setClassName("valueSpinner-arrow valueSpinner-arrowDown valueSpinner-arrowDown--hover");
                    stopSpinning(context, parent, value, valueUpdater);

                } else if (BrowserEvents.MOUSEDOWN.equals(eventType)) {
                    downArrow.setClassName("valueSpinner-arrow valueSpinner-arrowDown valueSpinner-arrowDown--pressed");
                    ensureSpinner();

                    // Get the object that we are going to use to apply
                    // value constraints.
                    HasSpinnerConstraints constraints = this;
                    if (value instanceof HasSpinnerConstraints) {
                        constraints = (HasSpinnerConstraints) value;
                    }

                    final InputElement input = getInputElement(parent);
                    final String constrainedValue = constrainValue(constraints, input.getValue());
                    spinner.start(constraints, false, Long.parseLong(constrainedValue), input);
                }
            }
        }
    }
The currently focused value key. Only one key can be focused at any time.
stroom-core-client-widget/src/main/java/stroom/cell/valuespinner/client/ValueSpinnerCell.java