На форме 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>