All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.jsftoolkit.base.HtmlScripts Maven / Gradle / Ivy

Go to download

The core classes for the JSF Toolkit Component Framework. Includes all framework base and utility classes as well as component kick-start/code-generation and registration tools. Also includes some classes for testing that are reused in other projects. They cannot be factored out into a separate project because they are referenced by the tests and they reference this code (circular dependence).

The newest version!
package com.jsftoolkit.base;

import java.io.IOException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import javax.faces.component.UIComponent;
import javax.faces.component.UIComponentBase;
import javax.faces.component.UIData;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.Renderer;

import com.jsftoolkit.base.renderer.ResourceUtils;
import com.jsftoolkit.utils.IOExceptionWrapper;
import com.jsftoolkit.utils.Utils;

/**
 * Depth first searches the component tree for components or components with
 * renderers that implement {@link HeadInsert}. The classpath resources are
 * then included via shale remoting.
 * 
 * TODO See about refactoring to a 1 script element 1 style element model. Allow
 * named template areas that other templates can include themselves in.
 * 
 * @author noah
 * 
 */
public class HtmlScripts extends UIComponentBase implements HeadInsert {

	private static final String DELIMETER = ";";

	private transient Set resourceIds = new HashSet();

	@Override
	public void decode(FacesContext context) {
		// process the renderer's decode method (if there is one)
		super.decode(context);

		resourceIds = Utils
				.asSet(Utils.split(context.getExternalContext()
						.getRequestParameterMap().get(getClientId(context)),
						DELIMETER));
	}

	/**
	 * Calls {@link #processChildren(UIComponent, FacesContext)} on the
	 * {@link UIViewRoot}.
	 */
	@Override
	public void encodeChildren(FacesContext context) throws IOException {
		Utils.notNull(context, "context");
		if (!isRendered()) {
			return;
		}
		processChildren(context.getViewRoot(), context, new HashSet(),
				resourceIds);
	}

	@Override
	public void encodeEnd(FacesContext context) throws IOException {
		super.encodeEnd(context);

		// write out our id and the already rendered resources
		ResponseWriter writer = context.getResponseWriter();
		writer.startElement("script", this);
		writer.writeAttribute("type", "text/javascript", null);
		writer.writeAttribute("id", getClientId(context), "id");
		writer.writeText("JsfTk.HtmlScriptsId = '", null);
		writer.writeText(getClientId(context), "id");
		writer.writeText("';\nJsfTk.HtmlScriptsResourceIds = '", null);
		writer.writeText(Utils.join(resourceIds.iterator(), DELIMETER), null);
		writer.writeText("';", null);
		writer.endElement("script");
	}

	/**
	 * Recursively process the children of the given component, linking
	 * resources for those rendered components that implement {@link HeadInsert}.
	 * Note that component is not processed in this invocation.
	 * 
	 * @param component
	 * @param context
	 * @param rendered
	 *            the ids of components that have already rendered (important
	 *            for components inside of UIData that may not necessarily be
	 *            rendered for every row, e.g. header and footer facets)
	 * @param resourceIds
	 * @throws IOException
	 */
	public static void processChildren(UIComponent component,
			FacesContext context, final Set rendered,
			final Set resourceIds) throws IOException {
		JsfIterator data = null;
		// determine if it's UIData or a JsfIterator
		if (component instanceof UIData) {
			data = new UIDataProcessor.UIDataWrapper((UIData) component);
		} else if (component instanceof JsfIterator) {
			data = (JsfIterator) component;
		}
		if (data == null) {
			// for non-iterators, process normally
			Iterator it = component.getFacetsAndChildren();
			while (it.hasNext()) {
				processChild(context, it.next(), rendered, resourceIds);
			}
		} else {
			// need to run iteration
			try {
				UIDataProcessor.iterate(context, data, new UIDataProcessor() {
					@Override
					public void processChild(FacesContext context,
							UIComponent child) {
						process(context, child);
					}

					@Override
					public void processFacet(FacesContext context,
							UIComponent facet, String name) {
						process(context, facet);
					}

					private void process(FacesContext context, UIComponent child) {
						try {
							HtmlScripts.processChild(context, child, rendered,
									resourceIds);
						} catch (IOException e) {
							throw new IOExceptionWrapper(e);
						}
					}
				});
			} catch (IOExceptionWrapper e) {
				throw e.getWrapped();
			}
		}
	}

	protected static void processChild(FacesContext context, UIComponent child,
			Set rendered, Set resourceIds) throws IOException {
		if (!child.isRendered() || !rendered.add(child.getClientId(context))) {
			// skip components that are not rendered (which means their children
			// cannot be rendered either) or that have already been rendered
			// (which means their children have as well)
			return;
		}

		// resolve the component's renderer, if it has one
		Renderer renderer = getRenderer(child, context);

		// determine if the component or it's renderer implements HeadInsert
		HeadInsert c = null;
		if (renderer == null) {
			// component renders itself
			if (child instanceof HeadInsert) {
				c = (HeadInsert) child;
			}
		} else {
			if (renderer instanceof HeadInsert) {
				c = (HeadInsert) renderer;
			}
		}

		if (c != null) {
			// let it write into head
			c.encodeHead(context, child, resourceIds);
		}

		// process the child's children
		processChildren(child, context, rendered, resourceIds);
	}

	/**
	 * 
	 * @param c
	 * @param context
	 * @return the renderer for the given component.
	 */
	protected static Renderer getRenderer(UIComponent c, FacesContext context) {
		String family = c.getFamily();
		String rendererType = c.getRendererType();
		if (family != null && rendererType != null) {
			return context.getRenderKit().getRenderer(family, rendererType);
		}
		return null;
	}

	/**
	 * No family, this component is self-rendering.
	 */
	@Override
	public String getFamily() {
		return null;
	}

	/**
	 * No renderer type, this component is self-rendering.
	 */
	@Override
	public String getRendererType() {
		return null;
	}

	@Override
	public boolean getRendersChildren() {
		return true;
	}

	public void encodeHead(FacesContext context, UIComponent component,
			Set resourceIds) throws IOException {
		ResourceUtils.writeIncludes(context, component, Utils
				.asSet(ResourceConstants.JSFTK_JS), resourceIds);
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy