Search code examples
javaxpages

Need to put style-tag in head section in XPages, output goes to Excel


I have an XPage that allows the selection of a query-document. The full-text query that's inside it searches documents from the database, does some calculations and displays them as a view on the screen. There is also a button on the screen that sets requestScope.showExcel=true and does a full reload, in order to download the data directly into Excel (using .setHeader("Content-disposition", "inline; myfile.xls"). It is no more than a simple table with its tr and td tags. So far so good.

Column properties (height, width, colour) can be set per column, these are stored inside the query-document (which is a separate document, not part of the search results). Those properties are put into a style-tag element created using an xp:text control set to create html output.

It all works, except for one thing: Excel and OpenOffice or LibreOffice Calc don't like the style section in the body. When I save the output and move the styles to the head section the file loads okay in Excel.

So I went out to put our computed styling in the head section. I found the styleSheet resource, with its computed content parameter. It does generate some of the CSS I put in, but not all. As it turns out, the content is computed on load, and not dynamically. The button mentioned above does a full refresh of the page, which made me assume that styles would also be updated.

Alas, no. The stylesheet content seems to be fixed.

My questions:

  • Is there a way that inline CSS can be put in a style section in the head section in a dynamic way, so that it is recomputed when the page is reloaded (full update)?

  • Is there maybe some control somewhere that lets me add arbitrary content to the head section?

  • Or is there a way in Java to dynamically adapt the head section??

Thanks for your help!


Solution

  • Just create your own renderer for your header resource:

    package ch.hasselba.xpages.renderkit;
    
    import com.ibm.commons.util.StringUtil;
    import com.ibm.xsp.complex.Parameter;
    import com.ibm.xsp.render.ResourceRenderer;
    import com.ibm.xsp.resource.GenericHeadResource;
    import com.ibm.xsp.resource.Resource;
    import com.ibm.xsp.util.JSUtil;
    import java.io.IOException;
    import java.util.List;
    import javax.faces.component.UIComponent;
    import javax.faces.context.FacesContext;
    import javax.faces.context.ResponseWriter;
    
    public class GenericHeadResourceRenderer extends ResourceRenderer {
        public void encodeResource(FacesContext fc, UIComponent uiComponent,
                Resource res) throws IOException {
            GenericHeadResource headRes = (GenericHeadResource) res;
            ResponseWriter rw = fc.getResponseWriter();
    
            String tagName = headRes.getTagName();
            if (StringUtil.isNotEmpty(tagName)) {
    
                rw.startElement(tagName, uiComponent);
    
                List<Parameter> params = headRes.getAttributes();
                if (params != null) {
                    for (Parameter param : params) {
                        String name = param.getName();
                        if (StringUtil.isNotEmpty(name)) {
                            String value = param.getValue();
                            if (value == null) {
                                value = "";
                            }
                            if( "content".equals( name ) ){
                                rw.write( value );
                            }else{
                                rw.writeAttribute(name, value, name);
                            }
                        }
                    }
                }
                rw.endElement(tagName);
                JSUtil.writeln(rw);
            }
        }
    }
    

    To activate the renderer, you have to overwrite the existing one in the faces-config.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <faces-config version="1.2" xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd">
    
        <render-kit>
            <renderer>
                <component-family>com.ibm.xsp.resource.Resource</component-family>
                <renderer-type>com.ibm.xsp.resource.GenericHead</renderer-type>
                <renderer-class>ch.hasselba.xpages.renderkit.GenericHeadResourceRenderer</renderer-class>
            </renderer>
        </render-kit>
    
    </faces-config>
    

    Then, add the dynamic content you want in a parameter with the name "content":

    <?xml version="1.0" encoding="UTF-8"?>
    <xp:view xmlns:xp="http://www.ibm.com/xsp/core">
    
         <xp:this.resources>
             <xp:headTag tagName="style">
                 <xp:this.attributes>
                     <xp:parameter name="type" value="text/css" />
                     <xp:parameter name="content"
                        value="#{javascript:java.lang.System.currentTimeMillis()}" />
                 </xp:this.attributes>
             </xp:headTag>
        </xp:this.resources>
    
    </xp:view>