UI IE 8 Support

A reasonable, transparent IE8 support can be achieved in a Wicket application the following way.

Obviously, you’ll still run into slowdowns, bugs and limitations due to IE8 being IE8. But the most visible issues will be gone.

1. Add IE8-specific CSS

Put these files beside your StylesLessCssResourceReference.java:

IE8AndLesserLessCssResourceReference.java:

public final class IE8AndLesserLessCssResourceReference extends LessCssResourceReference {

    private static final long serialVersionUID = 4656765761895221782L;

    private static final IE8AndLesserLessCssResourceReference INSTANCE = new IE8AndLesserLessCssResourceReference();

    private IE8AndLesserLessCssResourceReference() {
        super(IE8AndLesserLessCssResourceReference.class, "ie8-and-lesser.less");
    }

    public static IE8AndLesserLessCssResourceReference get() {
        return INSTANCE;
    }

}

ie8-and-lesser.less:

@import "@{scope-core-bs3}bootstrap/variables.less";
@import "@{scope-core-bs3}bootstrap/override/variables.less";
@import "variables.less";

.placeholder { // Added by the "placeholder" jquery polyfill plugin. See jquery.placeholder.js
    color: @input-color-placeholder;
}

.btn-icon-only.btn-placeholder, .btn-placeholder {
    visibility: hidden;
}

/* Put any IE8-specific CSS here */

2. Add global listeners

Add this in your Wicket Application’s init method:

IELegacySupport.init(this);

With IELegacySupport.java being:

public final class IELegacySupport {

    private IELegacySupport() {
    }

    public static final String IE_LEGACY_CONDITION = "lte IE 8";

    public static final String IE_UNSUPPORTED_CONDITION = "lt IE 8";

    public static final String IE_8_CONDITION = "IE 8";

    public static final int IE_LEGACY_VERSION = 8;

    public static void init(WebApplication webApplication) {
        webApplication.getComponentInstantiationListeners().add(new InstantiationListener());
        webApplication.getAjaxRequestTargetListeners().add(new AjaxRequestTargetListener());
    }

    private static class IELegacyHeaderItemsContributorBehavior extends Behavior {

        private static final long serialVersionUID = -1441191136903604013L;

        private final Iterable<HeaderItem> headerItems;

        public IELegacyHeaderItemsContributorBehavior(HeaderItem ... headerItems) {
            this(ImmutableList.copyOf(headerItems));
        }

        public IELegacyHeaderItemsContributorBehavior(Iterable<HeaderItem> headerItems) {
            super();
            this.headerItems = headerItems;
        }

        @Override
        public void renderHead(Component component, IHeaderResponse response) {
            WebClientInfo clientInfo = (WebClientInfo) Session.get().getClientInfo();
            ClientProperties properties = clientInfo.getProperties();
            if (properties.isBrowserInternetExplorer() && properties.getBrowserVersionMajor() <= IE_LEGACY_VERSION) {
                for(HeaderItem headerItem : headerItems) {
                    response.render(headerItem);
                }
            }
        }
    }

    private static class InstantiationListener implements IComponentInstantiationListener {
        @Override
        public void onInstantiation(Component component) {
            if (component instanceof Page) {
                Page page = (Page) component;

                // Support for the placeholder text of input fields in IE8 and lesser
                page.add(new PlaceholderPolyfillBehavior());

                page.add(new IELegacyHeaderItemsContributorBehavior(
                        // Support for media queries in IE8 and lesser
                        JavaScriptHeaderItem.forReference(RespondJavaScriptResourceReference.get()),
                        // IE8 and lesser specific CSS
                        CssHeaderItem.forReference(IE8AndLesserLessCssResourceReference.get())
                ));
            }
        }
    }

    private static class AjaxRequestTargetListener extends AjaxRequestTarget.AbstractListener {
        @Override
        public void updateAjaxAttributes(AbstractDefaultAjaxBehavior behavior, AjaxRequestAttributes attributes) {
            WebClientInfo clientInfo = (WebClientInfo) Session.get().getClientInfo();
            ClientProperties properties = clientInfo.getProperties();
            if (properties.isBrowserInternetExplorer() && properties.getBrowserVersionMajor() <= IE_LEGACY_VERSION) {
                attributes.getAjaxCallListeners().add(
                        new AjaxCallListener().onBefore(
                                // Prevents placeholder text from being submitted
                                PlaceholderPolyfillBehavior.disable().render()
                        )
                );
            }
        }

        @Override
        public void onBeforeRespond(Map<String, Component> map, AjaxRequestTarget target) {
            // Refresh the placeholder text (for instance when rendering a popup)
            target.appendJavaScript(PlaceholderPolyfillBehavior.statement().render());
        }

        @Override
        public void onAfterRespond(Map<String, Component> map, IJavaScriptResponse response) {
            // Nothing to do
        }
    }

}