Rolls behavior from incubator's HyperlinkOverride into Hyperlink. Now Hyperlink
will let the default browser action happen in some cases, eg Ctrl-clicking on a
link. Particular behavior is specific per browser.

patch by: ajr
review by: rjrjr


git-svn-id: https://google-web-toolkit.googlecode.com/svn/releases/1.6@4225 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/user/Hyperlink.gwt.xml b/user/src/com/google/gwt/user/Hyperlink.gwt.xml
new file mode 100644
index 0000000..e667c13
--- /dev/null
+++ b/user/src/com/google/gwt/user/Hyperlink.gwt.xml
@@ -0,0 +1,19 @@
+<module>
+  <inherits name="com.google.gwt.core.Core"/>
+  <inherits name="com.google.gwt.user.UserAgent"/>
+
+  <replace-with class="com.google.gwt.user.client.ui.impl.HyperlinkImplOpera">
+    <when-type-is class="com.google.gwt.user.client.ui.impl.HyperlinkImpl"/>
+    <when-property-is name="user.agent" value="opera"/>
+  </replace-with>
+
+  <replace-with class="com.google.gwt.user.client.ui.impl.HyperlinkImplSafari">
+    <when-type-is class="com.google.gwt.user.client.ui.impl.HyperlinkImpl"/>
+    <when-property-is name="user.agent" value="safari"/>
+  </replace-with>
+
+  <replace-with class="com.google.gwt.user.client.ui.impl.HyperlinkImplIE">
+    <when-type-is class="com.google.gwt.user.client.ui.impl.HyperlinkImpl"/>
+    <when-property-is name="user.agent" value="ie6"/>
+  </replace-with>
+</module>
diff --git a/user/src/com/google/gwt/user/User.gwt.xml b/user/src/com/google/gwt/user/User.gwt.xml
index 3010bef..17de395 100644
--- a/user/src/com/google/gwt/user/User.gwt.xml
+++ b/user/src/com/google/gwt/user/User.gwt.xml
@@ -39,6 +39,7 @@
    <inherits name="com.google.gwt.user.CaptionPanel" />
    <inherits name="com.google.gwt.user.Window" />
    <inherits name="com.google.gwt.user.Tree"/>
+   <inherits name="com.google.gwt.user.Hyperlink"/>
     
     <super-source path="translatable"/>
     <source path="client"/>
diff --git a/user/src/com/google/gwt/user/client/ui/Hyperlink.java b/user/src/com/google/gwt/user/client/ui/Hyperlink.java
index 981ed9e..789f855 100644
--- a/user/src/com/google/gwt/user/client/ui/Hyperlink.java
+++ b/user/src/com/google/gwt/user/client/ui/Hyperlink.java
@@ -15,6 +15,7 @@
  */
 package com.google.gwt.user.client.ui;
 
+import com.google.gwt.core.client.GWT;
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.event.dom.client.HasClickHandlers;
@@ -23,6 +24,7 @@
 import com.google.gwt.user.client.Element;
 import com.google.gwt.user.client.Event;
 import com.google.gwt.user.client.History;
+import com.google.gwt.user.client.ui.impl.HyperlinkImpl;
 
 /**
  * A widget that serves as an "internal" hyperlink. That is, it is a link to
@@ -52,6 +54,8 @@
 public class Hyperlink extends Widget implements HasHTML, SourcesClickEvents,
     HasClickHandlers {
 
+  private static HyperlinkImpl impl = GWT.create(HyperlinkImpl.class);
+  
   private Element anchorElem;
   private String targetHistoryToken;
 
@@ -126,8 +130,11 @@
   public void onBrowserEvent(Event event) {
     if (DOM.eventGetType(event) == Event.ONCLICK) {
       super.onBrowserEvent(event);
-      History.newItem(targetHistoryToken);
-      DOM.eventPreventDefault(event);
+      
+      if (impl.handleAsClick(event)) {
+        History.newItem(getTargetHistoryToken());
+        DOM.eventPreventDefault(event);
+      }
     }
   }
 
diff --git a/user/src/com/google/gwt/user/client/ui/impl/HyperlinkImpl.java b/user/src/com/google/gwt/user/client/ui/impl/HyperlinkImpl.java
new file mode 100644
index 0000000..884042e
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/ui/impl/HyperlinkImpl.java
@@ -0,0 +1,45 @@
+/*
+ * 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.google.gwt.user.client.ui.impl;
+
+import com.google.gwt.user.client.Event;
+
+/**
+ * Methods that need browser-specific implementations for Hyperlink.
+ * By default, we're very conservative and let the browser handle any clicks
+ * with non-left buttons or with modifier keys. This happens to be the correct
+ * behavior for Firefox.
+ */
+public class HyperlinkImpl {
+
+  /**
+   * Default version, useful for Firefox. Don't fire if it's a rightclick,
+   * middleclick, or if any modifiers are held down.
+   */
+  public boolean handleAsClick(Event event) {   
+    int mouseButtons = event.getButton();
+    boolean alt = event.getAltKey();
+    boolean ctrl = event.getCtrlKey();
+    boolean meta = event.getMetaKey();
+    boolean shift = event.getShiftKey();    
+    boolean modifiers = alt || ctrl || meta || shift;
+    boolean middle = mouseButtons == Event.BUTTON_MIDDLE;
+    boolean right = mouseButtons == Event.BUTTON_RIGHT;
+
+    return !modifiers && !middle && !right;
+  }
+}
diff --git a/user/src/com/google/gwt/user/client/ui/impl/HyperlinkImplIE.java b/user/src/com/google/gwt/user/client/ui/impl/HyperlinkImplIE.java
new file mode 100644
index 0000000..42e83a3
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/ui/impl/HyperlinkImplIE.java
@@ -0,0 +1,65 @@
+/*
+ * 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.google.gwt.user.client.ui.impl;
+
+import com.google.gwt.user.client.Event;
+
+/**
+ * IE version of HyperlinkImpl. IE6 and IE7 actually have different
+ * behavior; both have special behavior for shift-click, but IE7 also opens
+ * in a new tab on ctrl-click. IE6 treats ctrl-click as a standard click.
+ */
+public class HyperlinkImplIE extends HyperlinkImpl {
+  
+  private static boolean ctrlisModifier = (getInternetExplorerVersion() >= 7);
+
+  /**
+   * Returns the version of Internet Explorer or a -1, (indicating the use of
+   * another browser). Based on code from MSDN.
+   * http://msdn2.microsoft.com/en-us/library/ms537509.aspx
+   */
+  private static native int getInternetExplorerVersion() /*-{
+    var rv = -1; // Assume that we're not IE.
+           
+    if (navigator.appName == 'Microsoft Internet Explorer') {
+      var ua = navigator.userAgent;
+      var re  = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
+      if (re.exec(ua) != null)
+        rv = parseFloat( RegExp.$1 );
+    }
+    
+    return rv;
+  }-*/;
+  
+  @Override
+  public boolean handleAsClick(Event event) {
+    int mouseButtons = event.getButton();
+    boolean ctrl = event.getCtrlKey();
+    boolean shift = event.getShiftKey();
+    boolean middle = mouseButtons == Event.BUTTON_MIDDLE;
+    boolean right = mouseButtons == Event.BUTTON_RIGHT;
+    boolean modifiers;
+    
+    if (ctrlisModifier) {
+      modifiers = shift || ctrl;
+    } else {
+      modifiers = shift;  
+    }
+
+    return !modifiers && !middle && !right;
+  }
+}
diff --git a/user/src/com/google/gwt/user/client/ui/impl/HyperlinkImplOpera.java b/user/src/com/google/gwt/user/client/ui/impl/HyperlinkImplOpera.java
new file mode 100644
index 0000000..00f46c3
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/ui/impl/HyperlinkImplOpera.java
@@ -0,0 +1,35 @@
+/*
+ * 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.google.gwt.user.client.ui.impl;
+
+import com.google.gwt.user.client.Event;
+
+/**
+ * Opera version of HyperlinkImpl. As of Opera 9, the only modifier key
+ * that changes click behavior on links is shift.
+ */
+public class HyperlinkImplOpera extends HyperlinkImpl {
+  @Override
+  public boolean handleAsClick(Event event) {
+    int mouseButtons = event.getButton();
+    boolean shift = event.getShiftKey();
+    boolean middle = mouseButtons == Event.BUTTON_MIDDLE;
+    boolean right = mouseButtons == Event.BUTTON_RIGHT;
+
+    return !shift && !middle && !right;
+  }
+}
diff --git a/user/src/com/google/gwt/user/client/ui/impl/HyperlinkImplSafari.java b/user/src/com/google/gwt/user/client/ui/impl/HyperlinkImplSafari.java
new file mode 100644
index 0000000..764ece1
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/ui/impl/HyperlinkImplSafari.java
@@ -0,0 +1,51 @@
+/*
+ * 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.google.gwt.user.client.ui.impl;
+
+import com.google.gwt.user.client.Event;
+
+/**
+ * HyperlinkImpl for Safari and Google Chrome. Safari has special behavior for
+ * all the modifier keys except shift, which behaves like a regular click.
+ * Chrome, however, opens a new window on a shift-click.
+ */
+public class HyperlinkImplSafari extends HyperlinkImpl {
+
+  private static boolean shiftIsModifier = onChrome();
+
+  private static native boolean onChrome() /*-{
+    return navigator.userAgent.indexOf("Chrome") != -1;
+  }-*/;
+
+  @Override
+  public boolean handleAsClick(Event event) {
+    int mouseButtons = event.getButton();
+    boolean alt = event.getAltKey();
+    boolean ctrl = event.getCtrlKey();
+    boolean meta = event.getMetaKey();
+    boolean shift = event.getShiftKey();
+    boolean middle = mouseButtons == Event.BUTTON_MIDDLE;
+    boolean right = mouseButtons == Event.BUTTON_RIGHT;
+
+    boolean modifiers = alt || ctrl || meta;
+    if (shiftIsModifier) {
+      modifiers |= shift;
+    }
+    
+    return !modifiers && !middle && !right;
+  }
+}