org.icefaces.ace.component.tree.TreeRenderer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of icefaces-ace Show documentation
Show all versions of icefaces-ace Show documentation
${icefaces.product.name} ACE Component Library
/*
* Copyright 2004-2014 ICEsoft Technologies Canada Corp.
*
* 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 org.icefaces.ace.component.tree;
import org.icefaces.ace.model.tree.*;
import org.icefaces.ace.renderkit.CoreRenderer;
import org.icefaces.ace.util.ComponentUtils;
import org.icefaces.ace.util.HTML;
import org.icefaces.ace.util.JSONBuilder;
import org.icefaces.render.MandatoryResourceComponent;
import org.icefaces.util.JavaScriptRunner;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.model.DataModel;
import java.io.IOException;
import java.lang.String;
import java.util.Iterator;
import java.util.Map;
@MandatoryResourceComponent(tagName = "tree", value="org.icefaces.ace.component.tree.Tree")
public class TreeRenderer extends CoreRenderer {
// Wraps everything
public static final String TREE_CONTAINER_CLASS = "if-tree if-node-sub ui-widget-content ui-corner-all";
// Cell for the node template
public static final String NODE_CLASS = "if-node";
// Wraps individual node template
public static final String NODE_WRAPPER_CLASS = "if-node-wrp";
// Wraps node & subnode container class
public static final String NODE_CONTAINER_CLASS = "if-node-cnt";
// Wraps child node container classes
public static final String SUBNODE_CONTAINER_CLASS = "if-node-sub";
// Wraps switch icon
public static final String NODE_SWITCH_CLASS = "if-node-sw";
public static final String NODE_SWITCH_DISABLED_CLASS = "noexp";
public static final String NODE_SWITCH_UNRENDERED_CLASS = "ui-icon ui-icon-radio-on";
public static final String NODE_SELECTION_DISABLED_CLASS = "noselect";
public static final String NODE_SELECTED_CLASS = "ui-state-active";
// Applied to span with JQuery UI icon class applied
public static final String NODE_SWITCH_ICON_CLASS = "ui-icon";
public static final String NODE_EXPANDED_ICON_CLASS = "ui-icon-minus";
public static final String NODE_CONTRACTED_ICON_CLASS = "ui-icon-plus";
public static final String NODE_CELL = "if-node-td";
public static final String NODE_ROW = "if-node-tr";
private static final String NODE_LINE_CONTAINER = "if-node-ln";
@Override
public void decode(final FacesContext context, final UIComponent component) {
new TreeDecoder(context, (Tree) component) {{
decode();
}};
decodeBehaviors(context, component);
}
@Override
public void encodeChildren(FacesContext context, UIComponent component) throws IOException {}
@Override
public boolean getRendersChildren() { return true; }
@Override
public void encodeEnd(FacesContext facesContext, UIComponent component) throws IOException {
Tree tree = (Tree) component;
TreeRendererContext renderContext = new TreeRendererContext(tree);
ResponseWriter writer = facesContext.getResponseWriter();
openContainerElement(writer, facesContext, renderContext);
encodeRoots(writer, facesContext, renderContext);
encodeHiddenFields(writer, facesContext, renderContext);
encodeScript(writer, facesContext, renderContext);
closeContainerElement(writer, renderContext);
}
private void encodeHiddenFields(ResponseWriter writer, FacesContext facesContext, TreeRendererContext renderContext) throws IOException {
String id;
String clientId = renderContext.getTree().getClientId(facesContext);
id = clientId + "_select";
writer.startElement(HTML.INPUT_ELEM, null);
writer.writeAttribute(HTML.TYPE_ATTR, "hidden", null);
writer.writeAttribute(HTML.ID_ATTR, id, null);
writer.writeAttribute(HTML.NAME_ATTR, id, null);
writer.writeAttribute(HTML.AUTOCOMPLETE_ATTR, "off", null);
writer.endElement(HTML.INPUT_ELEM);
id = clientId + "_deselect";
writer.startElement(HTML.INPUT_ELEM, null);
writer.writeAttribute(HTML.TYPE_ATTR, "hidden", null);
writer.writeAttribute(HTML.ID_ATTR, id, null);
writer.writeAttribute(HTML.NAME_ATTR, id, null);
writer.writeAttribute(HTML.AUTOCOMPLETE_ATTR, "off", null);
writer.endElement(HTML.INPUT_ELEM);
id = clientId + "_expand";
writer.startElement(HTML.INPUT_ELEM, null);
writer.writeAttribute(HTML.TYPE_ATTR, "hidden", null);
writer.writeAttribute(HTML.ID_ATTR, id, null);
writer.writeAttribute(HTML.NAME_ATTR, id, null);
writer.writeAttribute(HTML.AUTOCOMPLETE_ATTR, "off", null);
writer.endElement(HTML.INPUT_ELEM);
id = clientId + "_contract";
writer.startElement(HTML.INPUT_ELEM, null);
writer.writeAttribute(HTML.TYPE_ATTR, "hidden", null);
writer.writeAttribute(HTML.ID_ATTR, id, null);
writer.writeAttribute(HTML.NAME_ATTR, id, null);
writer.writeAttribute(HTML.AUTOCOMPLETE_ATTR, "off", null);
writer.endElement(HTML.INPUT_ELEM);
}
private void encodeScript(ResponseWriter writer, FacesContext facesContext, TreeRendererContext renderContext) throws IOException {
JSONBuilder confJson = new JSONBuilder();
Tree tree = renderContext.getTree();
KeySegmentConverter converter = tree.getKeyConverter();
String clientId = tree.getClientId(facesContext);
boolean selection = renderContext.isSelection();
boolean expansion = renderContext.isExpansion();
boolean reordering = renderContext.isReordering();
boolean multipleSelection = renderContext.isMultipleSelection();
boolean indexIds = converter instanceof NodeModelLazyListKeyConverter ||
converter instanceof NodeModelListSequenceKeyConverter;
String handle = tree.getDragHandle();
confJson.beginFunction("ice.ace.create").item("Tree")
.beginArray()
.item(clientId)
.beginMap()
.entry("expansionMode", tree.getExpansionMode().name())
.entry("selectionMode", tree.getSelectionMode().name())
.entry("indexIds", indexIds);
if (reordering)
confJson.entry("reorder", true);
if (expansion) {
confJson.entry("expansion", true);
}
if (selection) {
confJson.entry("selection", true);
if (multipleSelection) confJson.entry("multiSelect", true);
}
if (handle != null) {
confJson.entry("handle", handle);
}
encodeClientBehaviors(facesContext, tree, confJson);
confJson.endMap().endArray().endFunction();
writer.startElement(HTML.SCRIPT_ELEM, null);
writer.writeAttribute(HTML.TYPE_ATTR, "text/javascript", null);
writer.write(confJson.toString());
writer.endElement(HTML.SCRIPT_ELEM);
// re-initialize tree in client if this was a reorder request
Map paramMap = facesContext.getExternalContext().getRequestParameterMap();
String reorderString = paramMap.get(clientId + TreeDecoder.REORDER_SUFFIX);
if (reorderString != null && reorderString.length() > 0 && !reorderString.equals("[]"))
JavaScriptRunner.runScript(facesContext, confJson.toString());
}
private void encodeRoots(ResponseWriter writer, FacesContext facesContext, TreeRendererContext renderContext) throws IOException {
Tree tree = renderContext.getTree();
// Initalize cached NodeStateMap before clientId begins to change
tree.getClientId();
tree.getStateMap();
// Encode each 'child' of the null keyed node, the root nodes.
for (Iterator> roots = tree.children();
roots.hasNext();) {
Map.Entry root = roots.next();
tree.setNodeToChild(root.getKey().getKeys()[0]);
encodeNode(writer, facesContext, renderContext);
tree.setNodeToParent();
}
tree.setNodeToKey(NodeKey.ROOT_KEY);
}
private void encodeNode(ResponseWriter writer, FacesContext facesContext, TreeRendererContext renderContext) throws IOException {
Tree tree = renderContext.getTree();
NodeState state = tree.getNodeState();
String nodeClass = NODE_CLASS;
String nodeWrapperClass = NODE_WRAPPER_CLASS;
String dotSource = renderContext.getDotURL();
String id = tree.getClientId(facesContext);
boolean expanded = state.isExpanded();
boolean isClientExpansion = renderContext.getExpansionMode().isClient();
if (!state.isSelectionEnabled())
nodeClass+= " " + NODE_SELECTION_DISABLED_CLASS;
if (state.isSelected() && renderContext.isSelection())
nodeWrapperClass += " " + NODE_SELECTED_CLASS;
// Encode 'table' container
writer.startElement(HTML.TABLE_ELEM, null);
writer.writeAttribute(HTML.ID_ATTR, id, null);
writer.writeAttribute(HTML.CLASS_ATTR, NODE_CONTAINER_CLASS, null);
writer.startElement(HTML.TBODY_ELEM, null);
// First 'line' of node
writer.startElement(HTML.TR_ELEM, null);
writer.writeAttribute(HTML.CLASS_ATTR, NODE_ROW, null);
encodeNodeSwitch(writer, renderContext, state);
// Write Node Template
writer.startElement(HTML.TD_ELEM, null);
writer.writeAttribute(HTML.CLASS_ATTR, nodeClass, null);
writer.startElement(HTML.DIV_ELEM, null);
writer.writeAttribute(HTML.CLASS_ATTR, nodeWrapperClass, null);
tree.getNodeForType().encodeAll(facesContext);
writer.endElement(HTML.DIV_ELEM);
writer.endElement(HTML.TD_ELEM);
// End first line
writer.endElement(HTML.TR_ELEM);
// 2nd line of node
writer.startElement(HTML.TR_ELEM, null);
writer.writeAttribute(HTML.CLASS_ATTR, NODE_ROW, null);
// Write filler cell
writer.startElement(HTML.TD_ELEM, null);
writer.writeAttribute(HTML.CLASS_ATTR, NODE_CELL, null);
writer.startElement(HTML.DIV_ELEM, null);
writer.writeAttribute(HTML.CLASS_ATTR, NODE_LINE_CONTAINER, null);
writer.startElement(HTML.IMG_ELEM, null);
writer.writeAttribute(HTML.SRC_ATTR, dotSource, null);
writer.endElement(HTML.IMG_ELEM);
writer.endElement(HTML.DIV_ELEM);
writer.endElement(HTML.TD_ELEM);
// Open SubComponent Container
writer.startElement(HTML.TD_ELEM, null);
writer.writeAttribute(HTML.CLASS_ATTR, SUBNODE_CONTAINER_CLASS, null);
if (isClientExpansion && !expanded)
writer.writeAttribute(HTML.STYLE_ATTR, "display:none;", null);
if (expanded || isClientExpansion) {
encodeSubnodes(writer, facesContext, renderContext);
}
// Close SubComponent Container
writer.endElement(HTML.TD_ELEM);
// End 2nd line of node
writer.endElement(HTML.TR_ELEM);
// End node
writer.endElement(HTML.TBODY_ELEM);
if (renderContext.isReordering()) {
writer.startElement(HTML.SCRIPT_ELEM, null);
writer.writeAttribute(HTML.TYPE_ATTR, "text/javascript", null);
writer.write("if (ice.ace.instance('"+renderContext.getRootClientId()+"')) ice.ace.instance('"+renderContext.getRootClientId()+"').rs('"+id+"');");
writer.endElement(HTML.SCRIPT_ELEM);
}
writer.endElement(HTML.TABLE_ELEM);
}
private void encodeSubnodes(ResponseWriter writer, FacesContext facesContext, TreeRendererContext renderContext) throws IOException {
Tree tree = renderContext.getTree();
for (Iterator> children = tree.children();
children.hasNext();) {
Map.Entry node = children.next();
Object[] nextKeys = node.getKey().getKeys();
tree.setNodeToChild(nextKeys[nextKeys.length - 1]);
if (tree.isNodeAvailable())
encodeNode(writer, facesContext, renderContext);
tree.setNodeToParent();
}
}
// Responsible for encoding node switch and heirarchy line.
private void encodeNodeSwitch(ResponseWriter writer, TreeRendererContext renderContext, NodeState state) throws IOException {
String switchClass = NODE_SWITCH_CLASS;
String iconClass = NODE_SWITCH_ICON_CLASS;
String expandedClass = NODE_EXPANDED_ICON_CLASS;
String contractedClass = NODE_CONTRACTED_ICON_CLASS;
String dotSource = renderContext.getDotURL();
Tree tree = renderContext.getTree();
boolean lazy = renderContext.isLazy();
boolean leaf = lazy ? false : tree.isLeaf(); // prevent attempt at loading children in lazy mode
DataModel model = tree.getDataModel();
if (model != null && model instanceof LazyNodeDataModel) {
Object parent = ((LazyNodeDataModel) model).getParentData();
if (parent != null) {
NodeStateMap stateMap = tree.getStateMap();
NodeState parentState = stateMap.get(parent);
if (parentState.isExpanded()) {
leaf = tree.isLeaf(); // do load children in lazy mode only if immediate parent is expanded
}
}
}
if (leaf)
; // don't add anything to icon class
else if (renderContext.isExpansion())
iconClass += " " + (state.isExpanded() ? expandedClass : contractedClass);
else
iconClass = NODE_SWITCH_UNRENDERED_CLASS;
if (!state.isExpansionEnabled() || !renderContext.isExpansion())
switchClass += " " + NODE_SWITCH_DISABLED_CLASS;
writer.startElement(HTML.TD_ELEM, null);
writer.writeAttribute(HTML.CLASS_ATTR, switchClass, null);
writer.startElement(HTML.DIV_ELEM, null);
writer.writeAttribute(HTML.CLASS_ATTR, NODE_LINE_CONTAINER, null);
writer.startElement(HTML.IMG_ELEM, null);
writer.writeAttribute(HTML.SRC_ATTR, dotSource, null);
writer.endElement(HTML.IMG_ELEM);
writer.startElement(HTML.SPAN_ELEM, null);
writer.writeAttribute(HTML.CLASS_ATTR, iconClass, null);
if (leaf)
writer.writeAttribute(HTML.STYLE_ATTR, "background-position:-160px 0;", null);
writer.endElement(HTML.SPAN_ELEM);
writer.endElement(HTML.DIV_ELEM);
writer.endElement(HTML.TD_ELEM);
}
private void closeContainerElement(ResponseWriter writer, TreeRendererContext renderContext) throws IOException {
writer.endElement(HTML.SPAN_ELEM);
}
private void openContainerElement(ResponseWriter writer, FacesContext context, TreeRendererContext renderContext) throws IOException {
writer.startElement(HTML.SPAN_ELEM, renderContext.getTree());
String clientId = renderContext.getTree().getClientId(context);
writer.writeAttribute(HTML.ID_ATTR, clientId, null);
ComponentUtils.enableOnElementUpdateNotify(writer, clientId);
writer.writeAttribute(HTML.CLASS_ATTR, TREE_CONTAINER_CLASS, null);
String accesskey = renderContext.getTree().getAccesskey();
if (accesskey != null) {
writer.writeAttribute("accesskey", accesskey, null);
writer.writeAttribute("tabindex", "0", null);
}
}
}