Follow-on to spurious horizontal scrollbars fix. Previously, the code to correctly position the focusable element (in the event of a branch collapse with the selected item as a descendant) was placed in the elementClicked method. This did not handle the case of collapsing a branch programatically. The call site has been moved to the bottom of the TreeItem.updateState method. Notice that the code to manipulate the focusable element has remained as part of the Tree class. The idea behind this is that the Tree may want to react in other ways when it finds that a particular TreeItem opens/closes.
Also adds a fix for removing focus outlines around the focusable element in IE6/7.
Patch by: rdayal
Review by: jlabanca
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@2413 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/user/client/ui/Tree.java b/user/src/com/google/gwt/user/client/ui/Tree.java
index 3fdabc7..38fec29 100644
--- a/user/src/com/google/gwt/user/client/ui/Tree.java
+++ b/user/src/com/google/gwt/user/client/ui/Tree.java
@@ -679,6 +679,23 @@
return images;
}
+ void maybeUpdateSelection(TreeItem itemThatChangedState, boolean isItemOpening) {
+ /**
+ * If we just closed the item, let's check to see if this item is the parent of
+ * the currently selected item. If so, we should make this item the currently selected
+ * selected item.
+ */
+ if (!isItemOpening) {
+ TreeItem tempItem = curSelection;
+ while (tempItem != null) {
+ if (tempItem == itemThatChangedState) {
+ setSelectedItem(itemThatChangedState);
+ return;
+ }
+ tempItem = tempItem.getParentItem();
+ }
+ }
+ }
void orphan(Widget widget) {
// Validation should already be done.
assert (widget.getParent() == this);
@@ -710,25 +727,6 @@
if (item != null) {
if (DOM.isOrHasChild(item.getImageElement(), hElem)) {
item.setState(!item.getState(), true);
-
- // If we just closed the item, let's check to see if this item is the parent of
- // the currently selected item. If so, we should make this item the currently selected
- // selected item. Note that we only need to do this check in the case where an element's
- // state is changed due to a click; in the case of keyboard interaction, an item's state
- // can only be changed if it is the currently selected item.
- if (!item.getState()) {
- if (curSelection != null) {
- TreeItem tempItem = curSelection;
- while (tempItem != null) {
- if (tempItem == item) {
- setSelectedItem(item);
- break;
- }
- tempItem = tempItem.getParentItem();
- }
- }
- }
-
return true;
} else if (DOM.isOrHasChild(item.getElement(), hElem)) {
onSelection(item, true, !shouldTreeDelegateFocusToElement(hElem));
@@ -788,12 +786,23 @@
private void init(TreeImages images) {
this.images = images;
setElement(DOM.createDiv());
+
DOM.setStyleAttribute(getElement(), "position", "relative");
+
+ // Fix rendering problem with relatively-positioned elements and their children by
+ // forcing the element that is positioned relatively to 'have layout'
DOM.setStyleAttribute(getElement(), "zoom", "1");
+
focusable = FocusPanel.impl.createFocusable();
DOM.setStyleAttribute(focusable, "fontSize", "0");
DOM.setStyleAttribute(focusable, "position", "absolute");
+
+ // Hide focus outline in Mozilla/Webkit/Opera
DOM.setStyleAttribute(focusable, "outline", "0px");
+
+ // Hide focus outline in IE 6/7
+ DOM.setElementAttribute(focusable, "hideFocus", "true");
+
DOM.setIntStyleAttribute(focusable, "zIndex", -1);
DOM.appendChild(getElement(), focusable);
@@ -904,7 +913,7 @@
DOM.setIntStyleAttribute(focusable, "top", 0);
return;
}
-
+
// Set the focusable element's position and size to exactly underlap the
// item's content element.
DOM.setStyleAttribute(focusable, "left", left + "px");
@@ -915,14 +924,14 @@
// Scroll it into view.
DOM.scrollIntoView(focusable);
- // Update ARIA attributes to reflect the information from the newly-selected item.
- updateAriaAttributes();
+ // Update ARIA attributes to reflect the information from the newly-selected item.
+ updateAriaAttributes();
- // Ensure Focus is set, as focus may have been previously delegated by
- // tree.
- setFocus(true);
+ // Ensure Focus is set, as focus may have been previously delegated by
+ // tree.
+ setFocus(true);
+ }
}
- }
/**
* Moves to the next item, going into children as if dig is enabled.
@@ -1068,4 +1077,4 @@
Accessibility.setState(focusable, Accessibility.STATE_ACTIVEDESCENDANT,
DOM.getElementAttribute(curSelectionContentElem, "id"));
}
-}
+ }
diff --git a/user/src/com/google/gwt/user/client/ui/TreeItem.java b/user/src/com/google/gwt/user/client/ui/TreeItem.java
index 5268c6b..4fe5f4f 100644
--- a/user/src/com/google/gwt/user/client/ui/TreeItem.java
+++ b/user/src/com/google/gwt/user/client/ui/TreeItem.java
@@ -244,7 +244,7 @@
item.setTree(tree);
if (children.size() == 1) {
- updateState(false);
+ updateState(false, false);
}
}
@@ -395,7 +395,7 @@
children.remove(item);
if (children.size() == 0) {
- updateState(false);
+ updateState(false, false);
}
}
@@ -451,7 +451,7 @@
// Only do the physical update if it changes
if (this.open != open) {
this.open = open;
- updateState(true);
+ updateState(true, true);
}
if (fireEvents && tree != null) {
@@ -601,7 +601,7 @@
for (int i = 0, n = children.size(); i < n; ++i) {
children.get(i).setTree(newTree);
}
- updateState(false);
+ updateState(false, true);
if (newTree != null) {
if (widget != null) {
@@ -611,7 +611,7 @@
}
}
- void updateState(boolean animate) {
+ void updateState(boolean animate, boolean updateTreeSelection) {
// If the tree hasn't been set, there is no visual state to update.
if (tree == null) {
return;
@@ -642,12 +642,24 @@
} else {
images.treeClosed().applyTo(statusImage);
}
+
+ // We may need to update the tree's selection in response to a tree state change. For
+ // example, if the tree's currently selected item is a descendant of an item whose
+ // branch was just collapsed, then the item itself should become the newly-selected item.
+ if (updateTreeSelection) {
+ tree.maybeUpdateSelection(this, this.open);
+ }
}
void updateStateRecursive() {
- updateState(false);
+ updateStateRecursiveHelper();
+ tree.maybeUpdateSelection(this, this.open);
+ }
+
+ private void updateStateRecursiveHelper() {
+ updateState(false, false);
for (int i = 0, n = children.size(); i < n; ++i) {
- children.get(i).updateStateRecursive();
+ children.get(i).updateStateRecursiveHelper();
}
}
}