XPages: Empty HTML5 Attibutes & PassThroughTags

A while ago I developed some HTML5 XPages applications, but the development process was a little bit frustrating because of the missing possibility to add empty attributes to a PassThroughTag.  A single empty attribute is not allowed, because this would result in invalid XML, and you cannot use „xp:attributes“ with „UIPassThroughTag“ components.

A simple example like this…

<input type="text" value="John Doe" disabled />

… always ended up in something like this:

<xp:text tagName="input" disableTheme="true">
   <xp:this.attrs>
      <xp:attr name="disabled" minimized="true" value="disabled" />
      <xp:attr name="value" value="John Doe" />
   </xp:this.attrs>
</xp:text>

To fit my requirements, I had extended the „UIPassThroughTag“ with a special attribute named „emptyAttrs„. This allowed me to write the example above in the following syntax:

<input type="text" value="John Doe" emptyAttrs="disabled" />

(Multiple empty attributes can be added comma separated.)

Here is the Java class:

package ch.hasselba.xpages;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;

import com.ibm.xsp.component.UIPassThroughTag;
import com.ibm.xsp.renderkit.html_basic.PassThroughTagRenderer;
import com.ibm.xsp.webapp.XspHttpServletResponse;

public class PassThroughTagRendererEx extends PassThroughTagRenderer {

    private final static String EMPTY_ATTRIBUTE_NAME = "emptyAttrs";
    
    public void encodeBegin(FacesContext fc, UIComponent uiComponent)
            throws IOException {

        // Component is rendered?
        if (uiComponent.isRendered() == false) {
            return;
        }
        
        // only process instances of UIPassThroughTags
        if ((uiComponent instanceof UIPassThroughTag)) {
            
            UIPassThroughTag uiPTTag = (UIPassThroughTag) uiComponent;
            
            ResponseWriter rw = fc.getResponseWriter();
            
            // grab the printer writer directly from the response
            XspHttpServletResponse response = (XspHttpServletResponse) 
                fc.getExternalContext().getResponse();

            PrintWriter rwPrinter = response.getWriter();
            
            // start the element tag
            rw.startElement(uiPTTag.getTag(), uiComponent);
            
            // process all attributes
            List<UIPassThroughTag.TagAttribute> attrList = uiPTTag
                    .getTagAttributes();
            
            if (attrList != null) {

                UIPassThroughTag.TagAttribute tagAttribute = null;
                String attrName = null;
                String attrValue = null;

                for (int i = 0; i < attrList.size(); i++) {
                    tagAttribute = attrList.get(i);
                    attrName = tagAttribute.getName();
                    attrValue = tagAttribute.getValue();
                    if (EMPTY_ATTRIBUTE_NAME.equalsIgnoreCase(attrName)) {
                        
                        // process all empty tags
                        String tags[] = attrValue.split(",");
                        for( int j=0; j<tags.length; j++){
                            // write the attribute name only
                            rwPrinter.write( " " );
                            rwPrinter.write( tags[j].trim() );
                        }
                    }else{
                            // write the attribute data
                            rw.writeAttribute(attrName, attrValue, null);
                    }
                }
                
            }
        } else {
            // process other instances "as always"
            super.encodeBegin(fc, uiComponent);
        }
    }

}

To activate the class you have to overwrite the renderer in the „faces-config.xml„:

<?xml version="1.0" encoding="UTF-8"?>
<faces-config>
  <render-kit>
    <renderer>
      <component-family>javax.faces.Output</component-family>
      <renderer-type>com.ibm.xsp.PassThroughTagRenderer</renderer-type>
      <renderer-class>ch.hasselba.xpages.PassThroughTagRendererEx</renderer-class>
    </renderer>
  </render-kit>
</faces-config>
Dieser Beitrag wurde unter HTML5, XPages abgelegt und mit , , , verschlagwortet. Setze ein Lesezeichen auf den Permalink.

2 Kommentare zu XPages: Empty HTML5 Attibutes & PassThroughTags

  1. Txemanu Calle sagt:

    Ok, I quit, I was just trying to paste the code of a xp:text wich returns HTML (escape=“false“) and here you have 100% control of the HTML rendered, and empty attributes can be used.

    You can remove the spam comments 🙂

    • Thanks for your comments 🙂

      Sure, you can also do this. But it is just a crutch, and makes plain HTML code not easier to read / maintain. And you have to disable the theme again for every component, or there is a span tag around your html element.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.