You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

HistoryImplIEVaadin.java 6.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. /*
  2. @ITMillApache2LicenseForJavaFiles@
  3. */
  4. /*
  5. * Copyright 2008 Google Inc.
  6. *
  7. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  8. * use this file except in compliance with the License. You may obtain a copy of
  9. * the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  15. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  16. * License for the specific language governing permissions and limitations under
  17. * the License.
  18. */
  19. package com.vaadin.terminal.gwt.client;
  20. import com.google.gwt.user.client.DOM;
  21. import com.google.gwt.user.client.Element;
  22. import com.google.gwt.user.client.impl.HistoryImpl;
  23. /**
  24. * A slightly modified version of GWT's HistoryImplIE6 to bypass bug #2931. Also
  25. * combined with HistoryImplFrame.
  26. *
  27. * This class should be removed if GWT issue 3890 gets resolved. (Also remember
  28. * to removed deferred binding rule from .gwt.xml file).
  29. */
  30. public class HistoryImplIEVaadin extends HistoryImpl {
  31. private static native Element findHistoryFrame()
  32. /*-{
  33. return $doc.getElementById('__gwt_historyFrame');
  34. }-*/;
  35. private static native Element getTokenElement(Element historyFrame)
  36. /*-{
  37. // Initialize the history iframe. If '__gwt_historyToken' already exists, then
  38. // we're probably backing into the app, so _don't_ set the iframe's location.
  39. if (historyFrame.contentWindow) {
  40. var doc = historyFrame.contentWindow.document;
  41. return doc.getElementById('__gwt_historyToken');
  42. }
  43. }-*/;
  44. protected Element historyFrame;
  45. @Override
  46. protected final void nativeUpdate(String historyToken) {
  47. /*
  48. * Must update the location hash since it isn't already correct.
  49. */
  50. updateHash(historyToken);
  51. navigateFrame(historyToken);
  52. }
  53. @Override
  54. protected final void nativeUpdateOnEvent(String historyToken) {
  55. updateHash(historyToken);
  56. }
  57. /**
  58. * Sanitizes an untrusted string to be used in an HTML context. NOTE: This
  59. * method of escaping strings should only be used on Internet Explorer.
  60. *
  61. * @param maybeHtml
  62. * untrusted string that may contain html
  63. * @return sanitized string
  64. */
  65. @SuppressWarnings("unused")
  66. private static String escapeHtml(String maybeHtml) {
  67. final Element div = DOM.createDiv();
  68. DOM.setInnerText(div, maybeHtml);
  69. return DOM.getInnerHTML(div);
  70. }
  71. /**
  72. * For IE6, reading from $wnd.location.hash drops part of the fragment if
  73. * the fragment contains a '?'. To avoid this bug, we use location.href
  74. * instead.
  75. */
  76. @SuppressWarnings("unused")
  77. private static native String getLocationHash()
  78. /*-{
  79. var href = $wnd.location.href;
  80. var hashLoc = href.lastIndexOf("#");
  81. return (hashLoc > 0) ? href.substring(hashLoc) : "";
  82. }-*/;
  83. @Override
  84. public boolean init() {
  85. historyFrame = findHistoryFrame();
  86. if (historyFrame == null) {
  87. return false;
  88. }
  89. initHistoryToken();
  90. // Initialize the history iframe. If a token element already exists,
  91. // then
  92. // we're probably backing into the app, so _don't_ create a new item.
  93. Element tokenElement = getTokenElement(historyFrame);
  94. if (tokenElement != null) {
  95. setToken(getTokenElementContent(tokenElement));
  96. } else {
  97. navigateFrame(getToken());
  98. }
  99. injectGlobalHandler();
  100. initUrlCheckTimer();
  101. return true;
  102. }
  103. protected native String getTokenElementContent(Element tokenElement)
  104. /*-{
  105. return tokenElement.innerText;
  106. }-*/;
  107. protected native void initHistoryToken()
  108. /*-{
  109. // Assume an empty token.
  110. var token = '';
  111. // Get the initial token from the url's hash component.
  112. var hash = @com.vaadin.terminal.gwt.client.HistoryImplIEVaadin::getLocationHash()();
  113. if (hash.length > 0) {
  114. try {
  115. token = this.@com.google.gwt.user.client.impl.HistoryImpl::decodeFragment(Ljava/lang/String;)(hash.substring(1));
  116. } catch (e) {
  117. // Clear the bad hash (this can't have been a valid token).
  118. $wnd.location.hash = '';
  119. }
  120. }
  121. @com.google.gwt.user.client.impl.HistoryImpl::setToken(Ljava/lang/String;)(token);
  122. }-*/;
  123. protected native void injectGlobalHandler()
  124. /*-{
  125. var historyImplRef = this;
  126. $wnd.__gwt_onHistoryLoad = function(token) {
  127. historyImplRef.@com.google.gwt.user.client.impl.HistoryImpl::newItemOnEvent(Ljava/lang/String;)(token);
  128. };
  129. }-*/;
  130. protected native void navigateFrame(String token)
  131. /*-{
  132. var escaped = @com.vaadin.terminal.gwt.client.HistoryImplIEVaadin::escapeHtml(Ljava/lang/String;)(token);
  133. var doc = this.@com.vaadin.terminal.gwt.client.HistoryImplIEVaadin::historyFrame.contentWindow.document;
  134. doc.open();
  135. doc.write('<html><body onload="if(parent.__gwt_onHistoryLoad)parent.__gwt_onHistoryLoad(__gwt_historyToken.innerText)"><div id="__gwt_historyToken">' + escaped + '</div></body></html>');
  136. doc.close();
  137. }-*/;
  138. protected native void updateHash(String token)
  139. /*-{
  140. $wnd.location.hash = this.@com.google.gwt.user.client.impl.HistoryImpl::encodeFragment(Ljava/lang/String;)(token);
  141. }-*/;
  142. private native void initUrlCheckTimer()
  143. /*-{
  144. // This is the URL check timer. It detects when an unexpected change
  145. // occurs in the document's URL (e.g. when the user enters one manually
  146. // or selects a 'favorite', but only the #hash part changes). When this
  147. // occurs, we _must_ reload the page. This is because IE has a really
  148. // nasty bug that totally mangles its history stack and causes the location
  149. // bar in the UI to stop working under these circumstances.
  150. var historyImplRef = this;
  151. var urlChecker = function() {
  152. $wnd.setTimeout(urlChecker, 250);
  153. var hash = @com.vaadin.terminal.gwt.client.HistoryImplIEVaadin::getLocationHash()();
  154. if (hash.length > 0) {
  155. var token = '';
  156. try {
  157. token = historyImplRef.@com.google.gwt.user.client.impl.HistoryImpl::decodeFragment(Ljava/lang/String;)(hash.substring(1));
  158. } catch (e) {
  159. // If there's a bad hash, always reload. This could only happen if
  160. // if someone entered or linked to a bad url.
  161. $wnd.location.reload();
  162. }
  163. var historyToken = @com.google.gwt.user.client.impl.HistoryImpl::getToken()();
  164. if (token != historyToken) {
  165. $wnd.location.reload();
  166. }
  167. }
  168. };
  169. urlChecker();
  170. }-*/;
  171. }