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

net.wicp.tams.component.services.impl.JqDocLinkerImpl Maven / Gradle / Ivy

There is a newer version: 2.0.0
Show newest version
package net.wicp.tams.component.services.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import org.apache.tapestry5.commons.util.CollectionFactory;
import org.apache.tapestry5.dom.Document;
import org.apache.tapestry5.dom.Element;
import org.apache.tapestry5.internal.services.DocumentLinker;
import org.apache.tapestry5.internal.services.ModuleInitsManager;
import org.apache.tapestry5.json.JSONArray;
import org.apache.tapestry5.services.javascript.InitializationPriority;
import org.apache.tapestry5.services.javascript.ModuleConfigurationCallback;
import org.apache.tapestry5.services.javascript.ModuleManager;
import org.apache.tapestry5.services.javascript.StylesheetLink;

import net.wicp.tams.component.services.ISupportedLocales;

public class JqDocLinkerImpl implements DocumentLinker {
	private final List coreLibraryURLs = CollectionFactory.newList();

	private final List libraryURLs = CollectionFactory.newList();

	private final Set htmlLibraryURLs = CollectionFactory.newSet();

	private final ModuleInitsManager initsManager = new ModuleInitsManager();

	private final List moduleConfigurationCallbacks = CollectionFactory.newList();

	private final List includedStylesheets = CollectionFactory.newList();

	private final ModuleManager moduleManager;

	private final boolean omitGeneratorMetaTag;

	private final String contextPath;

	private final String rjzjhjsclientpath;

	private final ISupportedLocales supportedLocales;

	private final String tapestryBanner;

	// Initially false; set to true when a scriptURL or any kind of
	// initialization is added.
	private boolean hasScriptsOrInitializations;

	/**
	 * @param moduleManager
	 *            used to identify the root folder for dynamically loaded
	 *            modules
	 * @param omitGeneratorMetaTag
	 *            via symbol configuration
	 * @param tapestryVersion
	 *            version of Tapestry framework (for meta tag)
	 */
	public JqDocLinkerImpl(ModuleManager moduleManager, boolean omitGeneratorMetaTag, String tapestryVersion,
			String contextPath, String rjzjhjsclientpath, ISupportedLocales supportedLocales) {
		this.moduleManager = moduleManager;
		this.omitGeneratorMetaTag = omitGeneratorMetaTag;
		this.contextPath = contextPath;
		this.rjzjhjsclientpath = rjzjhjsclientpath;
		this.supportedLocales = supportedLocales;

		tapestryBanner = String.format("Apache Tapestry Framework (version %s)", tapestryVersion);
	}

	public void addStylesheetLink(StylesheetLink sheet) {
		includedStylesheets.add(sheet);
	}

	public void addCoreLibrary(String libraryURL) {
		coreLibraryURLs.add(libraryURL);

		hasScriptsOrInitializations = true;
	}

	public void addHtmlLibrary(String libraryURL) {
		htmlLibraryURLs.add(libraryURL);
		hasScriptsOrInitializations = true;
	}

	public void addLibrary(String libraryURL) {
		libraryURLs.add(libraryURL);
		hasScriptsOrInitializations = true;
	}

	public void addScript(InitializationPriority priority, String script) {
		addInitialization(priority, "t5/core/pageinit", "evalJavaScript", new JSONArray().put(script));
	}

	public void addInitialization(InitializationPriority priority, String moduleName, String functionName,
			JSONArray arguments) {
		initsManager.addInitialization(priority, moduleName, functionName, arguments);

		hasScriptsOrInitializations = true;
	}

	/**
	 * Updates the supplied Document, possibly adding <head> or
	 * <body> elements.
	 * 
	 * @param document
	 *            to be updated
	 */
	public void updateDocument(Document document) {
		Element root = document.getRootElement();

		// If the document failed to render at all, that's a different problem
		// and is reported elsewhere.

		if (root == null) {
			return;
		}

		addStylesheetsToHead(root, includedStylesheets);

		// only add the generator meta only to html documents

		boolean isHtmlRoot = root.getName().equals("html");

		if (!omitGeneratorMetaTag && isHtmlRoot) {
			Element head = findOrCreateElement(root, "head", true);

			Element existingMeta = head.find("meta");

			addElementBefore(head, existingMeta, "meta", "name", "generator", "content", tapestryBanner);
		}

		addScriptElements(root);
	}

	private static Element addElementBefore(Element container, Element insertionPoint, String name,
			String... namesAndValues) {
		if (insertionPoint == null) {
			return container.element(name, namesAndValues);
		}

		return insertionPoint.elementBefore(name, namesAndValues);
	}

	private void addScriptElements(Element root) {
		String rootElementName = root.getName();

		Element body = rootElementName.equals("html") ? findOrCreateElement(root, "body", false) : null;

		// Write the data-page-initialized attribute in for all pages; it will
		// be "true" when the page has no
		// initializations (which is somewhat rare in Tapestry). When the page
		// has initializations, it will be set to
		// "true" once those initializations all run.
		if (body != null) {
			body.attribute("data-page-initialized", Boolean.toString(!hasScriptsOrInitializations));
		}

		if (!hasScriptsOrInitializations) {
			return;
		}

		// This only applies when the document is an HTML document. This may
		// need to change in the
		// future, perhaps configurable, to allow for html and xhtml and perhaps
		// others. Does SVG
		// use stylesheets?

		if (!rootElementName.equals("html")) {
			throw new RuntimeException(String.format(
					"The root element of the rendered document was <%s>, not . A root element of  is needed when linking JavaScript and stylesheet resources.",
					rootElementName));
		}

		// TAPESTRY-2364
		// 加上核心的js文件
		Element head = findOrCreateElement(root, "head", true);

		// head.text("最高组").moveToTop(head);

		// Element sysHead = head.elementBefore("head");
		addScriptsToEndOfHead(head);
	}

	/**
	 * Finds an element by name, or creates it. Returns the element (if found),
	 * or creates a new element with the given name, and returns it. The new
	 * element will be positioned at the top or bottom of the root element.
	 * 
	 * @param root
	 *            element to search
	 * @param childElement
	 *            element name of child
	 * @param atTop
	 *            if not found, create new element at top of root, or at bottom
	 * @return the located element, or null
	 */
	private Element findOrCreateElement(Element root, String childElement, boolean atTop) {
		Element container = root.find(childElement);

		// Create the element is it is missing.

		if (container == null) {
			container = atTop ? root.elementAt(0, childElement) : root.element(childElement);
		}

		return container;
	}

	/**
	 * Adds {@code