Fixing a few logic and usability bugs in Cell Widgets. CellTree items are now easier to click. Fixed a bug in CellBrowser keyboard navigation on Chrome where we would get async blur events that prevented keyboard navigation. Fixed a few IE7 specific bugs that occur when delayed events fire on elements that have been replaced.
Review at http://gwt-code-reviews.appspot.com/995801
Review by: rice@google.com
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@9050 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/user/cellview/CellView.gwt.xml b/user/src/com/google/gwt/user/cellview/CellView.gwt.xml
index ad0cbe0..22a4326 100644
--- a/user/src/com/google/gwt/user/cellview/CellView.gwt.xml
+++ b/user/src/com/google/gwt/user/cellview/CellView.gwt.xml
@@ -24,7 +24,6 @@
<replace-with class="com.google.gwt.user.cellview.client.CellBasedWidgetImplStandard">
<when-type-is class="com.google.gwt.user.cellview.client.CellBasedWidgetImpl"/>
<any>
- <when-property-is name="user.agent" value="safari"/>
<when-property-is name="user.agent" value="opera"/>
<when-property-is name="user.agent" value="gecko"/>
<when-property-is name="user.agent" value="gecko1_8"/>
@@ -40,6 +39,14 @@
</any>
</replace-with>
+ <!-- Safari-specific CellBasedWidgetImpl implementation. -->
+ <replace-with class="com.google.gwt.user.cellview.client.CellBasedWidgetImplSafari">
+ <when-type-is class="com.google.gwt.user.cellview.client.CellBasedWidgetImpl"/>
+ <any>
+ <when-property-is name="user.agent" value="safari"/>
+ </any>
+ </replace-with>
+
<!-- IE-specific CellTable implementation. -->
<replace-with class="com.google.gwt.user.cellview.client.CellTable.ImplTrident">
<when-type-is class="com.google.gwt.user.cellview.client.CellTable.Impl"/>
diff --git a/user/src/com/google/gwt/user/cellview/client/CellBasedWidgetImplSafari.java b/user/src/com/google/gwt/user/cellview/client/CellBasedWidgetImplSafari.java
new file mode 100644
index 0000000..c24d875
--- /dev/null
+++ b/user/src/com/google/gwt/user/cellview/client/CellBasedWidgetImplSafari.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2010 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.cellview.client;
+
+import com.google.gwt.core.client.Scheduler;
+import com.google.gwt.core.client.Scheduler.ScheduledCommand;
+
+/**
+ * Webkit specified Impl used by cell based widgets.
+ */
+public class CellBasedWidgetImplSafari extends CellBasedWidgetImplStandard {
+
+ @Override
+ public void resetFocus(ScheduledCommand command) {
+ // Webkit will not focus an element that was created in this event loop.
+ Scheduler.get().scheduleDeferred(command);
+ }
+}
diff --git a/user/src/com/google/gwt/user/cellview/client/CellBrowser.css b/user/src/com/google/gwt/user/cellview/client/CellBrowser.css
index 6428be8..8739e95 100644
--- a/user/src/com/google/gwt/user/cellview/client/CellBrowser.css
+++ b/user/src/com/google/gwt/user/cellview/client/CellBrowser.css
@@ -40,6 +40,7 @@
@sprite .cellBrowserSelectedItem {
gwt-image: 'cellBrowserSelectedBackground';
background-color: #628cd5;
+ background-repeat: repeat-x;
color: white;
height: auto;
overflow: hidden;
@@ -48,6 +49,7 @@
@sprite .cellBrowserOpenItem {
gwt-image: 'cellBrowserOpenBackground';
background-color: #7b7b7b;
+ background-repeat: repeat-x;
color: white;
height: auto;
overflow: hidden;
diff --git a/user/src/com/google/gwt/user/cellview/client/CellBrowser.java b/user/src/com/google/gwt/user/cellview/client/CellBrowser.java
index 42e31d5..7ab531e 100644
--- a/user/src/com/google/gwt/user/cellview/client/CellBrowser.java
+++ b/user/src/com/google/gwt/user/cellview/client/CellBrowser.java
@@ -101,14 +101,16 @@
/**
* The background used for open items.
*/
- @ImageOptions(repeatStyle = RepeatStyle.Horizontal, flipRtl = true)
+ // Use RepeatStyle.BOTH to ensure that we do not bundle the image.
+ @ImageOptions(repeatStyle = RepeatStyle.Both, flipRtl = true)
ImageResource cellBrowserOpenBackground();
/**
* The background used for selected items.
*/
+ // Use RepeatStyle.BOTH to ensure that we do not bundle the image.
@Source("cellTreeSelectedBackground.png")
- @ImageOptions(repeatStyle = RepeatStyle.Horizontal, flipRtl = true)
+ @ImageOptions(repeatStyle = RepeatStyle.Both, flipRtl = true)
ImageResource cellBrowserSelectedBackground();
/**
diff --git a/user/src/com/google/gwt/user/cellview/client/CellList.java b/user/src/com/google/gwt/user/cellview/client/CellList.java
index 9097338..2906315 100644
--- a/user/src/com/google/gwt/user/cellview/client/CellList.java
+++ b/user/src/com/google/gwt/user/cellview/client/CellList.java
@@ -380,6 +380,9 @@
// If the event causes us to page, then the index will be out of bounds.
return;
}
+
+ // Get the cell parent before doing selection in case the list is redrawn.
+ Element cellParent = getCellParent(target);
T value = getDisplayedItem(indexOnPage);
if (isMouseDown && !cell.handlesSelection()) {
doSelection(event, value, indexOnPage);
@@ -392,7 +395,7 @@
}
// Fire the event to the cell if the list has not been refreshed.
- fireEventToCell(event, getCellParent(target), value);
+ fireEventToCell(event, cellParent, value);
}
}
diff --git a/user/src/com/google/gwt/user/cellview/client/CellTable.java b/user/src/com/google/gwt/user/cellview/client/CellTable.java
index 829ef8d..5b3cb50 100644
--- a/user/src/com/google/gwt/user/cellview/client/CellTable.java
+++ b/user/src/com/google/gwt/user/cellview/client/CellTable.java
@@ -935,7 +935,8 @@
boolean isMouseDown = "mousedown".equals(eventType);
int row = tr.getSectionRowIndex();
if ("mouseover".equals(eventType)) {
- if (hoveringRow != null) {
+ // Unstyle the old row if it is still part of the table.
+ if (hoveringRow != null && tbody.isOrHasChild(hoveringRow)) {
setRowStyleName(hoveringRow, style.cellTableHoveredRow(),
style.cellTableHoveredRowCell(), false);
}
diff --git a/user/src/com/google/gwt/user/cellview/client/CellTree.java b/user/src/com/google/gwt/user/cellview/client/CellTree.java
index 66dbaba..fa93a60 100644
--- a/user/src/com/google/gwt/user/cellview/client/CellTree.java
+++ b/user/src/com/google/gwt/user/cellview/client/CellTree.java
@@ -18,6 +18,7 @@
import com.google.gwt.animation.client.Animation;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.Scheduler;
+import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.dom.client.Style.Position;
@@ -503,6 +504,11 @@
private boolean isAnimationEnabled;
/**
+ * The deferred command used to keyboard select a node.
+ */
+ private ScheduledCommand keyboardSelectCommand;
+
+ /**
* The {@link CellTreeNodeView} whose children are currently being selected
* using the keyboard.
*/
@@ -677,7 +683,7 @@
collectElementChain(chain, getElement(), target);
boolean isMouseDown = "mousedown".equals(eventType);
- CellTreeNodeView<?> nodeView = findItemByChain(chain, 0, rootNode);
+ final CellTreeNodeView<?> nodeView = findItemByChain(chain, 0, rootNode);
if (nodeView != null && nodeView != rootNode) {
if (isMouseDown) {
Element showMoreElem = nodeView.getShowMoreElement();
@@ -693,11 +699,21 @@
}
// Forward the event to the cell
- if (nodeView.getCellParent().isOrHasChild(target)) {
+ if (nodeView.getSelectionElement().isOrHasChild(target)) {
// Move the keyboard focus to the clicked item.
if ("focus".equals(eventType) || isMouseDown) {
- isFocused = true;
- keyboardSelect(nodeView, false);
+ // Wait until any pending blur event has fired.
+ final boolean targetsCellParent = nodeView.getCellParent().isOrHasChild(target);
+ keyboardSelectCommand = new ScheduledCommand() {
+ public void execute() {
+ if (keyboardSelectCommand == this && !nodeView.isDestroyed()) {
+ isFocused = true;
+ keyboardSelectCommand = null;
+ keyboardSelect(nodeView, !targetsCellParent);
+ }
+ }
+ };
+ Scheduler.get().scheduleDeferred(keyboardSelectCommand);
}
nodeView.fireEventToCell(event);
@@ -879,7 +895,8 @@
void resetFocus() {
CellBasedWidgetImpl.get().resetFocus(new Scheduler.ScheduledCommand() {
public void execute() {
- if (isFocused && !keyboardSelectedNode.resetFocusOnCell()) {
+ if (isFocused && !keyboardSelectedNode.isDestroyed()
+ && !keyboardSelectedNode.resetFocusOnCell()) {
keyboardSelectedNode.setKeyboardSelected(true, true);
}
}
diff --git a/user/src/com/google/gwt/user/cellview/client/CellTreeNodeView.java b/user/src/com/google/gwt/user/cellview/client/CellTreeNodeView.java
index 634efe1..2afe4b7 100644
--- a/user/src/com/google/gwt/user/cellview/client/CellTreeNodeView.java
+++ b/user/src/com/google/gwt/user/cellview/client/CellTreeNodeView.java
@@ -974,6 +974,9 @@
}
// Forward the event to the cell.
+ if (!cellParent.isOrHasChild(Element.as(event.getEventTarget()))) {
+ return;
+ }
Set<String> consumedEvents = parentCell.getConsumedEvents();
if (consumedEvents != null && consumedEvents.contains(eventType)) {
boolean cellWasEditing = parentCell.isEditing(cellParent, value, key);
@@ -1007,6 +1010,17 @@
}
/**
+ * Returns the element that selection styles are applied to. The element
+ * includes the open/close image and the rendered value and spans the width of
+ * the tree.
+ *
+ * @return the selection element
+ */
+ protected Element getSelectionElement() {
+ return getSelectionElement(getElement());
+ }
+
+ /**
* Returns the key for the value of this node using the parent's
* implementation of NodeInfo.getKey().
*/
@@ -1039,7 +1053,7 @@
animationFrame = Document.get().createDivElement();
animationFrame.getStyle().setPosition(Position.RELATIVE);
animationFrame.getStyle().setOverflow(Overflow.HIDDEN);
- animationFrame.setId("animFrame");
+ animationFrame.getStyle().setDisplay(Display.NONE);
getElement().appendChild(animationFrame);
}
return animationFrame;