/* * 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.museum.client.defaultmuseum; 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.Command; import com.google.gwt.user.client.DeferredCommand; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.RichTextArea; import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.Widget; /** * <h1>Attaching and detaching a RichTextArea too fast crashes GWT</h1> * * <p> * The RichTextArea uses a Timer or iframe.onload event (depending on the * browser) to trigger the event system initialization. Basically, that * introduces a small delay between the time the RichTextArea is attached to the * page and the time that the event handlers are added. * </p> * <p> * However, if you programmatically (or just very quickly) remove the * RichTextArea from the page, you will immediately trigger the teardown methods * that remove the event listeners. In some browsers, removing the event * listeners before they are added throws a JavaScript exception do to an * undefined variable, which messes up the rest of the onDetach mechanism, which * gets your attach state out of sync, which means your app stops working * properly. * </p> * <p> * I am able to reliably reproduce these errors by attaching and removing a * RichTextArea very quickly, even in user time. The errors affect all browsers, * but Firefox is by far the most affected because it catches the iframe.onload * event, whereas the others just use a 1ms timer. Also, Safari and IE seem to * handle the javascript exceptions a little cleaner. * </p> */ public class Issue1897 extends AbstractIssue { /** * A set of options used to set the caption and content in the caption panel. */ private class ControlPanel extends Composite { private final HorizontalPanel hPanel = new HorizontalPanel(); public ControlPanel() { initWidget(hPanel); hPanel.setSpacing(10); // Add option to attach RichTextArea Button attachButton = new Button("Attach RichText", new ClickHandler() { public void onClick(ClickEvent event) { if (rta.isAttached()) { Window.alert("RichTextArea is already attached."); } wrapper.add(rta); } }); hPanel.add(attachButton); // Add option to detach RichTextArea Button detachButton = new Button("Detach RichText", new ClickHandler() { public void onClick(ClickEvent event) { if (!rta.isAttached()) { Window.alert("RichTextArea is already detached."); return; } wrapper.remove(rta); } }); hPanel.add(detachButton); // Add option to attach and detach RichTextArea Button quickDetachButton = new Button("Attach/Detach RichText", new ClickHandler() { public void onClick(ClickEvent event) { if (rta.isAttached()) { Window.alert("RichTextArea is already attached."); return; } wrapper.add(rta); wrapper.remove(rta); } }); hPanel.add(quickDetachButton); } } private RichTextArea rta; private VerticalPanel wrapper; @Override public Widget createIssue() { rta = new RichTextArea(); rta.setPixelSize(200, 100); // Combine the control panel and RichTextArea in a wrapper wrapper = new VerticalPanel(); wrapper.setSpacing(10); wrapper.add(new ControlPanel()); wrapper.add(rta); // Remove the RichTextArea after the wrapper is attached to the DOM DeferredCommand.addCommand(new Command() { public void execute() { wrapper.remove(rta); } }); return wrapper; } @Override public String getInstructions() { return "You should <b>not</b> see a RichTextArea, and no errors should " + "occur. If you click the Attach/Detach button, the RichTextArea will" + " be programmatically attached and detached from the DOM structure, " + "and you should not see any errors."; } @Override public String getSummary() { return "Attaching and detaching a RichTextArea too fast crashes GWT"; } @Override public boolean hasCSS() { return true; } }