私はGWT2.5.0を使用しています。
クライアント側の検証フィードバック用にカスタムの抽象ベースウィジェットを実装しました。私の質問は、特にInternetExplorerでのウィジェット<select/>
の動的なインラインスタイリングに関連しています。<input type="text"/>
InternetExplorer8/9でレンダリングを適切かつ一貫して実行させることができません。Safari、Chrome、Opera、Firefoxなどの他のブラウザの場合、私のimplは希望どおりに機能します。
基本的に、保留中の有効な入力の場合、前述のウィジェットの背景を黄色にし、前景色(テキスト)を青にします。
ここに記載されているヒントとコツを使用しています:https ://developers.google.com/web-toolkit/doc/latest/DevGuideIE9 。
基本的な問題は、「イベントバブリング」をサポートしていないIEに反抗していることだと思います。GWTの「Change」ブラウザイベントを参照してください。しかし、私はそれに対処する方法がわかりません。
アップデート
私の実装は、まで人質にされる可能性があるようです
http://code.google.com/p/google-web-toolkit/issues/detail?id=7139
固定されています。
これが私の基本抽象クラスです。onBrowserEvent
およびrender
メソッドでのInternetExplorerのユーザーエージェント「ハック」に注意してください。(他に方法がある場合は、お知らせください)。
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 <input> 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));
}
}
別のサンプルサブクラス(の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;
}
}