diff --git a/src/main/config/component/focusModifier.xml b/src/main/config/component/focusModifier.xml
index 7a17a81..00e7c43 100644
--- a/src/main/config/component/focusModifier.xml
+++ b/src/main/config/component/focusModifier.xml
@@ -43,5 +43,20 @@
""
+
+ priority
+ java.lang.Integer
+
+ If there are more components requesting focus, then component with lowest priority will be focused.
+
+
+
+ skipped
+ boolean
+
+ If set to true, component will not be concerned when calculating default focus.
+
+ false
+
diff --git a/src/main/java/org/richfaces/component/UIFocus.java b/src/main/java/org/richfaces/component/UIFocus.java
index ca2922c..5831592 100644
--- a/src/main/java/org/richfaces/component/UIFocus.java
+++ b/src/main/java/org/richfaces/component/UIFocus.java
@@ -5,32 +5,71 @@ import javax.faces.component.UIComponentBase;
import javax.faces.component.UIForm;
import javax.faces.component.UIInput;
import javax.faces.context.FacesContext;
+import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.List;
import java.util.Set;
public abstract class UIFocus extends UIComponentBase {
+// ------------------------------ FIELDS ------------------------------
+
+ public static final String COMPONENT_FAMILY = "org.richfaces.Focus";
public static final String COMPONENT_TYPE = "org.richfaces.Focus";
- public static final String COMPONENT_FAMILY = "org.richfaces.Focus";
+ public static final int DEFAULT_PRIORITY = Integer.MAX_VALUE;
+
+ public static final String FOCUS_MODIFIER_FACET_NAME = "focusModifier";
public static final String TIMING_ON_LOAD = "onload";
- public static final String FOCUS_MODIFIER_FACET_NAME = "focusModifier";
+// -------------------------- STATIC METHODS --------------------------
- public Integer getDefaultPriority(FacesContext context) {
- UIComponent parentForm = getParent();
+ public static UIFocusModifier findModifier(UIComponent component) {
+ if (component instanceof UIFocusModifier) {
+ return (UIFocusModifier) component;
+ }
+ UIFocusModifier modifier = (UIFocusModifier) component.getFacet(UIFocus.FOCUS_MODIFIER_FACET_NAME);
+ if (modifier == null) {
+ for (UIComponent child : component.getChildren()) {
+ modifier = findModifier(child);
+ if (modifier != null) {
+ break;
+ }
+ }
+ }
+ return modifier;
+ }
+
+// -------------------------- OTHER METHODS --------------------------
+
+ public int calculatePriority(UIComponent component) {
+ final UIFocusModifier modifier = findModifier(component);
+ if (modifier != null && modifier.getPriority() != null) {
+ return modifier.getPriority();
+ }
+ UIComponent parentForm = component.getParent();
while (parentForm != null && !(parentForm instanceof UIForm)) {
parentForm = parentForm.getParent();
}
if (parentForm != null) {
- return getUIInputChildrenCount(parentForm, getTargetComponentId(context));
+ return getUIInputChildrenCount(parentForm, component.getId());
} else {
- return Integer.MAX_VALUE;
+ return DEFAULT_PRIORITY;
}
}
+ public abstract String getFor();
+
+ public abstract String getName();
+
+ public abstract Integer getPriority();
+
+ public abstract String getSuffix();
+
+ public abstract String getTargetClientId();
+
public String getTargetComponentId(FacesContext context) {
String aFor = getFor();
@@ -43,68 +82,49 @@ public abstract class UIFocus extends UIComponentBase {
while (clientIdsWithMessages.hasNext()) {
allowedClientIds.add(clientIdsWithMessages.next());
}
- UIComponent component = getFirstInput(getParentForm(this), allowedClientIds);
- return component == null ? null : component.getClientId(context);
+ final List inputs = new ArrayList();
+ getInputs(getParentForm(this), allowedClientIds, inputs);
+ UIInput inputWithLowestPriority = null;
+ int lowestPriority = Integer.MAX_VALUE;
+ for (UIInput input : inputs) {
+ final int priority = calculatePriority(input);
+ if (priority < lowestPriority) {
+ inputWithLowestPriority = input;
+ lowestPriority = priority;
+ }
+ }
+ return inputWithLowestPriority == null ? null : inputWithLowestPriority.getClientId(context);
} else {
return getParent().getClientId(context);
}
}
}
- private int getUIInputChildrenCount(UIComponent component, String breakOnId) {
- int inputComponentsCount = 0;
- for (UIComponent child : component.getChildren()) {
- if (child.getId().equals(breakOnId)) {
- break;
- }
- if (child instanceof UIInput) {
- inputComponentsCount++;
- } else {
- int uIInputChildrenCount = getUIInputChildrenCount(child, breakOnId);
- inputComponentsCount += uIInputChildrenCount;
- }
- }
- return inputComponentsCount;
- }
-
- public abstract String getFor();
+ public abstract String getTiming();
public abstract void setFor(String value);
- public abstract String getTargetClientId();
-
- public abstract void setTargetClientId(String targetClientId);
-
- public abstract String getSuffix();
-
- public abstract void setSuffix(String value);
-
- public abstract Integer getPriority();
+ public abstract void setName(String name);
public abstract void setPriority(Integer value);
- public abstract String getTiming();
-
- public abstract String getName();
+ public abstract void setSuffix(String value);
- public abstract void setName(String name);
+ public abstract void setTargetClientId(String targetClientId);
public abstract void setTiming(String timing);
- private UIComponent getFirstInput(UIComponent parent, Set allowedClientIds) {
- UIComponent input = null;
+ private void getInputs(UIComponent parent, Set allowedClientIds, List inputs) {
FacesContext facesContext = getFacesContext();
for (UIComponent child : parent.getChildren()) {
if (child instanceof UIInput && (allowedClientIds.size() == 0 || allowedClientIds.contains(child.getClientId(facesContext)))) {
- return child;
- } else {
- input = getFirstInput(child, allowedClientIds);
- if (input != null) {
- break;
+ final UIFocusModifier modifier = findModifier(child);
+ if (modifier == null || !modifier.isSkipped()) {
+ inputs.add((UIInput) child);
}
}
+ getInputs(child, allowedClientIds, inputs);
}
- return input;
}
private UIForm getParentForm(UIComponent component) {
@@ -118,4 +138,36 @@ public abstract class UIFocus extends UIComponentBase {
return getParentForm(parent);
}
}
+
+ private int getUIInputChildrenCount(UIComponent component, String breakOnId) {
+ final Holder childrenCount = new Holder();
+ childrenCount.value = 0;
+ getUIInputChildrenCount(component, breakOnId, childrenCount);
+ return childrenCount.value;
+ }
+
+ private boolean getUIInputChildrenCount(UIComponent component, String breakOnId, Holder childrenCount) {
+ for (UIComponent child : component.getChildren()) {
+ if (child.getId().equals(breakOnId)) {
+ return true;
+ }
+ if (child instanceof UIInput) {
+ final UIFocusModifier modifier = findModifier(child);
+ if (modifier == null || !modifier.isSkipped()) {
+ childrenCount.value++;
+ }
+ } else {
+ if (getUIInputChildrenCount(child, breakOnId, childrenCount)) return true;
+ }
+ }
+ return false;
+ }
+
+// -------------------------- INNER CLASSES --------------------------
+
+ private class Holder {
+// ------------------------------ FIELDS ------------------------------
+
+ public T value;
+ }
}
diff --git a/src/main/java/org/richfaces/component/UIFocusModifier.java b/src/main/java/org/richfaces/component/UIFocusModifier.java
index 387d111..0ce2dfe 100644
--- a/src/main/java/org/richfaces/component/UIFocusModifier.java
+++ b/src/main/java/org/richfaces/component/UIFocusModifier.java
@@ -11,11 +11,19 @@ public abstract class UIFocusModifier extends UIComponentBase {
// -------------------------- OTHER METHODS --------------------------
- public abstract String getTargetClientId();
+ public abstract Integer getPriority();
public abstract String getSuffix();
- public abstract void setTargetClientId(String focusClientId);
+ public abstract String getTargetClientId();
+
+ public abstract boolean isSkipped();
+
+ public abstract void setPriority(Integer priority);
+
+ public abstract void setSkipped(boolean skipped);
public abstract void setSuffix(String value);
+
+ public abstract void setTargetClientId(String focusClientId);
}
diff --git a/src/main/java/org/richfaces/renderkit/html/HtmlFocusRenderer.java b/src/main/java/org/richfaces/renderkit/html/HtmlFocusRenderer.java
index e76078d..61b7593 100644
--- a/src/main/java/org/richfaces/renderkit/html/HtmlFocusRenderer.java
+++ b/src/main/java/org/richfaces/renderkit/html/HtmlFocusRenderer.java
@@ -32,6 +32,7 @@ import org.richfaces.component.UIFocusModifier;
import javax.faces.FacesException;
import javax.faces.component.UIComponent;
+import javax.faces.component.UIInput;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import java.io.IOException;
@@ -58,6 +59,26 @@ public class HtmlFocusRenderer extends HeaderResourcesRendererBase {
return styles;
}
+ private void checkValidity(FacesContext context, UIFocus component) {
+ String clientId = getUtils().clientId(context, component);
+ String name = component.getName();
+ String timing = component.getTiming();
+ String _for = component.getFor();
+ String targetClientId = component.getTargetClientId();
+ if ((name == null || "".equals(name.trim())) && "onJScall".equals(timing)) {
+ throw new FacesException(
+ "The name attribute of the focus component (id='" + clientId + "') must be specified when timing attribute equals to 'onJScall'");
+ }
+ if (name != null && !"".equals(name.trim()) && !"onJScall".equals(timing)) {
+ throw new FacesException(
+ "The timing attribute of the focus component (id='" + clientId + "') must be set to 'onJScall' when name attribute is specified");
+ }
+ if ((_for == null || "".equals(_for)) && (targetClientId == null || "".equals(targetClientId)) && !(component.getParent() instanceof UIInput)
+ && getUtils().getNestingForm(context, component) == null) {
+ throw new FacesException("Focus component must have either one of 'for' or 'targetClientId' attributes specified or be nested within UIForm or UIInput component");
+ }
+ }
+
@Override
protected void doEncodeEnd(ResponseWriter writer, FacesContext context, UIComponent component)
throws IOException {
@@ -66,11 +87,8 @@ public class HtmlFocusRenderer extends HeaderResourcesRendererBase {
}
UIFocus uiFocus = (UIFocus) component;
final String clientId = getUtils().clientId(context, component);
- checkValidity(clientId, uiFocus.getName(), uiFocus.getTiming());
+ checkValidity(context, uiFocus);
Integer priority = uiFocus.getPriority();
- if (priority == null) {
- priority = uiFocus.getDefaultPriority(context);
- }
String targetClientId = uiFocus.getTargetClientId();
if (targetClientId == null || "".equals(targetClientId)) {
String targetComponentId = uiFocus.getTargetComponentId(context);
@@ -83,7 +101,7 @@ public class HtmlFocusRenderer extends HeaderResourcesRendererBase {
throw new FacesException("No component with id=" + targetComponentId + " found!");
}
targetClientId = forcomp.getClientId(context);
- UIFocusModifier modifier = findModifier(forcomp);
+ UIFocusModifier modifier = UIFocus.findModifier(forcomp);
if (modifier != null) {
final String modifiedTargetClientId = modifier.getTargetClientId();
if (modifiedTargetClientId != null && !modifiedTargetClientId.equals("")) {
@@ -92,6 +110,9 @@ public class HtmlFocusRenderer extends HeaderResourcesRendererBase {
suffix = modifier.getSuffix();
}
}
+ if (priority == null) {
+ priority = uiFocus.calculatePriority(forcomp);
+ }
if (suffix != null && !"".equals(suffix)) {
targetClientId += suffix;
}
@@ -99,6 +120,9 @@ public class HtmlFocusRenderer extends HeaderResourcesRendererBase {
if (targetClientId == null || targetClientId.equals("")) {
return;
}
+ if (priority == null) {
+ priority = UIFocus.DEFAULT_PRIORITY;
+ }
writer.startElement(RendererUtils.HTML.SCRIPT_ELEM, null);
writer.writeAttribute(RendererUtils.HTML.TYPE_ATTR, "text/javascript", "type");
writer.writeAttribute(RendererUtils.HTML.id_ATTRIBUTE, clientId, RendererUtils.HTML.id_ATTRIBUTE);
@@ -119,34 +143,7 @@ public class HtmlFocusRenderer extends HeaderResourcesRendererBase {
writer.endElement(RendererUtils.HTML.SCRIPT_ELEM);
}
- private void checkValidity(String clientId, String name, String timing) {
- if ((name == null || "".equals(name.trim())) && "onJScall".equals(timing)) {
- throw new FacesException(
- "The name attribute of the focus component (id='" + clientId + "') must be specified when timing attribute equals to 'onJScall'");
- }
- if (name != null && !"".equals(name.trim()) && !"onJScall".equals(timing)) {
- throw new FacesException(
- "The timing attribute of the focus component (id='" + clientId + "') must be set to 'onJScall' when name attribute is specified");
- }
- }
-
protected Class extends UIComponent> getComponentClass() {
return UIFocus.class;
}
-
- private UIFocusModifier findModifier(UIComponent component) {
- if (component instanceof UIFocusModifier) {
- return (UIFocusModifier) component;
- }
- UIFocusModifier modifier = (UIFocusModifier) component.getFacet(UIFocus.FOCUS_MODIFIER_FACET_NAME);
- if (modifier == null) {
- for (UIComponent child : component.getChildren()) {
- modifier = findModifier(child);
- if (modifier != null) {
- break;
- }
- }
- }
- return modifier;
- }
}