According to JSF 2 h:button documentation:
Render an HTML "input" element of type "button". The value of the component is rendered as the button text and the outcome of the component is used to determine the target URL which is activated by onclick. If "image" attribute is specified, render it as the value of the "src" attribute after passing it to the getResourceURL() method of the ViewHandler for this application, and passing the result through the encodeResourceURL() method of the ExternalContext.
We can extend HtmlOutcomeTargetButton
, so we don't have to start from scratch.
This is our component class:
1 2 3 4 5 6 7 8 | @ResourceDependencies({ @ResourceDependency(library = "foundation", name = "css/foundation.min.css") }) @FacesComponent(createTag = true, namespace = "http://foundation.faces.com/taglib", tagName = "button") public class ButtonUI extends HtmlOutcomeTargetButton { //code } |
- The
@ResourceDependencies
annotation defines which resources this component requires to be rendered. - The
@FacesComponent
annotation defines the name of our component tag and also which namespace it uses.
taglib.xml
file, however most IDEs won't be able to identify its attributes for auto-completion.
To make it look like Foundation Buttons we have to add class="button"
to the generated HTML button and a few more attributes to our ButtonUI
:
- sizing: change the button size
- expanded: expand the button to fill the whole row
- coloring: change the button color related to a meaning
- hollow: invert the colors of the background/border and the font
- disabled: add opacity and prevent cursor events
Since all the attributes are related to the styleClass
, I don't need to reimplement the HtmlOutcomeTargetButton
enconding methods, all I have to do is to change the styleClass
value:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | @Override public void encodeBegin(FacesContext context) throws IOException { ResponseWriter writer = context.getResponseWriter(); this.setStyleClass(buildStyleClass()); super.encodeBegin(context); } public String buildStyleClass() { StringJoiner styleClass = new StringJoiner(" "); styleClass.add("button"); if (getStyleClass() != null) { styleClass.add(getStyleClass()); } if (getSizing() != null && getSizing().matches("(.*)(tiny|small|normal|large)(.*)")) { styleClass.add(getSizing()); } if (isExpanded()) { styleClass.add("expanded"); } if (getColoring() != null && getColoring().matches("(.*)(secondary|success|alert|warning)(.*)")) { styleClass.add(getColoring()); } if (isHollow()) { styleClass.add("hollow"); } if (isDisabled()) { styleClass.add("disabled"); } return styleClass.toString(); } |
Let's try our component
page.xhtml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html" xmlns:fo="http://foundation.faces.com/taglib"> <h:head> <title>Buttons</title> </h:head> <h:body > <h:form prependId="false"> <fo:button outcome="page2.xhtml" value="Tiny" sizing="tiny"/> <fo:button outcome="page2.xhtml" value="Small" sizing="small"/> <fo:button outcome="page2.xhtml" value="Normal"/> <fo:button outcome="page2.xhtml" value="Large" sizing="large"/> <fo:button outcome="page2.xhtml" value="Expanded small" sizing="small" expanded="true"/> <fo:button outcome="page2.xhtml" value="Expanded" expanded="true"/> <fo:button outcome="page2.xhtml" value="Secondary" coloring="secondary"/> <fo:button outcome="page2.xhtml" value="Success" coloring="success"/> <fo:button outcome="page2.xhtml" value="Alert" coloring="alert"/> <fo:button outcome="page2.xhtml" value="Warning" coloring="warning"/> <fo:button outcome="page2.xhtml" value="Hollow Secondary" coloring="secondary" hollow="true"/> <fo:button outcome="page2.xhtml" value="Hollow Success" coloring="success" hollow="true"/> <fo:button outcome="page2.xhtml" value="Hollow" hollow="true"/> <fo:button outcome="page2.xhtml" value="Hollow Alert" coloring="alert" hollow="true"/> <fo:button outcome="page2.xhtml" value="Hollow Warning" coloring="warning" hollow="true"/> <fo:button outcome="page2.xhtml" value="Disabled" disabled="true" /> </h:form> </h:body> </html> |
This is the output:
The only button that wasn't displayed as expected is the disabled one because it's almost invisible. Let's see what happened.
According to foundation documentation, a disabled button should be rendered like this:
1 | <a class="disabled button" href="#">Disabled Button</a> |
However, our disabled button received one unexpected attribute:
1 | <input value="Disabled" class="button disabled" disabled="disabled" type="button"> |
The disabled
attribute is used by JSF to disable the button, but that way we are applying 2 differente disabled styles simultaneosly:
1 2 3 4 5 6 7 8 9 | button.disabled { opacity: 0.25; cursor: not-allowed; pointer-events: none; } input:disabled, input[readonly], textarea:disabled, textarea[readonly] { background-color: #E6E6E6; cursor: default; } |
The simplest solution is to set disabled
to false after we have already built our styleClass attribute and before it's used by HtmlOutcomeTargetButton
encodeBegin
method:
1 2 3 4 5 6 7 | @Override public void encodeBegin(FacesContext context) throws IOException { ResponseWriter writer = context.getResponseWriter(); this.setStyleClass(buildStyleClass()); setDisabled(false); super.encodeBegin(context); } |
Now our disable button is rendered how it should:
ButtonUI
final source code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | package org.foundation.faces.components; import java.io.IOException; import java.util.StringJoiner; import javax.faces.application.ResourceDependencies; import javax.faces.application.ResourceDependency; import javax.faces.component.FacesComponent; import javax.faces.component.html.HtmlOutcomeTargetButton; import javax.faces.context.FacesContext; import javax.faces.context.ResponseWriter; @ResourceDependencies({ @ResourceDependency(library = "foundation", name = "css/foundation.min.css") }) @FacesComponent(createTag = true, namespace = "http://foundation.faces.com/taglib", tagName = "button") public class ButtonUI extends HtmlOutcomeTargetButton { enum PropertyKeys { sizing, expanded, coloring, hollow, disabled; } @Override public void encodeBegin(FacesContext context) throws IOException { ResponseWriter writer = context.getResponseWriter(); this.setStyleClass(buildStyleClass()); setDisabled(false); super.encodeBegin(context); } public String buildStyleClass() { StringJoiner styleClass = new StringJoiner(" "); styleClass.add("button"); if (getStyleClass() != null) { styleClass.add(getStyleClass()); } if (getSizing() != null && getSizing().matches("(.*)(tiny|small|normal|large)(.*)")) { styleClass.add(getSizing()); } if (isExpanded()) { styleClass.add("expanded"); } if (getColoring() != null && getColoring().matches("(.*)(secondary|success|alert|warning)(.*)")) { styleClass.add(getColoring()); } if (isHollow()) { styleClass.add("hollow"); } if (isDisabled()) { styleClass.add("disabled"); } return styleClass.toString(); } public String getSizing() { return (String) getStateHelper().eval(PropertyKeys.sizing, null); } public void setSizing(String sizing) { getStateHelper().put(PropertyKeys.sizing, sizing); } public Boolean isExpanded() { return (Boolean) getStateHelper().eval(PropertyKeys.expanded, Boolean.FALSE); } public void setExpanded(Boolean expanded) { getStateHelper().put(PropertyKeys.expanded, expanded); } public String getColoring() { return (String) getStateHelper().eval(PropertyKeys.coloring, null); } public void setColoring(String coloring) { getStateHelper().put(PropertyKeys.coloring, coloring); } public Boolean isHollow() { return (Boolean) getStateHelper().eval(PropertyKeys.hollow, Boolean.FALSE); } public void setHollow(Boolean hollow) { getStateHelper().put(PropertyKeys.hollow, hollow); } public boolean isDisabled() { return (Boolean) getStateHelper().eval(PropertyKeys.disabled, false); } public void setDisabled(boolean disabled) { getStateHelper().put(PropertyKeys.disabled, disabled); } } |
Nenhum comentário :