]> source.dussan.org Git - vaadin-framework.git/commitdiff
fixes #2931. Added own slightly modified History implementation for IE.
authorMatti Tahvonen <matti.tahvonen@itmill.com>
Wed, 29 Jul 2009 08:55:11 +0000 (08:55 +0000)
committerMatti Tahvonen <matti.tahvonen@itmill.com>
Wed, 29 Jul 2009 08:55:11 +0000 (08:55 +0000)
svn changeset:8419/svn branch:6.0

src/com/vaadin/terminal/gwt/DefaultWidgetSet.gwt.xml
src/com/vaadin/terminal/gwt/client/HistoryImplIEVaadin.java [new file with mode: 0644]

index eeae872b73b8d87d7c4277c9b7aa1509318ff309..23b281dc4f442af3db986b94f81d1fc85285f75a 100644 (file)
        <inherits name="com.google.gwt.json.JSON" />
 
        <source path="client" />
+       
+       <!-- Use our own history impl for IE to workaround #2931.       --> 
+       <replace-with class="com.vaadin.terminal.gwt.client.HistoryImplIEVaadin">
+               <when-type-is class="com.google.gwt.user.client.impl.HistoryImpl"/>
+               <when-property-is name="user.agent" value="ie6"/>
+       </replace-with>
 
        <entry-point class="com.vaadin.terminal.gwt.client.DefaultWidgetSet" />
 </module>
diff --git a/src/com/vaadin/terminal/gwt/client/HistoryImplIEVaadin.java b/src/com/vaadin/terminal/gwt/client/HistoryImplIEVaadin.java
new file mode 100644 (file)
index 0000000..7e56041
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2008 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.terminal.gwt.client;
+
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.impl.HistoryImpl;
+
+/**
+ * A slightly modified version of GWT's HistoryImplIE6 to bypass bug #2931. Also
+ * combined with HistoryImplFrame.
+ * 
+ * This class should be removed if GWT issue 3890 gets resolved. (Also remember
+ * to removed deferred binding rule from .gwt.xml file).
+ */
+public class HistoryImplIEVaadin extends HistoryImpl {
+
+    private static native Element findHistoryFrame()
+    /*-{
+        return $doc.getElementById('__gwt_historyFrame');
+    }-*/;
+
+    private static native Element getTokenElement(Element historyFrame)
+    /*-{
+       // Initialize the history iframe.  If '__gwt_historyToken' already exists, then
+       // we're probably backing into the app, so _don't_ set the iframe's location.
+       if (historyFrame.contentWindow) {
+           var doc = historyFrame.contentWindow.document;
+           return doc.getElementById('__gwt_historyToken');
+       }
+    }-*/;
+
+    protected Element historyFrame;
+
+    @Override
+    protected final void nativeUpdate(String historyToken) {
+        /*
+         * Must update the location hash since it isn't already correct.
+         */
+        updateHash(historyToken);
+        navigateFrame(historyToken);
+    }
+
+    @Override
+    protected final void nativeUpdateOnEvent(String historyToken) {
+        updateHash(historyToken);
+    }
+
+    /**
+     * Sanitizes an untrusted string to be used in an HTML context. NOTE: This
+     * method of escaping strings should only be used on Internet Explorer.
+     * 
+     * @param maybeHtml
+     *            untrusted string that may contain html
+     * @return sanitized string
+     */
+    @SuppressWarnings("unused")
+    private static String escapeHtml(String maybeHtml) {
+        final Element div = DOM.createDiv();
+        DOM.setInnerText(div, maybeHtml);
+        return DOM.getInnerHTML(div);
+    }
+
+    /**
+     * For IE6, reading from $wnd.location.hash drops part of the fragment if
+     * the fragment contains a '?'. To avoid this bug, we use location.href
+     * instead.
+     */
+    @SuppressWarnings("unused")
+    private static native String getLocationHash()
+    /*-{
+       var href = $wnd.location.href;
+       var hashLoc = href.lastIndexOf("#");
+       return (hashLoc > 0) ? href.substring(hashLoc) : "";
+    }-*/;
+
+    @Override
+    public boolean init() {
+        historyFrame = findHistoryFrame();
+        if (historyFrame == null) {
+            return false;
+        }
+
+        initHistoryToken();
+
+        // Initialize the history iframe. If a token element already exists,
+        // then
+        // we're probably backing into the app, so _don't_ create a new item.
+        Element tokenElement = getTokenElement(historyFrame);
+        if (tokenElement != null) {
+            setToken(getTokenElementContent(tokenElement));
+        } else {
+            navigateFrame(getToken());
+        }
+
+        injectGlobalHandler();
+
+        initUrlCheckTimer();
+        return true;
+    }
+
+    protected native String getTokenElementContent(Element tokenElement)
+    /*-{
+        return tokenElement.innerText;
+    }-*/;
+
+    protected native void initHistoryToken()
+    /*-{
+       // Assume an empty token.
+       var token = '';
+       // Get the initial token from the url's hash component.
+       var hash = @com.vaadin.terminal.gwt.client.HistoryImplIEVaadin::getLocationHash()();
+       if (hash.length > 0) {
+         try {
+           token = this.@com.google.gwt.user.client.impl.HistoryImpl::decodeFragment(Ljava/lang/String;)(hash.substring(1));
+         } catch (e) {
+           // Clear the bad hash (this can't have been a valid token).
+           $wnd.location.hash = '';
+         }
+       }
+       @com.google.gwt.user.client.impl.HistoryImpl::setToken(Ljava/lang/String;)(token);
+     }-*/;
+
+    protected native void injectGlobalHandler()
+    /*-{
+       var historyImplRef = this;
+
+       $wnd.__gwt_onHistoryLoad = function(token) {
+         historyImplRef.@com.google.gwt.user.client.impl.HistoryImpl::newItemOnEvent(Ljava/lang/String;)(token);
+       };
+     }-*/;
+
+    protected native void navigateFrame(String token)
+    /*-{
+       var escaped = @com.vaadin.terminal.gwt.client.HistoryImplIEVaadin::escapeHtml(Ljava/lang/String;)(token);
+       var doc = this.@com.vaadin.terminal.gwt.client.HistoryImplIEVaadin::historyFrame.contentWindow.document;
+       doc.open();
+       doc.write('<html><body onload="if(parent.__gwt_onHistoryLoad)parent.__gwt_onHistoryLoad(__gwt_historyToken.innerText)"><div id="__gwt_historyToken">' + escaped + '</div></body></html>');
+       doc.close();
+     }-*/;
+
+    protected native void updateHash(String token)
+    /*-{
+       $wnd.location.hash = this.@com.google.gwt.user.client.impl.HistoryImpl::encodeFragment(Ljava/lang/String;)(token);
+     }-*/;
+
+    private native void initUrlCheckTimer()
+    /*-{
+       // This is the URL check timer.  It detects when an unexpected change
+       // occurs in the document's URL (e.g. when the user enters one manually
+       // or selects a 'favorite', but only the #hash part changes).  When this
+       // occurs, we _must_ reload the page.  This is because IE has a really
+       // nasty bug that totally mangles its history stack and causes the location
+       // bar in the UI to stop working under these circumstances.
+       var historyImplRef = this;
+       var urlChecker = function() {
+         $wnd.setTimeout(urlChecker, 250);
+         var hash = @com.vaadin.terminal.gwt.client.HistoryImplIEVaadin::getLocationHash()();
+         if (hash.length > 0) {
+           var token = '';
+           try {
+             token = historyImplRef.@com.google.gwt.user.client.impl.HistoryImpl::decodeFragment(Ljava/lang/String;)(hash.substring(1));
+           } catch (e) {
+             // If there's a bad hash, always reload. This could only happen if
+             // if someone entered or linked to a bad url.
+             $wnd.location.reload();
+           }
+
+           var historyToken = @com.google.gwt.user.client.impl.HistoryImpl::getToken()();
+           if (token != historyToken) {
+             $wnd.location.reload();
+           }
+         }
+       };
+       urlChecker();
+     }-*/;
+
+}