3

我正在使用 GWT 2.5.0。

我已经为客户端验证反馈实现了一个自定义抽象基础小部件。我的问题与动态内联样式<select/><input type="text"/>小部件有关,尤其是在 Internet Explorer 中。

我无法让渲染在 Internet Explorer 8/9 上正确且一致地完成其工作。对于其他浏览器,如 Safari、Chrome、Opera、Firefox,我的 impl 功能完全符合我的要求。

基本上,对于待处理的有效输入,我希望上述小部件的背景为黄色,前景色(文本)为蓝色。

我正在使用此处提到的提示和技巧:https ://developers.google.com/web-toolkit/doc/latest/DevGuideIE9 。

我认为基本问题是我与不支持“事件冒泡”的 IE 发生冲突。请参阅GWT 中的“更改”浏览器事件。但我不知道如何解决它。

更新

看来我的实施可能会被扣为人质,直到

http://code.google.com/p/google-web-toolkit/issues/detail?id=7139 

是固定的。

这是我的基本抽象类。onBrowserEvent请注意和render方法中用于 Internet Explorer 的用户代理“hack” 。(如果有其他方法,请告诉我)。

public abstract class AbstractValidatableInputCell<E extends Element> extends AbstractInputCell<String, ValidationData> {

/**
 * The error message text, pop-up, callback, and position offsets -- error message will be displayed near a field that violated constraint.
 */
private String errorMessage;

private DecoratedPopupPanel errorMessagePopup;
private PopupPanel.PositionCallback popupPositionCallback;
private int popupPositionLeft;
private int popupPositionTop;


/**
 * Constructs a ValidatableInputCell that renders its text without HTML
 * markup.
 */
public AbstractValidatableInputCell(String... consumedEvents) {
    super(consumedEvents);
}


public void setErrorMessage(final String errorMessage) {
    this.errorMessage = SafeHtmlUtils.fromSafeConstant(errorMessage).asString();
}

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

    // Ignore events that don't target the input.
    final E input = getInputElement(parent);
    final Element target = event.getEventTarget().cast();
    if (!input.isOrHasChild(target)) {
        return;
    }

    final String eventType = event.getType();
    final Object key = context.getKey();
    ValidationData vd = getViewData(key);
    final boolean invalid = vd == null ? false : vd.isInvalid();


    if (BrowserEvents.CHANGE.equals(eventType)) {
        finishEditing(parent, value, key, valueUpdater);

    } else if (Window.Navigator.getUserAgent().contains("MSIE")
            && (event.getKeyCode() == KeyCodes.KEY_TAB)) { 
        finishEditing(parent, value, key, valueUpdater);
        getInputElement(parent).focus();

    } else if (BrowserEvents.KEYUP.equals(eventType)) {
        // Record keys as they are typed.
        if (vd == null) {
            vd = new ValidationData(value);
            setViewData(key, vd);
        }
        vd.setCurrentValue(getValue(input));

    } else if (BrowserEvents.MOUSEOVER.equals(eventType)) {
        if (invalid) {
            showErrorMessagePopup(parent);
        }

    } else if (BrowserEvents.MOUSEOUT.equals(eventType)) {
        if (invalid) {
            hideErrorMessagePopup();
        }
    }
}

protected void onFinishEditing(final String value, final E input, final Object key) {
    /*
     * If viewData is null, just paint the contents black. If it is non-null,
     * show the pending value and paint the contents red if they are known to
     * be invalid.
     */
    final ValidationData viewData = getViewData(key);
    final String pendingValue = viewData == null ? null : viewData.getCurrentValue();
    final boolean invalid = viewData == null ? false : viewData.isInvalid();

    String color;
    String backgroundColor;

    if (invalid) {
        color = App.INSTANCE.invalidCellInputTextColor();
        backgroundColor = App.INSTANCE.invalidCellInputTextBackgroundColor();
    } else if (pendingValue != null && !pendingValue.equals(value)) {
        color = App.INSTANCE.pendingCellInputTextColor();
        backgroundColor = App.INSTANCE.pendingCellInputTextBackgroundColor();
    } else {
        color = App.INSTANCE.defaultCellInputTextColor();
        backgroundColor = App.INSTANCE.defaultCellInputTextBackgroundColor();
    }

    // Mark cell as containing a pending change
    input.getStyle().setColor(color);
    input.getStyle().setBackgroundColor(backgroundColor);
}

private void showErrorMessagePopup(final Element parent) {
    errorMessagePopup = new DecoratedPopupPanel(true);
    final FlowPanel messageContainer = new FlowPanel();
    messageContainer.setWidth(App.INSTANCE.errorMessagePopupWidth());
    final Label messageTxt = new Label(errorMessage, true);
    messageTxt.setStyleName(UiResources.INSTANCE.style().error());
    messageContainer.add(messageTxt);
    errorMessagePopup.setWidget(messageContainer);

    final Node child = parent.getChild(0);
    final Element childElement = (Element) child;

    // Reposition the popup relative to input field
    popupPositionLeft = childElement.getAbsoluteLeft() - 15;
    popupPositionTop = childElement.getAbsoluteBottom() + 5;

    popupPositionCallback = new PopupPanel.PositionCallback() {

        @Override
        public void setPosition(final int offsetWidth, final int offsetHeight) {
            errorMessagePopup.setPopupPosition(popupPositionLeft, popupPositionTop);
        }
    };
    errorMessagePopup.setPopupPositionAndShow(popupPositionCallback);
}

private void hideErrorMessagePopup() {
    errorMessagePopup.hide();
}

@Override
public void render(final Context context, final String value, final SafeHtmlBuilder sb) {
    // Get the view data.
    final Object key = context.getKey();
    final ValidationData viewData = getViewData(key);

    final String pendingValue = viewData == null ? null : viewData.getCurrentValue();
    final boolean invalid = viewData == null ? false : viewData.isInvalid();

    String inputValue = value;
    if (pendingValue != null) {
        inputValue = pendingValue;
    }

    String color;
    String backgroundColor;

    if (invalid) {
        color = App.INSTANCE.invalidCellInputTextColor();
        backgroundColor = App.INSTANCE.invalidCellInputTextBackgroundColor();
    } else if (pendingValue != null) {
        color = App.INSTANCE.pendingCellInputTextColor();
        backgroundColor = App.INSTANCE.pendingCellInputTextBackgroundColor();
    } else {
        color = App.INSTANCE.defaultCellInputTextColor();
        backgroundColor = App.INSTANCE.defaultCellInputTextBackgroundColor();
    }

    // shame on you IE!
    if (Window.Navigator.getUserAgent().contains("MSIE") && viewData != null && !viewData.isPended() && !invalid) {
        color = App.INSTANCE.defaultCellInputTextColor();
        backgroundColor = App.INSTANCE.defaultCellInputTextBackgroundColor();
    }

    finishRender(inputValue, color, backgroundColor, sb);
}

protected abstract void finishRender(final String inputValue, final String color, final String backgroundColor, final SafeHtmlBuilder sb);

@Override
protected void finishEditing(final Element parent, final String value, final Object key,
        final ValueUpdater<String> valueUpdater) {
    final String newValue = getNewValue(parent);

    // Get the view data.
    ValidationData vd = getViewData(key);
    if (vd == null) {
        vd = new ValidationData(value);
        setViewData(key, vd);
    }
    vd.setCurrentValue(newValue);

    // Fire the value updater if the value has changed.
    if (valueUpdater != null && !vd.getCurrentValue().equals(vd.getLastValue())) {
        vd.setLastValue(newValue);
        valueUpdater.update(newValue);
    }

    onFinishEditing(value, getInputElement(parent), key);

    // Blur the element.
    super.finishEditing(parent, newValue, key, valueUpdater);
}

@Override
protected E getInputElement(final Element parent) {
    return super.getInputElement(parent).<E> cast();
}

protected abstract String getValue(E element);

protected abstract String getNewValue(Element parent);
}

这是一个示例子类(对于input):

public class ValidatableInputCell extends AbstractValidatableInputCell<InputElement> {

interface Template extends SafeHtmlTemplates {

    @Template("<input type=\"text\" value=\"{0}\" size=\"{1}\" style=\"color: {2}; background-color: {3}; display: block; text-align: right\"></input>")
    SafeHtml input(String value, String width, String color, String backgroundColor);
}

private static Template template;

private static final int DEFAULT_INPUT_SIZE = App.INSTANCE.defaultValidatableInputCellSize();

/**
 * Specifies the width, in characters, of the &lt;input&gt; element contained within this cell
 */
private int inputSize = DEFAULT_INPUT_SIZE;

/**
 * Constructs a ValidatableInputCell that renders its text without HTML
 * markup.
 */
public ValidatableInputCell() {
    // Since onBrowserEvent method is overridden, we must register all
    // events that handled in overridden method impl
    // Events below are added in
    // AbstractInputCell#getConsumedEventsImpl(Set<String> userEvents)
    super(BrowserEvents.CHANGE, BrowserEvents.KEYUP, BrowserEvents.MOUSEOVER, BrowserEvents.MOUSEOUT);
    if (template == null) {
        template = GWT.create(Template.class);
    }
}

public void setInputSize(final int inputSize) {
    this.inputSize = inputSize;
}


@Override
public void finishRender(final String inputValue, final String color, final String backgroundColor, final SafeHtmlBuilder sb) {
    sb.append(template.input(inputValue, String.valueOf(inputSize), color, backgroundColor));
}

@Override
protected String getValue(InputElement element) {
    return element.getValue();
}

@Override
protected String getNewValue(Element parent) {
    return getValue(getInputElement(parent));
}


}

这是另一个示例子类(for select):

public class ReferenceDataBackedSelectionCell extends AbstractValidatableInputCell<SelectElement> {

interface SelectTemplate extends SafeHtmlTemplates {
    @Template("<select style=\"color: {0}; background-color: {1};\">")
    SafeHtml select(String color, String backgroundColor);
}

interface OptionTemplate extends SafeHtmlTemplates {

    @Template("<option style=\"color: {2}; background-color: {3}; text-align: right\" value=\"{0}\">{1}</option>")
    SafeHtml deselected(String optionSubmitValue, String optionDisplayValue, String color, String backgroundColor);

    @Template("<option style=\"color: {2}; background-color: {3}; text-align: right\" value=\"{0}\" selected=\"selected\">{1}</option>")
    SafeHtml selected(String optionSubmitValue, String optionDisplayValue, String color, String backgroundColor);
}

private static SelectTemplate selectTemplate; 
private static OptionTemplate optionTemplate;

private final Map<String, String> options;

/**
 * Construct a new {@link ReferenceDataBackedSelectionCell} from
 * {@link ReferenceData}.
 * 
 * @param refData data used to create the options in the cell
 */
public ReferenceDataBackedSelectionCell(final ReferenceData refData) {
    super(BrowserEvents.CHANGE);
    if (optionTemplate == null) {
        optionTemplate = GWT.create(OptionTemplate.class);
    }
    if (selectTemplate == null) {
        selectTemplate = GWT.create(SelectTemplate.class);
    }
    if (refData == null) {
        throw new IllegalArgumentException("Reference data for selection cell may not be null");
    }
    options = new LinkedHashMap<String, String>(refData.allData());
}

@Override
public void finishRender(final String inputValue, final String color, final String backgroundColor, final SafeHtmlBuilder sb) {
    final String selectedIndex = inputValue == null ? "" : inputValue;
    sb.append(selectTemplate.select(color, backgroundColor));
    String optionSubmitValue, optionDisplayValue = null;
    for (final Map.Entry<String, String> option : options.entrySet()) {
        optionSubmitValue = option.getValue();
        optionDisplayValue = option.getKey();
        if (optionSubmitValue.equals(selectedIndex)) {
            sb.append(optionTemplate.selected(optionSubmitValue, optionDisplayValue, color, backgroundColor));
        } else {
            sb.append(optionTemplate.deselected(optionSubmitValue, optionDisplayValue, color, backgroundColor));
        }
    }
    sb.appendHtmlConstant("</select>");
}

@Override
protected String getValue(SelectElement element) {
    return element.getValue();
}

@Override
protected String getNewValue(Element parent) {
    final SelectElement select = parent.getFirstChild().cast();
    final Collection<String> optionCollection = options.values();
    final String[] array = optionCollection.toArray(new String[optionCollection.size()]);
    final String newValue = array[select.getSelectedIndex()];
    return newValue;
}
} 
4

1 回答 1

0

我会尝试 CSS3,因为 IE9 对它有很好的支持。

测试样式.css

@charset "utf-8";
/* CSS Document */

INPUT[type="text"]:focus,
INPUT[type="number"]:focus,
INPUT[type="email"]:focus,
INPUT[type="search"]:focus,
INPUT[type="password"]:focus,
INPUT[type="range"]:focus
{
    outline: 1px solid #0033dd;
    background-color: grey;
    color: white;   
}  

测试.html

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Test</title>
<link rel="stylesheet" type="text/css" href="teststyle.css" />
</head>

<body>
 <input name="" type="text">
</body>
</html>

IE9截图

在此处输入图像描述

于 2013-03-25T03:49:22.400 回答