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 | 43 | </description> |
44 | 44 | <defaultvalue>""</defaultvalue> |
45 | 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 | 61 | </component> |
47 | 62 | </components> | ... | ... |
... | ... | @@ -5,32 +5,71 @@ import javax.faces.component.UIComponentBase; |
5 | 5 | import javax.faces.component.UIForm; |
6 | 6 | import javax.faces.component.UIInput; |
7 | 7 | import javax.faces.context.FacesContext; |
8 | +import java.util.ArrayList; | |
8 | 9 | import java.util.HashSet; |
9 | 10 | import java.util.Iterator; |
11 | +import java.util.List; | |
10 | 12 | import java.util.Set; |
11 | 13 | |
12 | 14 | public abstract class UIFocus extends UIComponentBase { |
15 | +// ------------------------------ FIELDS ------------------------------ | |
16 | + | |
17 | + public static final String COMPONENT_FAMILY = "org.richfaces.Focus"; | |
13 | 18 | |
14 | 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 | 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 | 53 | while (parentForm != null && !(parentForm instanceof UIForm)) { |
25 | 54 | parentForm = parentForm.getParent(); |
26 | 55 | } |
27 | 56 | if (parentForm != null) { |
28 | - return getUIInputChildrenCount(parentForm, getTargetComponentId(context)); | |
57 | + return getUIInputChildrenCount(parentForm, component.getId()); | |
29 | 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 | 73 | public String getTargetComponentId(FacesContext context) { |
35 | 74 | String aFor = getFor(); |
36 | 75 | |
... | ... | @@ -43,68 +82,49 @@ public abstract class UIFocus extends UIComponentBase { |
43 | 82 | while (clientIdsWithMessages.hasNext()) { |
44 | 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 | 97 | } else { |
49 | 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 | 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 | 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 | 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 | 118 | FacesContext facesContext = getFacesContext(); |
97 | 119 | for (UIComponent child : parent.getChildren()) { |
98 | 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 | 130 | private UIForm getParentForm(UIComponent component) { |
... | ... | @@ -118,4 +138,36 @@ public abstract class UIFocus extends UIComponentBase { |
118 | 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 | |
12 | 12 | // -------------------------- OTHER METHODS -------------------------- |
13 | 13 | |
14 | - public abstract String getTargetClientId(); | |
14 | + public abstract Integer getPriority(); | |
15 | 15 | |
16 | 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 | 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 | 32 | |
33 | 33 | import javax.faces.FacesException; |
34 | 34 | import javax.faces.component.UIComponent; |
35 | +import javax.faces.component.UIInput; | |
35 | 36 | import javax.faces.context.FacesContext; |
36 | 37 | import javax.faces.context.ResponseWriter; |
37 | 38 | import java.io.IOException; |
... | ... | @@ -58,6 +59,26 @@ public class HtmlFocusRenderer extends HeaderResourcesRendererBase { |
58 | 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 | 82 | @Override |
62 | 83 | protected void doEncodeEnd(ResponseWriter writer, FacesContext context, UIComponent component) |
63 | 84 | throws IOException { |
... | ... | @@ -66,11 +87,8 @@ public class HtmlFocusRenderer extends HeaderResourcesRendererBase { |
66 | 87 | } |
67 | 88 | UIFocus uiFocus = (UIFocus) component; |
68 | 89 | final String clientId = getUtils().clientId(context, component); |
69 | - checkValidity(clientId, uiFocus.getName(), uiFocus.getTiming()); | |
90 | + checkValidity(context, uiFocus); | |
70 | 91 | Integer priority = uiFocus.getPriority(); |
71 | - if (priority == null) { | |
72 | - priority = uiFocus.getDefaultPriority(context); | |
73 | - } | |
74 | 92 | String targetClientId = uiFocus.getTargetClientId(); |
75 | 93 | if (targetClientId == null || "".equals(targetClientId)) { |
76 | 94 | String targetComponentId = uiFocus.getTargetComponentId(context); |
... | ... | @@ -83,7 +101,7 @@ public class HtmlFocusRenderer extends HeaderResourcesRendererBase { |
83 | 101 | throw new FacesException("No component with id=" + targetComponentId + " found!"); |
84 | 102 | } |
85 | 103 | targetClientId = forcomp.getClientId(context); |
86 | - UIFocusModifier modifier = findModifier(forcomp); | |
104 | + UIFocusModifier modifier = UIFocus.findModifier(forcomp); | |
87 | 105 | if (modifier != null) { |
88 | 106 | final String modifiedTargetClientId = modifier.getTargetClientId(); |
89 | 107 | if (modifiedTargetClientId != null && !modifiedTargetClientId.equals("")) { |
... | ... | @@ -92,6 +110,9 @@ public class HtmlFocusRenderer extends HeaderResourcesRendererBase { |
92 | 110 | suffix = modifier.getSuffix(); |
93 | 111 | } |
94 | 112 | } |
113 | + if (priority == null) { | |
114 | + priority = uiFocus.calculatePriority(forcomp); | |
115 | + } | |
95 | 116 | if (suffix != null && !"".equals(suffix)) { |
96 | 117 | targetClientId += suffix; |
97 | 118 | } |
... | ... | @@ -99,6 +120,9 @@ public class HtmlFocusRenderer extends HeaderResourcesRendererBase { |
99 | 120 | if (targetClientId == null || targetClientId.equals("")) { |
100 | 121 | return; |
101 | 122 | } |
123 | + if (priority == null) { | |
124 | + priority = UIFocus.DEFAULT_PRIORITY; | |
125 | + } | |
102 | 126 | writer.startElement(RendererUtils.HTML.SCRIPT_ELEM, null); |
103 | 127 | writer.writeAttribute(RendererUtils.HTML.TYPE_ATTR, "text/javascript", "type"); |
104 | 128 | writer.writeAttribute(RendererUtils.HTML.id_ATTRIBUTE, clientId, RendererUtils.HTML.id_ATTRIBUTE); |
... | ... | @@ -119,34 +143,7 @@ public class HtmlFocusRenderer extends HeaderResourcesRendererBase { |
119 | 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 | 146 | protected Class<? extends UIComponent> getComponentClass() { |
134 | 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