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