/* * � Copyright IBM Corp. 2010, 2013 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. */ package com.ibm.xsp.extlib.renderkit.dojo; import java.io.IOException; import java.util.Map; import javax.faces.component.UIComponent; import javax.faces.component.UIInput; import javax.faces.context.FacesContext; import javax.faces.context.ResponseWriter; import com.ibm.commons.util.StringUtil; import com.ibm.xsp.ajax.AjaxUtil; import com.ibm.xsp.component.UIViewRootEx; import com.ibm.xsp.dojo.FacesDojoComponent; import com.ibm.xsp.extlib.component.dojo.UIDojoWidgetBase; import com.ibm.xsp.extlib.renderkit.html_extended.FacesRendererEx; import com.ibm.xsp.extlib.resources.ExtLibResources; import com.ibm.xsp.resource.DojoModuleResource; import com.ibm.xsp.resource.Resource; import com.ibm.xsp.util.JavaScriptUtil; public abstract class DojoWidgetBaseRenderer extends FacesRendererEx { @Override public void encodeBegin(FacesContext context, UIComponent component) throws IOException { if (!component.isRendered()) { return; } // Get the response renderer ResponseWriter writer = context.getResponseWriter(); // Do not render if it is not needed if (AjaxUtil.isAjaxNullResponseWriter(writer)) { return; } // And write the value if (component instanceof UIDojoWidgetBase) { writeTag(context, (UIDojoWidgetBase) component, writer); } } @Override public boolean getRendersChildren() { return false; } @Override public void encodeEnd(FacesContext context, UIComponent component) throws IOException { if (!component.isRendered()) { return; } // Get the response renderer ResponseWriter writer = context.getResponseWriter(); // Do not render if it is not needed if (AjaxUtil.isAjaxNullResponseWriter(writer)) { return; } // And write the value if (component instanceof UIDojoWidgetBase) { endTag(context, writer, (UIDojoWidgetBase) component); } } protected void writeTag(FacesContext context, UIComponent component, ResponseWriter writer) throws IOException { startTag(context, writer, component); // write out dojoType and dojoAttributes if they are present boolean forceId = false; if (component instanceof FacesDojoComponent) { // Should we force the Id all the time here??? String dojoType = writeDojoAttributes(context, (FacesDojoComponent) component); if (StringUtil.isNotEmpty(dojoType)) { forceId = true; } } // id writeId(writer, context, component, forceId); } protected void startTag(FacesContext context, ResponseWriter writer, UIComponent component) throws IOException { String tagName = getTagName(); writer.startElement(tagName, component); } protected void endTag(FacesContext context, ResponseWriter writer, UIComponent component) throws IOException { String tagName = getTagName(); writer.endElement(tagName); // writer.write('\n'); } protected void writeValueAttribute(FacesContext context, UIInput component, ResponseWriter writer, String currentValue) throws IOException { if (StringUtil.isNotEmpty(currentValue)) { writer.writeAttribute("value", currentValue, "value"); //$NON-NLS-1$ //$NON-NLS-2$ } } protected String writeDojoAttributes(FacesContext context, FacesDojoComponent dojoComponent) throws IOException { UIViewRootEx viewEx = (UIViewRootEx)context.getViewRoot(); String dojoType = dojoComponent.getDojoType(); if (StringUtil.isEmpty(dojoType)) { dojoType = getDefaultDojoType(context, dojoComponent); // If the resources for the dojo type haven't been emitted yet, then do it // Not that the XPages runtime ensures that the resources are not emitted multiple times // This is simply an optimization if(shouldWriteModule(context, viewEx, dojoComponent, dojoType)) { writeDefaultDojoModule(context, viewEx, dojoComponent, dojoType); } } else { if(shouldWriteModule(context, viewEx, dojoComponent, dojoType)) { writeDojoModule(context, viewEx, dojoComponent, dojoType); } } if (StringUtil.isNotEmpty(dojoType)) { Map<String, String> attrs = DojoRendererUtil.createMap(context); // Compose the list of attributes from the list of dojo attributes DojoRendererUtil.getDojoAttributeMap(dojoComponent, attrs); // Add the attributes specific to this control initDojoAttributes(context, dojoComponent, attrs); // And generate them DojoRendererUtil.writeDojoHtmlAttributes(context, (UIComponent) dojoComponent, dojoType, attrs); } return dojoType; } protected boolean shouldWriteModule(FacesContext context, UIViewRootEx viewEx, FacesDojoComponent dojoComponent, String dojoType) { if (StringUtil.isNotEmpty(dojoType)) { if(viewEx.getEncodeProperty(dojoType)==null) { viewEx.putEncodeProperty(dojoType, Boolean.TRUE); return true; } } return false; } protected void writeDojoModule(FacesContext context, UIViewRootEx viewEx, FacesDojoComponent dojoComponent, String dojoType) { } protected void writeDefaultDojoModule(FacesContext context, UIViewRootEx viewEx, FacesDojoComponent dojoComponent, String dojoType) { // Add the default modules DojoModuleResource module = getDefaultDojoModule(context, dojoComponent); if(module!=null) { ExtLibResources.addEncodeResource(viewEx, module); } if (module != null && module.getName().equals(ExtLibResources.dojoxGridDataGrid.getName())) { // 1.6.1 loads dojox.grid.DataGrid, which loads dojox.html.metrics, which adds one extra IFrame ExtLibResources.addEncodeResource(viewEx, ExtLibResources.dojoIFrameAdjuster); } // Add the extra resources Resource[] res = getExtraResources(context, dojoComponent); if(res!=null) { for(int i=0; i<res.length; i++) { ExtLibResources.addEncodeResource(viewEx, res[i]); } } } protected abstract String getTagName(); protected abstract String getDefaultDojoType(FacesContext context, FacesDojoComponent component); protected abstract DojoModuleResource getDefaultDojoModule(FacesContext context, FacesDojoComponent component); protected Resource[] getExtraResources(FacesContext context, FacesDojoComponent component) { // None by default... return null; } protected void initDojoAttributes(FacesContext context, FacesDojoComponent dojoComponent, Map<String,String> attrs) throws IOException { if (dojoComponent instanceof UIDojoWidgetBase) { UIDojoWidgetBase c = (UIDojoWidgetBase) dojoComponent; if( isHasTooltipProperty() ){ DojoRendererUtil.addDojoHtmlAttributes(attrs, "tooltip", c.getTooltip()); // $NON-NLS-1$ } DojoRendererUtil.addDojoHtmlAttributes(attrs, "dir", c.getDir()); // $NON-NLS-1$ DojoRendererUtil.addDojoHtmlAttributes(attrs, "lang", c.getLang()); // $NON-NLS-1$ DojoRendererUtil.addDojoHtmlAttributes(attrs, "style", c.getStyle()); // $NON-NLS-1$ DojoRendererUtil.addDojoHtmlAttributes(attrs, "class", c.getStyleClass()); // $NON-NLS-1$ DojoRendererUtil.addDojoHtmlAttributes(attrs, "title", c.getTitle()); // $NON-NLS-1$ } } protected boolean isHasTooltipProperty(){ // in 8.5.3UP1 mobile controls would have a tooltip property // since 9.0.0 new controls do not have that property // because you can't hover for tooltips on touch-screen devices. return true; } protected static void encodeDojoEvents(FacesContext context, UIDojoWidgetBase component, String eventName, String eventValue) throws IOException { if(eventValue != null) { StringBuilder buff = new StringBuilder(); String clientId = component.getClientId(context); // if event value set // state the function String clientSideScriptName = JavaScriptUtil.startMethodJS(context, component, "clientSide_" + eventName, buff); // $NON-NLS-1$ // add scripts to the function block buff.append( eventValue ); buff.append("\n"); // $NON-NLS-1$ JavaScriptUtil.endMethodJS(buff); boolean submit = false; // clientSide script only int validationMode = JavaScriptUtil.VALIDATION_FULL; // since not submit, not immediate // XSP.attachEvent JavaScriptUtil.appendAttachEvent(buff, clientId, clientId, eventName, clientSideScriptName, submit, validationMode); buff.append("\n"); // $NON-NLS-1$ if( buff.length() == 0 ){ // no events return; } // then add the script block we just generated. // when using dojo, can't just put onload code inline into the page, // as the dojo dom manipulation won't have happened by then. // Have to put it into an addOnLoad method. JavaScriptUtil.addScriptOnLoad(buff.toString()); } } }