Revision: 6163 Author: [email protected] Date: Fri Sep 18 11:17:07 2009 Log: Allows multiple GWT apps to preview native events in IE.
Patch by: jlabanca Review by: jgw Issue: 3892 http://code.google.com/p/google-web-toolkit/source/detail?r=6163 Added: /trunk/eclipse/reference/code-museum/Issue3892.launch /trunk/reference/code-museum/src/com/google/gwt/museum/Issue3892Module1.gwt.xml /trunk/reference/code-museum/src/com/google/gwt/museum/Issue3892Module2.gwt.xml /trunk/reference/code-museum/src/com/google/gwt/museum/Issue3892Module3.gwt.xml /trunk/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/Issue3892EntryPoint1.java /trunk/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/Issue3892EntryPoint2.java /trunk/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/Issue3892EntryPoint3.java Modified: /trunk/user/src/com/google/gwt/user/client/impl/DOMImplTrident.java ======================================= --- /dev/null +++ /trunk/eclipse/reference/code-museum/Issue3892.launch Fri Sep 18 11:17:07 2009 @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication"> +<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS"> +<listEntry value="/code-museum"/> +</listAttribute> +<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES"> +<listEntry value="4"/> +</listAttribute> +<booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="true"/> +<listAttribute key="org.eclipse.jdt.launching.CLASSPATH"> +<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry containerPath="org.eclipse.jdt.launching.JRE_CONTAINER" javaProject="code-museum" path="1" type="4"/> "/> +<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/code-museum/src" path="3" type="2"/> "/> +<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/gwt-user/core/src" path="3" type="2"/> "/> +<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/gwt-dev-linux/core/src" path="3" type="2"/> "/> +<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/gwt-user/core/super" path="3" type="2"/> "/> +<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/gwt-dev-linux/core/super" path="3" type="2"/> "/> +<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry id="org.eclipse.jdt.launching.classpathentry.defaultClasspath"> <memento exportedEntriesOnly="false" project="code-museum"/> </runtimeClasspathEntry> "/> +</listAttribute> +<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/> +<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.HostedMode"/> +<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-startupUrl Issue3892.html com.google.gwt.museum.Issue3892Module1 com.google.gwt.museum.Issue3892Module2 com.google.gwt.museum.Issue3892Module3"/> +<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="code-museum"/> +<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-ea -Xmx256M -Dgwt.devjar=${gwt_devjar}""/> +</launchConfiguration> ======================================= --- /dev/null +++ /trunk/reference/code-museum/src/com/google/gwt/museum/Issue3892Module1.gwt.xml Fri Sep 18 11:17:07 2009 @@ -0,0 +1,28 @@ +<!-- --> +<!-- Copyright 2009 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 --> +<!-- 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. License for the specific language governing permissions and --> +<!-- limitations under the License. --> +<module rename-to="issue3892Module1"> + + <!-- Inherit the core Web Toolkit stuff. --> + <inherits name='com.google.gwt.user.User' /> + <inherits name='com.google.gwt.museum.Museum' /> + <inherits name="com.google.gwt.user.theme.standard.StandardResources" /> + <inherits name="com.google.gwt.user.theme.chrome.ChromeResources" /> + <inherits name="com.google.gwt.user.theme.dark.DarkResources" /> + + <!-- Specify the app entry point class. --> + <entry-point class='com.google.gwt.museum.client.defaultmuseum.Issue3892EntryPoint1' /> + <source path="client/common" /> + <source path="client/defaultmuseum" /> + <source path="client/viewer" /> +</module> ======================================= --- /dev/null +++ /trunk/reference/code-museum/src/com/google/gwt/museum/Issue3892Module2.gwt.xml Fri Sep 18 11:17:07 2009 @@ -0,0 +1,28 @@ +<!-- --> +<!-- Copyright 2009 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 --> +<!-- 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. License for the specific language governing permissions and --> +<!-- limitations under the License. --> +<module rename-to="issue3892Module2"> + + <!-- Inherit the core Web Toolkit stuff. --> + <inherits name='com.google.gwt.user.User' /> + <inherits name='com.google.gwt.museum.Museum' /> + <inherits name="com.google.gwt.user.theme.standard.StandardResources" /> + <inherits name="com.google.gwt.user.theme.chrome.ChromeResources" /> + <inherits name="com.google.gwt.user.theme.dark.DarkResources" /> + + <!-- Specify the app entry point class. --> + <entry-point class="com.google.gwt.museum.client.defaultmuseum.Issue3892EntryPoint2" /> + <source path="client/common" /> + <source path="client/defaultmuseum" /> + <source path="client/viewer" /> +</module> ======================================= --- /dev/null +++ /trunk/reference/code-museum/src/com/google/gwt/museum/Issue3892Module3.gwt.xml Fri Sep 18 11:17:07 2009 @@ -0,0 +1,28 @@ +<!-- --> +<!-- Copyright 2009 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 --> +<!-- 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. License for the specific language governing permissions and --> +<!-- limitations under the License. --> +<module rename-to="issue3892Module3"> + + <!-- Inherit the core Web Toolkit stuff. --> + <inherits name='com.google.gwt.user.User' /> + <inherits name='com.google.gwt.museum.Museum' /> + <inherits name="com.google.gwt.user.theme.standard.StandardResources" /> + <inherits name="com.google.gwt.user.theme.chrome.ChromeResources" /> + <inherits name="com.google.gwt.user.theme.dark.DarkResources" /> + + <!-- Specify the app entry point class. --> + <entry-point class="com.google.gwt.museum.client.defaultmuseum.Issue3892EntryPoint3" /> + <source path="client/common" /> + <source path="client/defaultmuseum" /> + <source path="client/viewer" /> +</module> ======================================= --- /dev/null +++ /trunk/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/Issue3892EntryPoint1.java Fri Sep 18 11:17:07 2009 @@ -0,0 +1,125 @@ +/* + * Copyright 2009 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.museum.client.defaultmuseum; + +import com.google.gwt.dom.client.Element; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.museum.client.common.AbstractIssue; +import com.google.gwt.user.client.Event; +import com.google.gwt.user.client.Window; +import com.google.gwt.user.client.Event.NativePreviewEvent; +import com.google.gwt.user.client.Event.NativePreviewHandler; +import com.google.gwt.user.client.ui.Button; +import com.google.gwt.user.client.ui.Grid; +import com.google.gwt.user.client.ui.Widget; + +/** + * Only a single GWT application can preview native events. + */ +public class Issue3892EntryPoint1 extends AbstractIssue { + + public static final String BUTTON_1_ID = "Issue3892Button1"; + public static final String BUTTON_2_ID = "Issue3892Button2"; + public static final String BUTTON_3_ID = "Issue3892Button3"; + + /** + * The main grid used for layout. + */ + private Grid grid = new Grid(1, 3); + + @Override + public Widget createIssue() { + Window.alert("Module 1 loaded"); + + // Setup the grid. + grid.setHTML(0, 0, "<b>Test<b>"); + grid.setHTML(0, 1, "<b>Description<b>"); + grid.setHTML(0, 2, "<b>Expected Results<b>"); + addTest(BUTTON_1_ID, "Event is not cancelled by any module.", + "The event will fire in the button.", false); + addTest(BUTTON_2_ID, "Module 1 cancels event.", + "The event will not fire in the button.", true); + addTest(BUTTON_3_ID, "Module 2 cancels event.", + "The event will not fire in the button.", true); + + // Add the event preview. + Event.addNativePreviewHandler(new NativePreviewHandler() { + public void onPreviewNativeEvent(NativePreviewEvent event) { + if (event.getTypeInt() == Event.ONCLICK) { + Element target = event.getNativeEvent().getEventTarget().cast(); + if (BUTTON_2_ID.equals(target.getId())) { + event.cancel(); + Window.alert("Click handled by module 1 and cancelled"); + } else { + Window.alert("Click handled by module 1"); + } + } + } + }); + + return grid; + } + + @Override + public String getInstructions() { + return "After all three modules have loaded (indicated by alert boxes), " + + "click the buttons and verify that you see the expected results. " + + "For each test, all three modules should preview the event (even if " + + "one of the modules cancels the event)."; + } + + @Override + public String getSummary() { + return "Only a single GWT application can preview native events"; + } + + @Override + public boolean hasCSS() { + return false; + } + + /** + * Add a test button to the grid. + * + * @param buttonId the ID of the button + * @param description the test description + * @param results the expected result of the test + * @param isCancelled true if one of the modules will cancel the event + */ + private void addTest(String buttonId, String description, String results, + final boolean isCancelled) { + int row = grid.getRowCount(); + grid.resizeRows(row + 1); + + // Add the test button. + Button button = new Button("Run Test", new ClickHandler() { + public void onClick(ClickEvent event) { + if (isCancelled) { + Window.alert("[Error] Event should have been cancelled"); + } else { + Window.alert("[Success] Event successfully fired"); + } + } + }); + button.getElement().setId(buttonId); + grid.setWidget(row, 0, button); + + // Add the description and expected results. + grid.setText(row, 1, description); + grid.setText(row, 2, results); + } +} ======================================= --- /dev/null +++ /trunk/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/Issue3892EntryPoint2.java Fri Sep 18 11:17:07 2009 @@ -0,0 +1,45 @@ +/* + * Copyright 2009 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.museum.client.defaultmuseum; + +import com.google.gwt.core.client.EntryPoint; +import com.google.gwt.dom.client.Element; +import com.google.gwt.user.client.Event; +import com.google.gwt.user.client.Window; +import com.google.gwt.user.client.Event.NativePreviewEvent; +import com.google.gwt.user.client.Event.NativePreviewHandler; + +/** + * Only a single GWT application can preview native events. + */ +public class Issue3892EntryPoint2 implements EntryPoint { + public void onModuleLoad() { + Window.alert("Module 2 loaded"); + Event.addNativePreviewHandler(new NativePreviewHandler() { + public void onPreviewNativeEvent(NativePreviewEvent event) { + if (event.getTypeInt() == Event.ONCLICK) { + Element target = event.getNativeEvent().getEventTarget().cast(); + if (Issue3892EntryPoint1.BUTTON_3_ID.equals(target.getId())) { + event.cancel(); + Window.alert("Click handled by module 2 and cancelled"); + } else { + Window.alert("Click handled by module 2"); + } + } + } + }); + } +} ======================================= --- /dev/null +++ /trunk/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/Issue3892EntryPoint3.java Fri Sep 18 11:17:07 2009 @@ -0,0 +1,38 @@ +/* + * Copyright 2009 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.museum.client.defaultmuseum; + +import com.google.gwt.core.client.EntryPoint; +import com.google.gwt.user.client.Event; +import com.google.gwt.user.client.Window; +import com.google.gwt.user.client.Event.NativePreviewEvent; +import com.google.gwt.user.client.Event.NativePreviewHandler; + +/** + * Only a single GWT application can preview native events. + */ +public class Issue3892EntryPoint3 implements EntryPoint { + public void onModuleLoad() { + Window.alert("Module 3 loaded"); + Event.addNativePreviewHandler(new NativePreviewHandler() { + public void onPreviewNativeEvent(NativePreviewEvent event) { + if (event.getTypeInt() == Event.ONCLICK) { + Window.alert("Click handled by module 3"); + } + } + }); + } +} ======================================= --- /trunk/user/src/com/google/gwt/user/client/impl/DOMImplTrident.java Tue Jul 21 07:10:53 2009 +++ /trunk/user/src/com/google/gwt/user/client/impl/DOMImplTrident.java Fri Sep 18 11:17:07 2009 @@ -31,6 +31,23 @@ @SuppressWarnings("unused") private static JavaScriptObject dispatchDblClickEvent; + /** + * Let every GWT app on the page preview the current event. If any app cancels + * the event, the event will be canceled for all apps. + * + * @return <code>false</code> to cancel the event + */ + @SuppressWarnings("unused") + private static native boolean previewEventImpl() /*-{ + var isCancelled = false; + for (var i = 0; i < $wnd.__gwt_globalEventArray.length; i++) { + if (!$wnd.__gwt_globalEventArray[i]()) { + isCancelled = true; + } + } + return !isCancelled; + }-*/; + @Override public native Element eventGetFromElement(Event evt) /*-{ // Prefer 'relatedTarget' if it's set (see createMouseEvent(), which @@ -68,6 +85,24 @@ @Override public native void initEventSystem() /*-{ + // All GWT apps on the page register themselves with the globelEventArray + // so that the first app to handle an event can allow all apps on the page + // to preview it. See issue 3892 for more details. + // + // Apps cannot just mark the event as they visit it for a few reasons. + // First, window level event handlers fire last in IE, so the first app to + // cancel the event will be the last to see it. Second, window events do + // not support arbitrary attributes, and the only writable field is the + // returnValue, which has another use. Finally, window events are not + // comparable (ex. a=event; b=event; a!=b), so we cannot keep a list of + // events that have already been previewed by the current app. + if ($wnd.__gwt_globalEventArray == null) { + $wnd.__gwt_globalEventArray = new Array(); + } + $wnd.__gwt_globalEventArray[$wnd.__gwt_globalEventArray.length] = function() { + return @com.google.gwt.user.client.DOM::previewEvent(Lcom/google/gwt/user/client/Event;)($wnd.event); + } + @com.google.gwt.user.client.impl.DOMImplTrident::dispatchEvent = function() { // IE doesn't define event.currentTarget, so we squirrel it away here. It // also seems that IE won't allow you to add expandos to the event object, @@ -76,9 +111,12 @@ var oldEventTarget = @com.google.gwt.dom.client.DOMImplTrident::currentEventTarget; @com.google.gwt.dom.client.DOMImplTrident::currentEventTarget = this; + // The first GWT app on the page to handle the event allows all apps to + // preview it before continuing or cancelling, which is consistent with + // other browsers. if ($wnd.event.returnValue == null) { $wnd.event.returnValue = true; - if ([email protected]::previewEvent(Lcom/google/gwt/user/client/Event;)($wnd.event)) { + if ([email protected]::previewEventImpl()()) { @com.google.gwt.dom.client.DOMImplTrident::currentEventTarget = oldEventTarget; return; } @@ -109,7 +147,7 @@ } else if ($wnd.event.returnValue == null) { // Ensure that we preview the event even if we aren't handling it. $wnd.event.returnValue = true; - @com.google.gwt.user.client.DOM::previewEvent(Lcom/google/gwt/user/client/Event;)($wnd.event); + @com.google.gwt.user.client.impl.DOMImplTrident::previewEventImpl()(); } }; --~--~---------~--~----~------------~-------~--~----~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~----------~----~----~----~------~----~------~--~---
