Commit de8ad4670d8e735edc5eb3202bd564b54fe9e103
1 parent
b536dfe6
Added priority and skipped attributes to focus component.
Showing
4 changed files
with
152 additions
and
80 deletions
@@ -43,5 +43,20 @@ | @@ -43,5 +43,20 @@ | ||
43 | </description> | 43 | </description> |
44 | <defaultvalue>""</defaultvalue> | 44 | <defaultvalue>""</defaultvalue> |
45 | </property> | 45 | </property> |
46 | + <property> | ||
47 | + <name>priority</name> | ||
48 | + <classname>java.lang.Integer</classname> | ||
49 | + <description> | ||
50 | + If there are more components requesting focus, then component with lowest priority will be focused. | ||
51 | + </description> | ||
52 | + </property> | ||
53 | + <property> | ||
54 | + <name>skipped</name> | ||
55 | + <classname>boolean</classname> | ||
56 | + <description> | ||
57 | + If set to true, component will not be concerned when calculating default focus. | ||
58 | + </description> | ||
59 | + <defaultvalue>false</defaultvalue> | ||
60 | + </property> | ||
46 | </component> | 61 | </component> |
47 | </components> | 62 | </components> |
@@ -5,32 +5,71 @@ import javax.faces.component.UIComponentBase; | @@ -5,32 +5,71 @@ import javax.faces.component.UIComponentBase; | ||
5 | import javax.faces.component.UIForm; | 5 | import javax.faces.component.UIForm; |
6 | import javax.faces.component.UIInput; | 6 | import javax.faces.component.UIInput; |
7 | import javax.faces.context.FacesContext; | 7 | import javax.faces.context.FacesContext; |
8 | +import java.util.ArrayList; | ||
8 | import java.util.HashSet; | 9 | import java.util.HashSet; |
9 | import java.util.Iterator; | 10 | import java.util.Iterator; |
11 | +import java.util.List; | ||
10 | import java.util.Set; | 12 | import java.util.Set; |
11 | 13 | ||
12 | public abstract class UIFocus extends UIComponentBase { | 14 | public abstract class UIFocus extends UIComponentBase { |
15 | +// ------------------------------ FIELDS ------------------------------ | ||
16 | + | ||
17 | + public static final String COMPONENT_FAMILY = "org.richfaces.Focus"; | ||
13 | 18 | ||
14 | public static final String COMPONENT_TYPE = "org.richfaces.Focus"; | 19 | public static final String COMPONENT_TYPE = "org.richfaces.Focus"; |
15 | 20 | ||
16 | - public static final String COMPONENT_FAMILY = "org.richfaces.Focus"; | 21 | + public static final int DEFAULT_PRIORITY = Integer.MAX_VALUE; |
22 | + | ||
23 | + public static final String FOCUS_MODIFIER_FACET_NAME = "focusModifier"; | ||
17 | 24 | ||
18 | public static final String TIMING_ON_LOAD = "onload"; | 25 | public static final String TIMING_ON_LOAD = "onload"; |
19 | 26 | ||
20 | - public static final String FOCUS_MODIFIER_FACET_NAME = "focusModifier"; | 27 | +// -------------------------- STATIC METHODS -------------------------- |
21 | 28 | ||
22 | - public Integer getDefaultPriority(FacesContext context) { | ||
23 | - UIComponent parentForm = getParent(); | 29 | + public static UIFocusModifier findModifier(UIComponent component) { |
30 | + if (component instanceof UIFocusModifier) { | ||
31 | + return (UIFocusModifier) component; | ||
32 | + } | ||
33 | + UIFocusModifier modifier = (UIFocusModifier) component.getFacet(UIFocus.FOCUS_MODIFIER_FACET_NAME); | ||
34 | + if (modifier == null) { | ||
35 | + for (UIComponent child : component.getChildren()) { | ||
36 | + modifier = findModifier(child); | ||
37 | + if (modifier != null) { | ||
38 | + break; | ||
39 | + } | ||
40 | + } | ||
41 | + } | ||
42 | + return modifier; | ||
43 | + } | ||
44 | + | ||
45 | +// -------------------------- OTHER METHODS -------------------------- | ||
46 | + | ||
47 | + public int calculatePriority(UIComponent component) { | ||
48 | + final UIFocusModifier modifier = findModifier(component); | ||
49 | + if (modifier != null && modifier.getPriority() != null) { | ||
50 | + return modifier.getPriority(); | ||
51 | + } | ||
52 | + UIComponent parentForm = component.getParent(); | ||
24 | while (parentForm != null && !(parentForm instanceof UIForm)) { | 53 | while (parentForm != null && !(parentForm instanceof UIForm)) { |
25 | parentForm = parentForm.getParent(); | 54 | parentForm = parentForm.getParent(); |
26 | } | 55 | } |
27 | if (parentForm != null) { | 56 | if (parentForm != null) { |
28 | - return getUIInputChildrenCount(parentForm, getTargetComponentId(context)); | 57 | + return getUIInputChildrenCount(parentForm, component.getId()); |
29 | } else { | 58 | } else { |
30 | - return Integer.MAX_VALUE; | 59 | + return DEFAULT_PRIORITY; |
31 | } | 60 | } |
32 | } | 61 | } |
33 | 62 | ||
63 | + public abstract String getFor(); | ||
64 | + | ||
65 | + public abstract String getName(); | ||
66 | + | ||
67 | + public abstract Integer getPriority(); | ||
68 | + | ||
69 | + public abstract String getSuffix(); | ||
70 | + | ||
71 | + public abstract String getTargetClientId(); | ||
72 | + | ||
34 | public String getTargetComponentId(FacesContext context) { | 73 | public String getTargetComponentId(FacesContext context) { |
35 | String aFor = getFor(); | 74 | String aFor = getFor(); |
36 | 75 | ||
@@ -43,68 +82,49 @@ public abstract class UIFocus extends UIComponentBase { | @@ -43,68 +82,49 @@ public abstract class UIFocus extends UIComponentBase { | ||
43 | while (clientIdsWithMessages.hasNext()) { | 82 | while (clientIdsWithMessages.hasNext()) { |
44 | allowedClientIds.add(clientIdsWithMessages.next()); | 83 | allowedClientIds.add(clientIdsWithMessages.next()); |
45 | } | 84 | } |
46 | - UIComponent component = getFirstInput(getParentForm(this), allowedClientIds); | ||
47 | - return component == null ? null : component.getClientId(context); | 85 | + final List<UIInput> inputs = new ArrayList<UIInput>(); |
86 | + getInputs(getParentForm(this), allowedClientIds, inputs); | ||
87 | + UIInput inputWithLowestPriority = null; | ||
88 | + int lowestPriority = Integer.MAX_VALUE; | ||
89 | + for (UIInput input : inputs) { | ||
90 | + final int priority = calculatePriority(input); | ||
91 | + if (priority < lowestPriority) { | ||
92 | + inputWithLowestPriority = input; | ||
93 | + lowestPriority = priority; | ||
94 | + } | ||
95 | + } | ||
96 | + return inputWithLowestPriority == null ? null : inputWithLowestPriority.getClientId(context); | ||
48 | } else { | 97 | } else { |
49 | return getParent().getClientId(context); | 98 | return getParent().getClientId(context); |
50 | } | 99 | } |
51 | } | 100 | } |
52 | } | 101 | } |
53 | 102 | ||
54 | - private int getUIInputChildrenCount(UIComponent component, String breakOnId) { | ||
55 | - int inputComponentsCount = 0; | ||
56 | - for (UIComponent child : component.getChildren()) { | ||
57 | - if (child.getId().equals(breakOnId)) { | ||
58 | - break; | ||
59 | - } | ||
60 | - if (child instanceof UIInput) { | ||
61 | - inputComponentsCount++; | ||
62 | - } else { | ||
63 | - int uIInputChildrenCount = getUIInputChildrenCount(child, breakOnId); | ||
64 | - inputComponentsCount += uIInputChildrenCount; | ||
65 | - } | ||
66 | - } | ||
67 | - return inputComponentsCount; | ||
68 | - } | ||
69 | - | ||
70 | - public abstract String getFor(); | 103 | + public abstract String getTiming(); |
71 | 104 | ||
72 | public abstract void setFor(String value); | 105 | public abstract void setFor(String value); |
73 | 106 | ||
74 | - public abstract String getTargetClientId(); | ||
75 | - | ||
76 | - public abstract void setTargetClientId(String targetClientId); | ||
77 | - | ||
78 | - public abstract String getSuffix(); | ||
79 | - | ||
80 | - public abstract void setSuffix(String value); | ||
81 | - | ||
82 | - public abstract Integer getPriority(); | 107 | + public abstract void setName(String name); |
83 | 108 | ||
84 | public abstract void setPriority(Integer value); | 109 | public abstract void setPriority(Integer value); |
85 | 110 | ||
86 | - public abstract String getTiming(); | ||
87 | - | ||
88 | - public abstract String getName(); | 111 | + public abstract void setSuffix(String value); |
89 | 112 | ||
90 | - public abstract void setName(String name); | 113 | + public abstract void setTargetClientId(String targetClientId); |
91 | 114 | ||
92 | public abstract void setTiming(String timing); | 115 | public abstract void setTiming(String timing); |
93 | 116 | ||
94 | - private UIComponent getFirstInput(UIComponent parent, Set<String> allowedClientIds) { | ||
95 | - UIComponent input = null; | 117 | + private void getInputs(UIComponent parent, Set<String> allowedClientIds, List<UIInput> inputs) { |
96 | FacesContext facesContext = getFacesContext(); | 118 | FacesContext facesContext = getFacesContext(); |
97 | for (UIComponent child : parent.getChildren()) { | 119 | for (UIComponent child : parent.getChildren()) { |
98 | if (child instanceof UIInput && (allowedClientIds.size() == 0 || allowedClientIds.contains(child.getClientId(facesContext)))) { | 120 | if (child instanceof UIInput && (allowedClientIds.size() == 0 || allowedClientIds.contains(child.getClientId(facesContext)))) { |
99 | - return child; | ||
100 | - } else { | ||
101 | - input = getFirstInput(child, allowedClientIds); | ||
102 | - if (input != null) { | ||
103 | - break; | 121 | + final UIFocusModifier modifier = findModifier(child); |
122 | + if (modifier == null || !modifier.isSkipped()) { | ||
123 | + inputs.add((UIInput) child); | ||
104 | } | 124 | } |
105 | } | 125 | } |
126 | + getInputs(child, allowedClientIds, inputs); | ||
106 | } | 127 | } |
107 | - return input; | ||
108 | } | 128 | } |
109 | 129 | ||
110 | private UIForm getParentForm(UIComponent component) { | 130 | private UIForm getParentForm(UIComponent component) { |
@@ -118,4 +138,36 @@ public abstract class UIFocus extends UIComponentBase { | @@ -118,4 +138,36 @@ public abstract class UIFocus extends UIComponentBase { | ||
118 | return getParentForm(parent); | 138 | return getParentForm(parent); |
119 | } | 139 | } |
120 | } | 140 | } |
141 | + | ||
142 | + private int getUIInputChildrenCount(UIComponent component, String breakOnId) { | ||
143 | + final Holder<Integer> childrenCount = new Holder<Integer>(); | ||
144 | + childrenCount.value = 0; | ||
145 | + getUIInputChildrenCount(component, breakOnId, childrenCount); | ||
146 | + return childrenCount.value; | ||
147 | + } | ||
148 | + | ||
149 | + private boolean getUIInputChildrenCount(UIComponent component, String breakOnId, Holder<Integer> childrenCount) { | ||
150 | + for (UIComponent child : component.getChildren()) { | ||
151 | + if (child.getId().equals(breakOnId)) { | ||
152 | + return true; | ||
153 | + } | ||
154 | + if (child instanceof UIInput) { | ||
155 | + final UIFocusModifier modifier = findModifier(child); | ||
156 | + if (modifier == null || !modifier.isSkipped()) { | ||
157 | + childrenCount.value++; | ||
158 | + } | ||
159 | + } else { | ||
160 | + if (getUIInputChildrenCount(child, breakOnId, childrenCount)) return true; | ||
161 | + } | ||
162 | + } | ||
163 | + return false; | ||
164 | + } | ||
165 | + | ||
166 | +// -------------------------- INNER CLASSES -------------------------- | ||
167 | + | ||
168 | + private class Holder<T> { | ||
169 | +// ------------------------------ FIELDS ------------------------------ | ||
170 | + | ||
171 | + public T value; | ||
172 | + } | ||
121 | } | 173 | } |
@@ -11,11 +11,19 @@ public abstract class UIFocusModifier extends UIComponentBase { | @@ -11,11 +11,19 @@ public abstract class UIFocusModifier extends UIComponentBase { | ||
11 | 11 | ||
12 | // -------------------------- OTHER METHODS -------------------------- | 12 | // -------------------------- OTHER METHODS -------------------------- |
13 | 13 | ||
14 | - public abstract String getTargetClientId(); | 14 | + public abstract Integer getPriority(); |
15 | 15 | ||
16 | public abstract String getSuffix(); | 16 | public abstract String getSuffix(); |
17 | 17 | ||
18 | - public abstract void setTargetClientId(String focusClientId); | 18 | + public abstract String getTargetClientId(); |
19 | + | ||
20 | + public abstract boolean isSkipped(); | ||
21 | + | ||
22 | + public abstract void setPriority(Integer priority); | ||
23 | + | ||
24 | + public abstract void setSkipped(boolean skipped); | ||
19 | 25 | ||
20 | public abstract void setSuffix(String value); | 26 | public abstract void setSuffix(String value); |
27 | + | ||
28 | + public abstract void setTargetClientId(String focusClientId); | ||
21 | } | 29 | } |
@@ -32,6 +32,7 @@ import org.richfaces.component.UIFocusModifier; | @@ -32,6 +32,7 @@ import org.richfaces.component.UIFocusModifier; | ||
32 | 32 | ||
33 | import javax.faces.FacesException; | 33 | import javax.faces.FacesException; |
34 | import javax.faces.component.UIComponent; | 34 | import javax.faces.component.UIComponent; |
35 | +import javax.faces.component.UIInput; | ||
35 | import javax.faces.context.FacesContext; | 36 | import javax.faces.context.FacesContext; |
36 | import javax.faces.context.ResponseWriter; | 37 | import javax.faces.context.ResponseWriter; |
37 | import java.io.IOException; | 38 | import java.io.IOException; |
@@ -58,6 +59,26 @@ public class HtmlFocusRenderer extends HeaderResourcesRendererBase { | @@ -58,6 +59,26 @@ public class HtmlFocusRenderer extends HeaderResourcesRendererBase { | ||
58 | return styles; | 59 | return styles; |
59 | } | 60 | } |
60 | 61 | ||
62 | + private void checkValidity(FacesContext context, UIFocus component) { | ||
63 | + String clientId = getUtils().clientId(context, component); | ||
64 | + String name = component.getName(); | ||
65 | + String timing = component.getTiming(); | ||
66 | + String _for = component.getFor(); | ||
67 | + String targetClientId = component.getTargetClientId(); | ||
68 | + if ((name == null || "".equals(name.trim())) && "onJScall".equals(timing)) { | ||
69 | + throw new FacesException( | ||
70 | + "The name attribute of the focus component (id='" + clientId + "') must be specified when timing attribute equals to 'onJScall'"); | ||
71 | + } | ||
72 | + if (name != null && !"".equals(name.trim()) && !"onJScall".equals(timing)) { | ||
73 | + throw new FacesException( | ||
74 | + "The timing attribute of the focus component (id='" + clientId + "') must be set to 'onJScall' when name attribute is specified"); | ||
75 | + } | ||
76 | + if ((_for == null || "".equals(_for)) && (targetClientId == null || "".equals(targetClientId)) && !(component.getParent() instanceof UIInput) | ||
77 | + && getUtils().getNestingForm(context, component) == null) { | ||
78 | + throw new FacesException("Focus component must have either one of 'for' or 'targetClientId' attributes specified or be nested within UIForm or UIInput component"); | ||
79 | + } | ||
80 | + } | ||
81 | + | ||
61 | @Override | 82 | @Override |
62 | protected void doEncodeEnd(ResponseWriter writer, FacesContext context, UIComponent component) | 83 | protected void doEncodeEnd(ResponseWriter writer, FacesContext context, UIComponent component) |
63 | throws IOException { | 84 | throws IOException { |
@@ -66,11 +87,8 @@ public class HtmlFocusRenderer extends HeaderResourcesRendererBase { | @@ -66,11 +87,8 @@ public class HtmlFocusRenderer extends HeaderResourcesRendererBase { | ||
66 | } | 87 | } |
67 | UIFocus uiFocus = (UIFocus) component; | 88 | UIFocus uiFocus = (UIFocus) component; |
68 | final String clientId = getUtils().clientId(context, component); | 89 | final String clientId = getUtils().clientId(context, component); |
69 | - checkValidity(clientId, uiFocus.getName(), uiFocus.getTiming()); | 90 | + checkValidity(context, uiFocus); |
70 | Integer priority = uiFocus.getPriority(); | 91 | Integer priority = uiFocus.getPriority(); |
71 | - if (priority == null) { | ||
72 | - priority = uiFocus.getDefaultPriority(context); | ||
73 | - } | ||
74 | String targetClientId = uiFocus.getTargetClientId(); | 92 | String targetClientId = uiFocus.getTargetClientId(); |
75 | if (targetClientId == null || "".equals(targetClientId)) { | 93 | if (targetClientId == null || "".equals(targetClientId)) { |
76 | String targetComponentId = uiFocus.getTargetComponentId(context); | 94 | String targetComponentId = uiFocus.getTargetComponentId(context); |
@@ -83,7 +101,7 @@ public class HtmlFocusRenderer extends HeaderResourcesRendererBase { | @@ -83,7 +101,7 @@ public class HtmlFocusRenderer extends HeaderResourcesRendererBase { | ||
83 | throw new FacesException("No component with id=" + targetComponentId + " found!"); | 101 | throw new FacesException("No component with id=" + targetComponentId + " found!"); |
84 | } | 102 | } |
85 | targetClientId = forcomp.getClientId(context); | 103 | targetClientId = forcomp.getClientId(context); |
86 | - UIFocusModifier modifier = findModifier(forcomp); | 104 | + UIFocusModifier modifier = UIFocus.findModifier(forcomp); |
87 | if (modifier != null) { | 105 | if (modifier != null) { |
88 | final String modifiedTargetClientId = modifier.getTargetClientId(); | 106 | final String modifiedTargetClientId = modifier.getTargetClientId(); |
89 | if (modifiedTargetClientId != null && !modifiedTargetClientId.equals("")) { | 107 | if (modifiedTargetClientId != null && !modifiedTargetClientId.equals("")) { |
@@ -92,6 +110,9 @@ public class HtmlFocusRenderer extends HeaderResourcesRendererBase { | @@ -92,6 +110,9 @@ public class HtmlFocusRenderer extends HeaderResourcesRendererBase { | ||
92 | suffix = modifier.getSuffix(); | 110 | suffix = modifier.getSuffix(); |
93 | } | 111 | } |
94 | } | 112 | } |
113 | + if (priority == null) { | ||
114 | + priority = uiFocus.calculatePriority(forcomp); | ||
115 | + } | ||
95 | if (suffix != null && !"".equals(suffix)) { | 116 | if (suffix != null && !"".equals(suffix)) { |
96 | targetClientId += suffix; | 117 | targetClientId += suffix; |
97 | } | 118 | } |
@@ -99,6 +120,9 @@ public class HtmlFocusRenderer extends HeaderResourcesRendererBase { | @@ -99,6 +120,9 @@ public class HtmlFocusRenderer extends HeaderResourcesRendererBase { | ||
99 | if (targetClientId == null || targetClientId.equals("")) { | 120 | if (targetClientId == null || targetClientId.equals("")) { |
100 | return; | 121 | return; |
101 | } | 122 | } |
123 | + if (priority == null) { | ||
124 | + priority = UIFocus.DEFAULT_PRIORITY; | ||
125 | + } | ||
102 | writer.startElement(RendererUtils.HTML.SCRIPT_ELEM, null); | 126 | writer.startElement(RendererUtils.HTML.SCRIPT_ELEM, null); |
103 | writer.writeAttribute(RendererUtils.HTML.TYPE_ATTR, "text/javascript", "type"); | 127 | writer.writeAttribute(RendererUtils.HTML.TYPE_ATTR, "text/javascript", "type"); |
104 | writer.writeAttribute(RendererUtils.HTML.id_ATTRIBUTE, clientId, RendererUtils.HTML.id_ATTRIBUTE); | 128 | writer.writeAttribute(RendererUtils.HTML.id_ATTRIBUTE, clientId, RendererUtils.HTML.id_ATTRIBUTE); |
@@ -119,34 +143,7 @@ public class HtmlFocusRenderer extends HeaderResourcesRendererBase { | @@ -119,34 +143,7 @@ public class HtmlFocusRenderer extends HeaderResourcesRendererBase { | ||
119 | writer.endElement(RendererUtils.HTML.SCRIPT_ELEM); | 143 | writer.endElement(RendererUtils.HTML.SCRIPT_ELEM); |
120 | } | 144 | } |
121 | 145 | ||
122 | - private void checkValidity(String clientId, String name, String timing) { | ||
123 | - if ((name == null || "".equals(name.trim())) && "onJScall".equals(timing)) { | ||
124 | - throw new FacesException( | ||
125 | - "The name attribute of the focus component (id='" + clientId + "') must be specified when timing attribute equals to 'onJScall'"); | ||
126 | - } | ||
127 | - if (name != null && !"".equals(name.trim()) && !"onJScall".equals(timing)) { | ||
128 | - throw new FacesException( | ||
129 | - "The timing attribute of the focus component (id='" + clientId + "') must be set to 'onJScall' when name attribute is specified"); | ||
130 | - } | ||
131 | - } | ||
132 | - | ||
133 | protected Class<? extends UIComponent> getComponentClass() { | 146 | protected Class<? extends UIComponent> getComponentClass() { |
134 | return UIFocus.class; | 147 | return UIFocus.class; |
135 | } | 148 | } |
136 | - | ||
137 | - private UIFocusModifier findModifier(UIComponent component) { | ||
138 | - if (component instanceof UIFocusModifier) { | ||
139 | - return (UIFocusModifier) component; | ||
140 | - } | ||
141 | - UIFocusModifier modifier = (UIFocusModifier) component.getFacet(UIFocus.FOCUS_MODIFIER_FACET_NAME); | ||
142 | - if (modifier == null) { | ||
143 | - for (UIComponent child : component.getChildren()) { | ||
144 | - modifier = findModifier(child); | ||
145 | - if (modifier != null) { | ||
146 | - break; | ||
147 | - } | ||
148 | - } | ||
149 | - } | ||
150 | - return modifier; | ||
151 | - } | ||
152 | } | 149 | } |
Please
register
or
login
to post a comment