/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.myfaces.renderkit.html.util;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.myfaces.shared_tomahawk.config.MyfacesConfig;
import org.apache.myfaces.shared_tomahawk.renderkit.html.HTML;
import org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlRendererUtils;
import org.apache.myfaces.shared_tomahawk.renderkit.html.util.JavascriptUtils;
/**
* This phase listener puts in the request the javascript code needed to render the dummyForm
* and the autoscroll feature.
*
* The ExtensionsFilter will put this code before the closing &tt;/body> tag.
*
* @author Bruno Aranda (latest modification by $Author: grantsmith $)
* @version $Revision: 472792 $ $Date: 2006-11-09 07:34:47 +0100 (Do, 09 Nov 2006) $
*/
public class ExtensionsPhaseListener implements PhaseListener {
private static final Log log = LogFactory.getLog(ExtensionsPhaseListener.class);
public static final String ORG_APACHE_MYFACES_MY_FACES_JAVASCRIPT = "org.apache.myfaces.myFacesJavascript";
public static final String LISTENERS_MAP = "_MyFaces_inputAjax_listenersMap";
public PhaseId getPhaseId()
{
return PhaseId.RENDER_RESPONSE;
}
public void beforePhase(PhaseEvent event)
{
}
public void afterPhase(PhaseEvent event)
{
FacesContext facesContext = event.getFacesContext();
try
{
getJavaScriptCodeAndStoreInRequest(facesContext);
} catch (IOException e)
{
log.error("Exception while rendering extension filter code.",e);
}
}
/**
* Creates javascript-code such as the dummy form and the autoscroll javascript, which goes before the closing </body>
*
* The extension filter will then finally process it and render it into the page.
*
* @throws IOException an exception if writer cannot be written to
* @param facesContext The current faces-context
*/
private void getJavaScriptCodeAndStoreInRequest(FacesContext facesContext) throws IOException
{
Object myFacesJavascript = facesContext.getExternalContext().getRequestMap().get(ORG_APACHE_MYFACES_MY_FACES_JAVASCRIPT);
if (myFacesJavascript != null)
{
return;
}
facesContext.getExternalContext().getRequestMap().put(ORG_APACHE_MYFACES_MY_FACES_JAVASCRIPT, getCodeBeforeBodyEnd(facesContext));
}
private static String getCodeBeforeBodyEnd(FacesContext facesContext) throws IOException
{
ResponseWriter responseWriter = facesContext.getResponseWriter();
HtmlBufferResponseWriterWrapper writerWrapper = HtmlBufferResponseWriterWrapper
.getInstance(responseWriter);
facesContext.setResponseWriter(writerWrapper);
writeCodeBeforeBodyEnd(facesContext);
//todo: this is just a quick-fix - Sun RI screams if the old responsewriter is null
//but how to reset the old response-writer then?
if(responseWriter!=null)
facesContext.setResponseWriter(responseWriter);
return "<!-- MYFACES JAVASCRIPT -->\n"+writerWrapper.toString()+"\n";
}
/**In case of StreamingAddResource and a documentBody-Tag, this method will be called with the
* normal response writer set.
*
* It will directly render out the javascript-text at the current position (immediately before body-closing).
*
* In the case of DefaultAddResource, this method will be called with a wrapped response writer - and we'll
* buffer the javascript-text in the request, for the ExtensionFilter to catch and render it.
*
* @param facesContext The current faces-context.
* @throws IOException Exception if writing to the output-stream fails.
*/
public static void writeCodeBeforeBodyEnd(FacesContext facesContext) throws IOException
{
ResponseWriter writer = facesContext.getResponseWriter();
MyfacesConfig myfacesConfig = MyfacesConfig.getCurrentInstance(facesContext.getExternalContext());
if (myfacesConfig.isDetectJavascript())
{
if (! JavascriptUtils.isJavascriptDetected(facesContext.getExternalContext()))
{
writer.startElement("script",null);
writer.writeAttribute("attr", HTML.SCRIPT_TYPE_TEXT_JAVASCRIPT,null);
StringBuffer script = new StringBuffer();
script.append("document.location.replace('").
append(facesContext.getApplication().getViewHandler().getResourceURL(facesContext, "/_javascriptDetector_")).append("?goto=").append(facesContext.getApplication().getViewHandler().getActionURL(facesContext, facesContext.getViewRoot().getViewId())).append("');");
writer.writeText(script.toString(),null);
writer.endElement(HTML.SCRIPT_ELEM);
}
}
if (myfacesConfig.isAutoScroll())
{
HtmlRendererUtils.renderAutoScrollFunction(facesContext, writer);
}
// now write out listeners
// todo: change the get entry below to use the static field in Listener if/when the listeners move to Tomahawk from sandbox
try
{
List listeners = (List) facesContext.getExternalContext().getRequestMap().get("org.apache.myfaces.Listener");
//System.out.println("listeners: " + listeners);
if(listeners != null && listeners.size() > 0){
writer.startElement(HTML.SCRIPT_ELEM,null);
writer.writeAttribute("attr", HTML.SCRIPT_TYPE_TEXT_JAVASCRIPT,null);
StringBuffer buff = new StringBuffer();
String mapName = LISTENERS_MAP;
buff.append("var ").append(mapName).append(" = new Object();\n");
for (int i = 0; i < listeners.size(); i++)
{
Map listenerItem = (Map) listeners.get(i);
String listenerId = (String) listenerItem.get("listenerId");
String listenOn = (String) listenerItem.get("listenOn");
String action = (String) listenerItem.get("action");
String eventType = (String) listenerItem.get("eventType");
// todo: Should use Listener object for more flexibility, but only when it moves to tomahawk
buff.append("var _MyFaces_listenerItem = ").append(mapName).append("['").append(listenOn).append("'];\n");
buff.append("if(!_MyFaces_listenerItem) {\n");
buff.append(" _MyFaces_listenerItem = new Array();\n");
buff.append(" ").append(mapName).append("['").append(listenOn).append("'] = _MyFaces_listenerItem;\n");
buff.append("}\n");
buff.append("var _MyFaces_listener = new Object();\n");
buff.append("_MyFaces_listener['id'] = '").append(listenerId).append("';\n");
buff.append("_MyFaces_listener['action'] = '").append(action).append("';\n");
buff.append("_MyFaces_listener['eventType'] = '").append(eventType).append("';\n");
buff.append("_MyFaces_listenerItem[_MyFaces_listenerItem.length] = _MyFaces_listener;\n");
}
writer.write(buff.toString());
writer.endElement(HTML.SCRIPT_ELEM);
}
}
catch (Exception e)
{
log.error("Exception while rendering code for listeners.",e);
}
}
}