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

de.larmic.butterfaces.component.renderkit.html_basic.text.TreeRenderer Maven / Gradle / Ivy

The newest version!
package de.larmic.butterfaces.component.renderkit.html_basic.text;

import de.larmic.butterfaces.component.base.renderer.HtmlBasicRenderer;
import de.larmic.butterfaces.component.behavior.JsfAjaxRequest;
import de.larmic.butterfaces.component.html.tree.HtmlTree;
import de.larmic.butterfaces.component.partrenderer.RenderUtils;
import de.larmic.butterfaces.component.renderkit.html_basic.text.model.CachedNodesInitializer;
import de.larmic.butterfaces.component.renderkit.html_basic.text.part.TrivialComponentsEntriesNodePartRenderer;
import de.larmic.butterfaces.context.StringHtmlEncoder;
import de.larmic.butterfaces.event.TreeNodeExpansionListener;
import de.larmic.butterfaces.event.TreeNodeSelectionEvent;
import de.larmic.butterfaces.event.TreeNodeSelectionListener;
import de.larmic.butterfaces.model.tree.Node;
import de.larmic.butterfaces.resolver.ClientBehaviorResolver;
import de.larmic.butterfaces.resolver.MustacheResolver;
import de.larmic.butterfaces.resolver.WebXmlParameters;
import de.larmic.butterfaces.util.StringUtils;

import javax.faces.component.UIComponent;
import javax.faces.component.behavior.AjaxBehavior;
import javax.faces.component.behavior.ClientBehavior;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.FacesRenderer;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;

@FacesRenderer(componentFamily = HtmlTree.COMPONENT_FAMILY, rendererType = HtmlTree.RENDERER_TYPE)
public class TreeRenderer extends HtmlBasicRenderer {

    public static final String DEFAULT_NODES_TEMPLATE = "
{{title}}
{{description}}
"; @Override public void encodeBegin(final FacesContext context, final UIComponent component) throws IOException { if (!component.isRendered()) { return; } final HtmlTree tree = (HtmlTree) component; final ResponseWriter writer = context.getResponseWriter(); writer.startElement(ELEMENT_DIV, tree); this.writeIdAttribute(context, writer, component); final String styleClass = tree.getStyleClass(); writer.writeAttribute(ATTRIBUTE_CLASS, StringUtils.isNotEmpty(styleClass) ? "butter-component-tree " + styleClass : "butter-component-tree", "class"); final String style = tree.getStyle(); if (StringUtils.isNotEmpty(style)) { writer.writeAttribute("style", style, "style"); } writer.startElement("input", tree); if (StringUtils.isNotEmpty(tree.getPlaceholder())) { writer.writeAttribute(ATTRIBUTE_PLACEHOLDER, tree.getPlaceholder(), null); } writer.writeAttribute(ATTRIBUTE_CLASS, "butter-component-tree-original-input", null); writer.endElement("input"); } @Override public void encodeEnd(final FacesContext context, final UIComponent component) throws IOException { if (!component.isRendered()) { return; } final HtmlTree tree = (HtmlTree) component; // HINT: getValue() should only called once because getValue() could create a new root node each time final Node rootNode = tree.getValue(); final List nodes = createNodesMap(tree, rootNode); final Map nodesMap = CachedNodesInitializer.createNodesMap(nodes); final ResponseWriter writer = context.getResponseWriter(); final List mustacheKeys = this.createMustacheKeys(context, tree); final String uniqueComponentId = tree.getClientId().replace(":", "_"); final String jQueryBySelector = RenderUtils.createJQueryBySelector(component.getClientId(), "input"); final Integer selectedNodeNumber = getSelectedNodeNumber(tree, nodesMap); if (selectedNodeNumber != null) { openPathToNode(nodesMap.get(selectedNodeNumber), tree.getNodeExpansionListener(), nodesMap); } writer.startElement("script", component); writer.writeText("jQuery(function () {\n", null); writer.writeText("var entries_" + uniqueComponentId + " = " + new TrivialComponentsEntriesNodePartRenderer().renderEntriesAsJSON(nodes, mustacheKeys, nodesMap) + ";\n", null); writer.writeText("var trivialTagsOptions" + uniqueComponentId + " = " + createTreeOptions(tree, context, selectedNodeNumber) + ";\n", null); writer.writeText("var trivialTree" + uniqueComponentId + " = ButterFaces.createTrivialTreeComponent(" + jQueryBySelector + ",trivialTagsOptions" + uniqueComponentId + ");\n", null); this.encodeAjaxEvent(tree, writer, "trivialTree" + uniqueComponentId, "click", "onSelectedEntryChanged"); this.encodeAjaxEvent(tree, writer, "trivialTree" + uniqueComponentId, "toggle", "onNodeExpansionStateChanged"); writer.writeText("});", null); writer.endElement("script"); writer.endElement(ELEMENT_DIV); } private String createTreeOptions(final HtmlTree tree, final FacesContext context, final Integer selectedNodeNumber) throws IOException { final StringBuilder options = new StringBuilder(); final String searchBarMode = determineSearchBarMode(tree); final WebXmlParameters webXmlParameters = new WebXmlParameters(context.getExternalContext()); final String noMatchingText = StringUtils.getNotNullValue(tree.getNoEntriesText(), webXmlParameters.getNoEntriesText()); final String spinnerText = StringUtils.getNotNullValue(tree.getSpinnerText(), webXmlParameters.getSpinnerText()); options.append("{"); options.append("\n searchBarMode: '" + searchBarMode + "',"); if (selectedNodeNumber != null) { options.append("\n selectedEntryId: '" + selectedNodeNumber + "',"); } if (tree.getToManyVisibleItemsRenderDelay() != null || tree.getToManyVisibleItemsThreshold() != null) { options.append("\n performanceOptimizationSettings: {"); if (tree.getToManyVisibleItemsRenderDelay() != null) { options.append("\n toManyVisibleItemsRenderDelay: " + tree.getToManyVisibleItemsRenderDelay() + ","); } if (tree.getToManyVisibleItemsThreshold() != null) { options.append("\n toManyVisibleItemsThreshold: " + tree.getToManyVisibleItemsThreshold() + ","); } options.append("\n },"); } if (tree.getFacet("template") != null) { final String encodedTemplate = StringHtmlEncoder.encodeComponentWithSurroundingDiv(context, tree.getFacet("template")); options.append("\n templates: ['" + encodedTemplate + "'],"); } else { options.append("\n templates: ['" + DEFAULT_NODES_TEMPLATE + "'],"); } options.append("\n spinnerTemplate: '
" + spinnerText + "
',"); options.append("\n noEntriesTemplate: '
" + noMatchingText + "
',"); options.append("\n entries: entries_" + tree.getClientId().replace(":", "_")); options.append("\n}"); return options.toString(); } private List createNodesMap(HtmlTree tree, Node rootNode) { return tree.isHideRootNode() ? rootNode.getSubNodes() : Arrays.asList(rootNode); } private List createMustacheKeys(FacesContext context, HtmlTree tree) throws IOException { if (tree.getFacet("template") != null) { final String encodedTemplate = StringHtmlEncoder.encodeComponentWithSurroundingDiv(context, tree.getFacet("template")); return MustacheResolver.getMustacheKeysForTreeNode(encodedTemplate); } return Collections.emptyList(); } private void encodeAjaxEvent(final HtmlTree tree, final ResponseWriter writer, final String variableName, final String eventName, final String trivialCallback) throws IOException { final AjaxBehavior ajaxBehavior = ClientBehaviorResolver.findFirstActiveAjaxBehavior(tree, eventName); if (ajaxBehavior != null) { writer.writeText(variableName + "." + trivialCallback + ".addListener(function(node) {", null); final String ajaxRequest = new JsfAjaxRequest(tree.getClientId(), true) .setEvent(eventName) .setRender(tree, eventName) .setParams("node.id") .addOnEventHandler(ajaxBehavior.getOnevent()) .addOnErrorHandler(ajaxBehavior.getOnerror()) .setBehaviorEvent(eventName).toString(); writer.writeText(ajaxRequest, null); writer.writeText("});", null); } } @Override public void decode(final FacesContext context, final UIComponent component) { final HtmlTree tree = (HtmlTree) component; final TreeNodeSelectionListener nodeSelectionListener = tree.getNodeSelectionListener(); final TreeNodeExpansionListener nodeExpansionListener = tree.getNodeExpansionListener(); final Map> behaviors = tree.getClientBehaviors(); if (behaviors.isEmpty()) { return; } final Node rootNode = tree.getValue(); final List nodes = createNodesMap(tree, rootNode); final Map nodesMap = CachedNodesInitializer.createNodesMap(nodes); final ExternalContext external = context.getExternalContext(); final Map params = external.getRequestParameterMap(); final String behaviorEvent = params.get("javax.faces.behavior.event"); if (behaviorEvent != null && "click".equals(behaviorEvent)) { try { final Integer nodeNumber = Integer.valueOf(params.get("params")); final Node node = nodesMap.get(nodeNumber); if (nodeSelectionListener != null) { final Integer selectedNodeNumber = getSelectedNodeNumber(tree, nodesMap); final Node selectedNode = selectedNodeNumber != null ? nodesMap.get(selectedNodeNumber) : null; nodeSelectionListener.processValueChange(new TreeNodeSelectionEvent(selectedNode, node)); } } catch (NumberFormatException e) { // here is nothing to do } } else if (behaviorEvent != null && "toggle".equals(behaviorEvent)) { try { final Integer nodeNumber = Integer.valueOf(params.get("params")); final Node cachedNode = nodesMap.get(nodeNumber); if (cachedNode != null) { if (cachedNode.isCollapsed()) { cachedNode.setCollapsed(false); if (nodeExpansionListener != null) { nodeExpansionListener.expandNode(cachedNode); } } else { cachedNode.setCollapsed(true); if (nodeExpansionListener != null) { nodeExpansionListener.collapseNode(cachedNode); } } } } catch (NumberFormatException e) { // here is nothing to do } } } private void openPathToNode(final Node node, final TreeNodeExpansionListener nodeExpansionListener, final Map nodesMap) { final Node parent = getParent(node, nodesMap); if (parent != null) { if (parent.isCollapsed()) { parent.setCollapsed(false); if (nodeExpansionListener != null) { nodeExpansionListener.expandNode(node); } } openPathToNode(parent, nodeExpansionListener, nodesMap); } } private Node getParent(final Node child, final Map nodesMap) { for (Node node : nodesMap.values()) { if (node.getSubNodes().contains(child)) { return node; } } return null; } private String determineSearchBarMode(final HtmlTree tree) { if ("show-if-filled".equals(tree.getSearchBarMode())) { return "show-if-filled"; } if ("always-visible".equals(tree.getSearchBarMode())) { return "always-visible"; } return "none"; } private Integer getSelectedNodeNumber(final HtmlTree tree, final Map nodesMap) { if (tree.getNodeSelectionListener() != null) { for (Integer nodeNumber : nodesMap.keySet()) { final Node node = nodesMap.get(nodeNumber); if (tree.getNodeSelectionListener().isValueSelected(node)) { return nodeNumber; } } } return null; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy