<commit_before>/**
 *  Copyright 2014-2017 <NAME>
 *
 *  This file is part of BootsFaces.
 *
* 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 net.bootsfaces.component.tree;

import java.io.IOException;

import javax.faces.FacesException;
import javax.faces.component.UIComponent;
import javax.faces.component.UIForm;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.FacesRenderer;

import net.bootsfaces.C;
import net.bootsfaces.component.tree.event.TreeNodeCheckedEvent;
import net.bootsfaces.component.tree.event.TreeNodeEventListener;
import net.bootsfaces.component.tree.event.TreeNodeExpandedEvent;
import net.bootsfaces.component.tree.event.TreeNodeSelectionEvent;
import net.bootsfaces.component.tree.model.Node;
import net.bootsfaces.component.tree.model.TreeModelUtils;
import net.bootsfaces.expressions.ExpressionResolver;
import net.bootsfaces.render.CoreRenderer;
import net.bootsfaces.render.H;
import net.bootsfaces.render.Responsive;
import net.bootsfaces.utils.BsfUtils;

/** This class provide the rendering logic of the &lt;b:tree /&gt;. */
@FacesRenderer(componentFamily = C.BSFCOMPONENT, rendererType = "net.bootsfaces.component.tree.Tree")
public class TreeRenderer extends CoreRenderer {

	/**
	 * Decode ajax behaviours specific to the components
	 */
	@Override
	public void decode(FacesContext context, UIComponent component) {
		Tree tree = (Tree) component;
		super.decode(context, tree);

		final TreeNodeEventListener nodeSelectionListener = tree.getNodeSelectionListener();
		String params = context.getExternalContext().getRequestParameterMap().get("params");

		if (params != null) {
			params = params.replace("BsFEvent=", "");
			String[] pair = params.split(":", 2);
			String key = pair[0];
			String value = null;
			if (pair.length == 2) {
				value = pair[1];
			}
			if (value != null && !"".equals(value.trim())) {
				// Node n = TreeModelUtils.mapDataToModel(value);
				Node n = (Node) BsfUtils.fromString(value);
				TreeModelUtils.updateNodeById(tree.getValue(), n.getNodeId(), n);
				// tree.setSubmittedValue(tree.getValue());

				if (nodeSelectionListener != null) {
					// execute listener only for listened events
					if ("nodeSelected".equals(key)) {
						nodeSelectionListener.processValueSelected(new TreeNodeSelectionEvent(n, true));
					} else if ("nodeUnselected".equals(key)) {
                                                nodeSelectionListener.processValueSelected(new TreeNodeSelectionEvent(n, false));
                                        }else if ("nodeChecked".equals(key)) {
						nodeSelectionListener.processValueChecked(new TreeNodeCheckedEvent(n, true));
					} else if ("nodeUnchecked".equals(key)) {
						nodeSelectionListener.processValueChecked(new TreeNodeCheckedEvent(n, false));
                                        } else if ("nodeExpanded".equals(key)) {
						nodeSelectionListener.processValueExpanded(new TreeNodeExpandedEvent(n, true));
					} else if ("nodeCollapsed".equals(key)) {
						nodeSelectionListener.processValueExpanded(new TreeNodeExpandedEvent(n, false));
					}
				}
			}
		}
	}

	@Override
	public void encodeBegin(FacesContext context, UIComponent component) throws IOException {
		if (!component.isRendered()) {
			return;
		}

		Tree tree = (Tree) component;
		ResponseWriter rw = context.getResponseWriter();
		String clientId = tree.getClientId();

		// check is inside form (MyFaces requires to be)
		final UIForm form = BsfUtils.getClosestForm(tree);
		if(form == null) {
			throw new FacesException("The tree component must be inside a form", null);
		}

		rw.startElement("div", tree);
		rw.writeAttribute("id", "tree_" + clientId, "id");
		renderPassThruAttributes(context, component, H.HTML5_DATA_ATTRIBUTES, true);
		String clazz = Responsive.getResponsiveStyleClass(tree, false);
		String styleClass = tree.getStyleClass();
		if (null != styleClass) {
			clazz = styleClass + clazz;
		}
		clazz=clazz.trim();
		if (clazz.length()>0) {
			rw.writeAttribute("class", clazz, "class");
		}
		writeAttribute(rw, "style", tree.getStyle());
		rw.endElement("div");
	}

	@Override
	public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
		if (!component.isRendered()) {
			return;
		}
		Tree tree = (Tree) component;
		String clientId = tree.getClientId();
		String jqClientId = BsfUtils.escapeJQuerySpecialCharsInSelector(clientId);
		ResponseWriter rw = context.getResponseWriter();

		final UIForm form = BsfUtils.getClosestForm(tree);
		if(form == null) {
			throw new FacesException("The tree component must be inside a form", null);
		}
		// String updateItems = BsfUtils.GetOrDefault("'" + tree.getUpdate() + "'", "null");
		String updateItems = tree.getUpdate();
		if(updateItems != null)
			updateItems = ExpressionResolver.getComponentIDs(context, component, updateItems);

		rw.startElement("script", tree);
		//# Start enclosure
		rw.writeText("$(document).ready(function() {", null);
		// build tree management javascript
		rw.writeText("function getTreeData() { " +
					 "   return '" + TreeModelUtils.renderModelAsJson(tree.getValue(), tree.isRenderRoot())  + "'; " +
					 "} " +

					 // build tree structure
					 "$('#tree_" + jqClientId + "').treeview({ " +
					 	(tree.isShowTags()  ? "showTags: true," : "") +<commit_msg>#676 throw a useful exception if the value attribute is missing<commit_after>/**
 *  Copyright 2014-2017 <NAME>
 *
 *  This file is part of BootsFaces.
 *
* 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 net.bootsfaces.component.tree;

import java.io.IOException;

import javax.faces.FacesException;
import javax.faces.component.UIComponent;
import javax.faces.component.UIForm;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.FacesRenderer;

import net.bootsfaces.C;
import net.bootsfaces.component.tree.event.TreeNodeCheckedEvent;
import net.bootsfaces.component.tree.event.TreeNodeEventListener;
import net.bootsfaces.component.tree.event.TreeNodeExpandedEvent;
import net.bootsfaces.component.tree.event.TreeNodeSelectionEvent;
import net.bootsfaces.component.tree.model.Node;
import net.bootsfaces.component.tree.model.TreeModelUtils;
import net.bootsfaces.expressions.ExpressionResolver;
import net.bootsfaces.render.CoreRenderer;
import net.bootsfaces.render.H;
import net.bootsfaces.render.Responsive;
import net.bootsfaces.utils.BsfUtils;

/** This class provide the rendering logic of the &lt;b:tree /&gt;. */
@FacesRenderer(componentFamily = C.BSFCOMPONENT, rendererType = "net.bootsfaces.component.tree.Tree")
public class TreeRenderer extends CoreRenderer {

	/**
	 * Decode ajax behaviours specific to the components
	 */
	@Override
	public void decode(FacesContext context, UIComponent component) {
		Tree tree = (Tree) component;
		super.decode(context, tree);

		final TreeNodeEventListener nodeSelectionListener = tree.getNodeSelectionListener();
		String params = context.getExternalContext().getRequestParameterMap().get("params");

		if (params != null) {
			params = params.replace("BsFEvent=", "");
			String[] pair = params.split(":", 2);
			String key = pair[0];
			String value = null;
			if (pair.length == 2) {
				value = pair[1];
			}
			if (value != null && !"".equals(value.trim())) {
				// Node n = TreeModelUtils.mapDataToModel(value);
				Node n = (Node) BsfUtils.fromString(value);
				TreeModelUtils.updateNodeById(tree.getValue(), n.getNodeId(), n);
				// tree.setSubmittedValue(tree.getValue());

				if (nodeSelectionListener != null) {
					// execute listener only for listened events
					if ("nodeSelected".equals(key)) {
						nodeSelectionListener.processValueSelected(new TreeNodeSelectionEvent(n, true));
					} else if ("nodeUnselected".equals(key)) {
                                                nodeSelectionListener.processValueSelected(new TreeNodeSelectionEvent(n, false));
                                        }else if ("nodeChecked".equals(key)) {
						nodeSelectionListener.processValueChecked(new TreeNodeCheckedEvent(n, true));
					} else if ("nodeUnchecked".equals(key)) {
						nodeSelectionListener.processValueChecked(new TreeNodeCheckedEvent(n, false));
                                        } else if ("nodeExpanded".equals(key)) {
						nodeSelectionListener.processValueExpanded(new TreeNodeExpandedEvent(n, true));
					} else if ("nodeCollapsed".equals(key)) {
						nodeSelectionListener.processValueExpanded(new TreeNodeExpandedEvent(n, false));
					}
				}
			}
		}
	}

	@Override
	public void encodeBegin(FacesContext context, UIComponent component) throws IOException {
		if (!component.isRendered()) {
			return;
		}

		Tree tree = (Tree) component;
		ResponseWriter rw = context.getResponseWriter();
		String clientId = tree.getClientId();

		Node value = tree.getValue();
		if (null == value) {
			throw new FacesException("Please set the value attribute of b:tree. ClientId of the tree without value: " + clientId);
		}

		// check is inside form (MyFaces requires to be)
		final UIForm form = BsfUtils.getClosestForm(tree);
		if(form == null) {
			throw new FacesException("The tree component must be inside a form", null);
		}

		rw.startElement("div", tree);
		rw.writeAttribute("id", "tree_" + clientId, "id");
		renderPassThruAttributes(context, component, H.HTML5_DATA_ATTRIBUTES, true);
		String clazz = Responsive.getResponsiveStyleClass(tree, false);
		String styleClass = tree.getStyleClass();
		if (null != styleClass) {
			clazz = styleClass + clazz;
		}
		clazz=clazz.trim();
		if (clazz.length()>0) {
			rw.writeAttribute("class", clazz, "class");
		}
		writeAttribute(rw, "style", tree.getStyle());
		rw.endElement("div");
	}

	@Override
	public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
		if (!component.isRendered()) {
			return;
		}
		Tree tree = (Tree) component;
		String clientId = tree.getClientId();
		String jqClientId = BsfUtils.escapeJQuerySpecialCharsInSelector(clientId);
		ResponseWriter rw = context.getResponseWriter();

		final UIForm form = BsfUtils.getClosestForm(tree);
		if(form == null) {
			throw new FacesException("The tree component must be inside a form", null);
		}
		// String updateItems = BsfUtils.GetOrDefault("'" + tree.getUpdate() + "'", "null");
		String updateItems = tree.getUpdate();
		if(updateItems != null)
			updateItems = ExpressionResolver.getComponentIDs(context, component, updateItems);

		rw.startElement("script", tree);
		//# Start enclosure
		rw.writeText("$(document).ready(function() {", null);
		// build tree management javascript
		Node value = tree.getValue();
		rw.writeText("function getTreeData() { " +
					 "   return '" + TreeModelUtils.renderModelAsJson(value, tree.isRenderRoot())  + "'; " +
					 "} " +

					 // build tree structure
					 "$('#tree_" + jqClientId + "').treeview({ " +
					 	(tree.isShowTags()  ? "showTags: true," : "") +
{'fraction_non_alphanumeric': 0.1220590689137327, 'fraction_numerical': 0.0032537960954446853, 'mean_word_length': 4.138019717102443, 'pattern_counts': {'":': 2, '<': 5, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5830321', 'n_tokens_mistral': 3840, 'n_tokens_neox': 3452, 'n_words': 861}