На форме jsf-страницы может быть расположено несколько UICommand компонент. Необходима возможность указать, какая компонента должна срабатывать при нажатии ENTER в одном из полей ввода.
Для этого будем обрабатывать onkeypressed внутри формы. То, какая компонента будет срабатывать и в каком контейнере, будем указывать с помощью классов “control” и “container”.
Также разработаем jsf-компоненту, которая будет показывать, внутри какого контейнера должен вызываться данный UICommand при нажатии ENTER в поле ввода.
<h:form id=”default”>
<t:panelGrid id=”cont” >
<t:inputText value=”#{testInfo.name}”/>
<t:commandButton type=”button” action=”#{testInfo.act1}” value=”button” />
<t:commandLink action=”#{testInfo.act2}” value=”link” >
<jsfaces:test forId=”cont”/>
</t:commandLink>
</t:panelGrid>
<t:panelGrid id=”cont2″>
<t:inputText value=”#{testInfo.name}”/>
<t:commandButton action=”#{testInfo.act1}” value=”button”>
<jsfaces:test forId=”cont2″ />
</t:commandButton>
<t:commandLink action=”#{testInfo.act2}” value=”link” />
</t:panelGrid>
</h:form>
Внутри сont все нажатия ENTER должны обрабатыватся с помощью CommandLink, внутри cont2 – CommandButton.
Код JS для обработки нажатия ENTER:
var onloadFunctions = new Array() ;
var FindHandler = new Object() ;
FindHandler.testClass = function(className) {
var classN = new RegExp(”(^|\\s)” + className + “(\\s|$)”);
return classN.test(className) ;
}
FindHandler.getParentByClass = function(className, tag) {
while (tag.parentNode) {
if (tag.className && this.testClass(tag.className)) {
return tag ;
} else {
tag = tag.parentNode ;
}
}
return null ;
}
FindHandler.getElementsByClassName = function(className, tag) {
var returnElements = new Array() ;
for (var i = 0 ; i < tag.childNodes.length; i ++) {
if (tag.childNodes[i].className && this.testClass(tag.childNodes[i].className)) {
returnElements.push(tag.childNodes[i]) ;
}
}
for (var i = 0 ; i < tag.childNodes.length; i ++) {
var ret = this.getElementsByClassName(className, tag.childNodes[i]) ;
if (ret) {
for (var j = 0 ; j 0 ? returnElements : null ;
}
var KeyCode = new Object() ;
KeyCode.VK_ENTER = 13 ;
var f1 = function() {
var form = document.forms[0] ;
if (form) {
form.onkeypress = function(e) {
var key;
if (window.event)
key = window.event.keyCode; //IE
else
key = e.which; //firefox
if (key == KeyCode.VK_ENTER) {
var target ;
if (window.event) {
target = window.event.srcElement ;
} else {
target = e.target ;
}
var parent = FindHandler.getParentByClass(”container”, target) ;
// alert(parent) ;
if (parent) {
var controls = FindHandler.getElementsByClassName(”control”, parent) ;
if (controls && controls[0]) {
// alert(controls[0].tagName) ;
if (controls[0].tagName == “INPUT” || controls[0].tagName == “BUTTON”) {
controls[0].click() ;
} else {
controls[0].onclick() ;
}
}
}
}
return false ;
}
}
}
onloadFunctions.push(f1) ;
window.onload = function() {
for (var i = 0 ; i < onloadFunctions.length; i ++) {
onloadFunctions[i]() ;
}
}
Классы компоненты:
UITest.java:
public class UITest extends UIComponentBase implements NamingContainer {
public void restoreState(FacesContext facesContext, Object object) {
if (object instanceof Object[]) {
Object[] state = (Object[]) object ;
super.restoreState(facesContext, state[0]);
forId = (String) state[1] ;
} else {
super.restoreState(facesContext, object); //To change body of overridden methods use File | Settings | File Templates.
}
}
public Object saveState(FacesContext facesContext) {
Object[] state = new Object[2] ;
state[0] = super.saveState(facesContext) ;
state[1] = forId ;
return state ; //To change body of overridden methods use File | Settings | File Templates.
}
public static final String COMPONENT_TYPE = “ru.js.faces.component.test.Test” ;
public static final String COMPONENT_FAMILY = “ru.js.faces.component.test.Test” ;
public static final String RENDERER_TYPE = “ru.js.faces.component.test.TestRenderer” ;
public UITest() {
super() ;
setRendererType(RENDERER_TYPE) ;
}
public String getFamily() {
return COMPONENT_FAMILY ; //To change body of implemented methods use File | Settings | File Templates.
}
private String forId ;
public String getForId() {
return forId;
}
public void setForId(String forId) {
this.forId = forId;
}
}
TestTag.java:
public class TestTag extends UIComponentTag {
public String getComponentType() {
return UITest.COMPONENT_TYPE; //To change body of implemented methods use File | Settings | File Templates.
}
public String getRendererType() {
return UITest.RENDERER_TYPE; //To change body of implemented methods use File | Settings | File Templates.
}
public String forId;
public String getForId() {
return forId;
}
public void setForId(String forId) {
this.forId = forId;
}
protected void setProperties(UIComponent uiComponent) {
super.setProperties(uiComponent); //To change body of overridden methods use File | Settings | File Templates.
if (null != getForId()) {
((UITest)uiComponent).setForId(getForId());
}
}
}
TestRenderer.java:
public class TestRenderer extends Renderer {
@Override
public void encodeBegin(FacesContext facesContext, UIComponent uiComponent) throws IOException {
super.encodeBegin(facesContext, uiComponent); //To change body of overridden methods use File | Settings | File Templates.
UITest testComponent = (UITest) uiComponent ;
ResponseWriter writer = facesContext.getResponseWriter();
writer.startElement(”script”, testComponent);
writer.writeAttribute(”type”, “text/javascript”, null);
String containerId = ((UITest)uiComponent).getForId() ;
UIComponent parent = uiComponent.getParent() ;
String controlId = parent.getId() ;
//JavaScript в данном случае добавляет к фунциям, которые выполнятся при загрузке еще одну. В ней элементам контейнера и контрола будут присваиваться соответствующие классы
writer.writeText(”var “+ controlId +”UseOnEnter = function () { var container = document.getElementById(document.forms[0].id + ‘:’ + ‘”+ containerId + “‘) ;\n” +
”var control = document.getElementById(document.forms[0].id + ‘:’ + ‘” + controlId + “‘); \n” +
”container.className = container.className + ‘ container’ ;\n” +
”control.className = control.className + ‘ control’; }\n” +
”onloadFunctions.push(”+ controlId +”UseOnEnter)”, null) ;
writer.endElement(”script”);
}
}
Описание компоненты и рендерера в faces-config.xml:
<component>
<component-type>ru.js.faces.component.test.Test</component-type>
<component-class>ru.js.faces.component.test.UITest</component-class>
<property>
<property-name>value</property-name>
<property-class>java.lang.String</property-class>
</property>
</component>
<render-kit>
<renderer>
<component-family>ru.js.faces.component.test.Test</component-family>
<renderer-type>ru.js.faces.component.test.TestRenderer</renderer-type>
<renderer-class>ru.js.faces.component.test.TestRenderer</renderer-class>
</renderer>
</render-kit>
Описание тега в components.tld:
<tag>
<name>test</name>
<tag-class>ru.js.faces.component.test.TestTag</tag-class>
<body-content>empty</body-content>
<attribute>
<name>forId</name>
<type>java.lang.String</type>
<required>true</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<name>id</name>
<type>java.lang.String</type>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>
Подключение components.tld в web.xml:
<jsp-config>
<taglib>
<taglib-uri>http://jsfaces</taglib-uri>
<taglib-location>/WEB-INF/components.tld</taglib-location>
</taglib>
</jsp-config>