/*******************************************************************************
* Copyright (c) 2007 Exadel, Inc. and Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is made available under the terms of the
* Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Exadel, Inc. and Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.jboss.tools.jsf.vpe.richfaces.template;
import static org.jboss.tools.vpe.xulrunner.util.XPCOM.queryInterface;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.jboss.tools.jsf.vpe.richfaces.ComponentUtil;
import org.jboss.tools.vpe.editor.VpeVisualDomBuilder;
import org.jboss.tools.vpe.editor.context.VpePageContext;
import org.jboss.tools.vpe.editor.template.VpeAbstractTemplate;
import org.jboss.tools.vpe.editor.template.VpeChildrenInfo;
import org.jboss.tools.vpe.editor.template.VpeCreationData;
import org.jboss.tools.vpe.editor.template.VpeToggableTemplate;
import org.jboss.tools.vpe.editor.util.Constants;
import org.jboss.tools.vpe.editor.util.HTML;
import org.mozilla.interfaces.nsIDOMDocument;
import org.mozilla.interfaces.nsIDOMElement;
import org.mozilla.interfaces.nsIDOMNode;
import org.mozilla.xpcom.XPCOMException;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
public class RichFacesTabPanelTemplate extends VpeAbstractTemplate implements VpeToggableTemplate {
public static final String CSS_PANEL = "rich-tabpanel"; //$NON-NLS-1$
public static final String CSS_CONTENT = "rich-tabpanel-content"; //$NON-NLS-1$
public static final String CSS_CONTENT_POSITION = "rich-tabpanel-content-position"; //$NON-NLS-1$
public static final String CSS_SIDE_BORDER = "rich-tabhdr-side-border"; //$NON-NLS-1$
public static final String CSS_SIDE_CELL = "rich-tabhdr-side-cell"; //$NON-NLS-1$
public static final String CSS_CELL_ACTIVE = "rich-tabhdr-cell-active"; //$NON-NLS-1$
public static final String CSS_CELL_INACTIVE = "rich-tabhdr-cell-inactive"; //$NON-NLS-1$
public static final String CSS_CELL_DISABLED = "rich-tabhdr-cell-disabled"; //$NON-NLS-1$
private static final String RICH_FACES_TAB_PANEL = "richFacesTabPanel"; //$NON-NLS-1$
private static final String CSS_FILE_PATH = "tabPanel/tabPanel.css"; //$NON-NLS-1$
private static final String SPACER_FILE_PATH = "common/spacer.gif"; //$NON-NLS-1$
private static final String INCLUDE_TAG = ":include"; //$NON-NLS-1$
private static final String YES = "yes"; //$NON-NLS-1$
private final String HEADER_ALINGMENT = "headerAlignment"; //$NON-NLS-1$
private final String HEADER_SPACING = "headerSpacing"; //$NON-NLS-1$
private final String SELECTED_TAB = "selectedTab"; //$NON-NLS-1$
private final String DIR = "dir"; //$NON-NLS-1$
private final String DIR_RTL = "RTL"; //$NON-NLS-1$
private final String DIR_LTR = "LTR"; //$NON-NLS-1$
private final String HEADER_CLASS = "headerClass"; //$NON-NLS-1$
private final String CONTENT_CLASS = "contentClass"; //$NON-NLS-1$
private final String CONTENT_STYLE = "contentStyle"; //$NON-NLS-1$
private final String TAB_CLASS = "tabClass"; //$NON-NLS-1$
private final String ACTIVE_TAB_CLASS = "activeTabClass"; //$NON-NLS-1$
private final String INACTIVE_TAB_CLASS = "inactiveTabClass"; //$NON-NLS-1$
private final String DISABLED_TAB_CLASS = "disabledTabClass"; //$NON-NLS-1$
private final String ZERO = "0"; //$NON-NLS-1$
private final String ONE = "1"; //$NON-NLS-1$
private final String TWO = "2"; //$NON-NLS-1$
private final String SPACE = " "; //$NON-NLS-1$
private final String EMPTY = ""; //$NON-NLS-1$
private final String TAB = ":tab"; //$NON-NLS-1$
private final String NAME = "name"; //$NON-NLS-1$
private List<nsIDOMElement> storedTabHeaders = new ArrayList<nsIDOMElement>();
private static Map toggleMap = new HashMap();
public VpeCreationData create(VpePageContext pageContext, Node sourceNode, nsIDOMDocument visualDocument) {
Element sourceElement = (Element)sourceNode;
nsIDOMElement table = visualDocument.createElement(HTML.TAG_TABLE);
VpeCreationData creationData = new VpeCreationData(table);
ComponentUtil.setCSSLink(pageContext, CSS_FILE_PATH, RICH_FACES_TAB_PANEL);
setDirAttr(table, sourceElement);
table.setAttribute(HTML.ATTR_CLASS,
ComponentUtil.getAttribute(sourceElement, RichFaces.ATTR_STYLE_CLASS)
+ SPACE + CSS_PANEL);
table.setAttribute(HTML.ATTR_BORDER, ZERO);
table.setAttribute(HTML.ATTR_CELLPADDING, ZERO);
table.setAttribute(HTML.ATTR_CELLSPACING, ZERO);
table.setAttribute(HTML.ATTR_STYLE, getStyle(sourceElement));
nsIDOMElement tbody = visualDocument.createElement(HTML.TAG_TBODY);
table.appendChild(tbody);
nsIDOMElement tr = visualDocument.createElement(HTML.TAG_TR);
tbody.appendChild(tr);
nsIDOMElement td = visualDocument.createElement(HTML.TAG_TD);
tr.appendChild(td);
td.setAttribute(HTML.ATTR_ALIGN, getHeaderAlignment(sourceElement));
td.setAttribute(HTML.ATTR_CLASS, ComponentUtil
.getAttribute(sourceElement, HEADER_CLASS));
nsIDOMElement inerTable = visualDocument.createElement(HTML.TAG_TABLE);
td.appendChild(inerTable);
inerTable.setAttribute(HTML.ATTR_BORDER, ZERO);
inerTable.setAttribute(HTML.ATTR_CELLPADDING, ZERO);
inerTable.setAttribute(HTML.ATTR_CELLSPACING, ZERO);
// Encode header
nsIDOMElement inerTr = visualDocument.createElement(HTML.TAG_TR);
inerTable.appendChild(inerTr);
nsIDOMElement inerTd = visualDocument.createElement(HTML.TAG_TD);
inerTr.appendChild(inerTd);
nsIDOMElement img = visualDocument.createElement(HTML.TAG_IMG);
inerTd.appendChild(img);
ComponentUtil.setImg(img, SPACER_FILE_PATH);
img.setAttribute(HTML.ATTR_WIDTH, TWO);
img.setAttribute(HTML.ATTR_HEIGHT, ONE);
img.setAttribute(HTML.ATTR_BORDER, ZERO);
List<Node> children = ComponentUtil.getChildren(sourceElement);
int activeId = getActiveId(sourceElement, children);
int i = 0;
for (Node child : children) {
boolean active = (i == activeId);
if (child.getNodeName().endsWith(INCLUDE_TAG)) {
VpeChildrenInfo vpeChildrenInfo = new VpeChildrenInfo(inerTr);
creationData.addChildrenInfo(vpeChildrenInfo);
vpeChildrenInfo.addSourceChild(child);
}
if(child.getNodeName().endsWith(TAB)) {
String headerSpacing = sourceElement.hasAttribute(HEADER_SPACING) ? sourceElement.getAttribute(HEADER_SPACING) : ONE;
/*
* Adds spacer before first tab
*/
if (i == 0) {
addSpacer(visualDocument, inerTr, headerSpacing);
}
nsIDOMElement headerTd = RichFacesTabTemplate.encodeHeader(
pageContext,
creationData,
(Element) child,
visualDocument, inerTr, active,
ComponentUtil.getAttribute(sourceElement,
TAB_CLASS),
(ComponentUtil.getAttribute(sourceElement,
ACTIVE_TAB_CLASS)
+ SPACE + CSS_CELL_ACTIVE).trim(),
(ComponentUtil.getAttribute(sourceElement,
INACTIVE_TAB_CLASS)
+ SPACE + CSS_CELL_INACTIVE).trim(),
(ComponentUtil.getAttribute(sourceElement,
DISABLED_TAB_CLASS)
+ SPACE + CSS_CELL_DISABLED).trim(),
String.valueOf(i));
i++;
addSpacer(visualDocument, inerTr, headerSpacing);
storedTabHeaders.add(headerTd);
}
}
inerTd = visualDocument.createElement(HTML.TAG_TD);
inerTr.appendChild(inerTd);
img = visualDocument.createElement(HTML.TAG_IMG);
inerTd.appendChild(img);
ComponentUtil.setImg(img, SPACER_FILE_PATH);
img.setAttribute(HTML.ATTR_WIDTH, ONE);
img.setAttribute(HTML.ATTR_HEIGHT, ONE);
img.setAttribute(HTML.ATTR_BORDER, ZERO);
// Encode first child tab
inerTr = visualDocument.createElement(HTML.TAG_TR);
tbody.appendChild(inerTr);
children = ComponentUtil.getChildren(sourceElement);
i = 0;
for (Node child : children) {
boolean active = (i == activeId);
if(child.getNodeName().endsWith(TAB)) {
i++;
if (active) {
RichFacesTabTemplate.encodeBody(pageContext, creationData,
(Element) child, visualDocument, inerTr, true,
ComponentUtil.getAttribute(sourceElement,
CONTENT_CLASS)
+ SPACE + CSS_PANEL
+ SPACE + CSS_CONTENT
+ SPACE + CSS_CONTENT_POSITION,
ComponentUtil.getAttribute(sourceElement,
CONTENT_STYLE));
break;
}
}
}
return creationData;
}
/**
* Adds the spacer.
* Add <td><img src="#{spacer}" height="1" alt="" border="0" style="#{this:encodeHeaderSpacing(context, component)}"/></td>
*
* @param visualDocument the visual document
* @param parentTr the parent tr
* @param headerSpacing the header spacing
*/
private void addSpacer(nsIDOMDocument visualDocument, nsIDOMElement parentTr, String headerSpacing) {
nsIDOMElement spaceTd = visualDocument.createElement(HTML.TAG_TD);
parentTr.appendChild(spaceTd);
nsIDOMElement spaceImg = visualDocument.createElement(HTML.TAG_IMG);
spaceTd.appendChild(spaceImg);
ComponentUtil.setImg(spaceImg, SPACER_FILE_PATH);
spaceImg.setAttribute(HTML.ATTR_HEIGHT, ONE);
spaceImg.setAttribute(HTML.ATTR_BORDER, ZERO);
spaceImg.setAttribute(HTML.ATTR_STYLE, "width: " + headerSpacing + Constants.PIXEL); //$NON-NLS-1$
}
private int getActiveId(Element sourceElement, List<Node> children) {
int activeId = -1;
try {
activeId = Integer.valueOf((String)toggleMap.get(sourceElement));
} catch (NumberFormatException nfe) {
activeId = -1;
}
if (activeId == -1) {
if (sourceElement.hasAttribute(SELECTED_TAB)) {
activeId = getTabId(children, sourceElement.getAttribute(SELECTED_TAB));
}
}
if (activeId == -1)
activeId = 0;
int count = getChildrenCount(children);
if (count - 1 < activeId) {
activeId = count - 1;
}
return activeId;
}
private int getChildrenCount(List<Node> children) {
int count = 0;
for (Node child : children) {
if (child.getNodeName().endsWith(TAB)) {
count++;
}
}
return count;
}
private int getTabId(List<Node> children, String tabName) {
int count = 0;
for (Node child : children) {
if (child.getNodeName().endsWith(TAB)) {
if (!(child instanceof Element))
continue;
String name = ((Element)child).getAttribute(NAME);
if (tabName.equals(name))
return count;
count++;
}
}
return -1;
}
private String getStyle(Element sourceElement) {
String styleAttrValue = sourceElement.getAttribute(HTML.ATTR_STYLE);
String style = sourceElement.hasAttribute(HTML.ATTR_STYLE) ? styleAttrValue : EMPTY;
if (!ComponentUtil.parameterPresent(styleAttrValue, HTML.ATTR_WIDTH)) {
String width = sourceElement.hasAttribute(HTML.ATTR_WIDTH) ? sourceElement.getAttribute(HTML.ATTR_WIDTH) : "100%"; //$NON-NLS-1$
style = ComponentUtil.addParameter(style, "width:" + width); //$NON-NLS-1$
}
if (!ComponentUtil.parameterPresent(styleAttrValue, HTML.ATTR_HEIGHT)) {
String height = sourceElement.hasAttribute(HTML.ATTR_HEIGHT) ? sourceElement.getAttribute(HTML.ATTR_HEIGHT) : EMPTY;
if (height.length() > 0) {
style =ComponentUtil.addParameter(style, "height:" + height); //$NON-NLS-1$
}
}
return style;
}
/**
* Sets the dir attribute to the element.
*
* @param element the element
* @param dir the dir value
*/
private void setDirAttr(nsIDOMElement element, Element sourceElement) {
String dir = ComponentUtil.getAttribute(sourceElement, DIR);
if ((null != dir) && (!EMPTY.equals(dir))){
if ((DIR_LTR.equalsIgnoreCase(dir)) || (DIR_RTL.equalsIgnoreCase(dir))) {
element.setAttribute(DIR, dir);
}
}
}
private String getHeaderAlignment(Element sourceElement) {
return sourceElement.hasAttribute(HEADER_ALINGMENT) ? sourceElement.getAttribute(HEADER_ALINGMENT) : HTML.VALUE_ALIGN_LEFT;
}
public void toggle(VpeVisualDomBuilder builder, Node sourceNode, String toggleId) {
toggleMap.put(sourceNode, toggleId);
}
public void stopToggling(Node sourceNode) {
toggleMap.remove(sourceNode);
}
/* (non-Javadoc)
* @see org.jboss.tools.vpe.editor.template.VpeAbstractTemplate#isRecreateAtAttrChange(org.jboss.tools.vpe.editor.context.VpePageContext, org.w3c.dom.Element, org.mozilla.interfaces.nsIDOMDocument, org.mozilla.interfaces.nsIDOMElement, java.lang.Object, java.lang.String, java.lang.String)
*/
@Override
public boolean recreateAtAttrChange(VpePageContext pageContext,
Element sourceElement, nsIDOMDocument visualDocument,
nsIDOMElement visualNode, Object data, String name, String value) {
return true;
}
/**
* Is invoked after construction of all child nodes of the current visual node.
* @param pageContext Contains the information on edited page.
* @param sourceNode The current node of the source tree.
* @param visualDocument The document of the visual tree.
* @param data Object <code>VpeCreationData</code>, built by a method <code>create</code>
*/
public void validate(VpePageContext pageContext, Node sourceNode, nsIDOMDocument visualDocument, VpeCreationData data) {
List<nsIDOMNode> elements = new ArrayList<nsIDOMNode>();
ComponentUtil.findAllElementsByName(data.getNode(), elements, HTML.TAG_TABLE);
for (nsIDOMNode node : elements) {
try {
nsIDOMElement element = queryInterface(node, nsIDOMElement.class);
if (ComponentUtil.getAttribute(element, RichFacesTabTemplate.TAB_HEADER_ATTR).equalsIgnoreCase(YES)) {
element.removeAttribute(HTML.ATTR_STYLE);
}
if (ComponentUtil.getAttribute(element, RichFacesTabTemplate.TAB_BODY_ATTR).equalsIgnoreCase(YES)) {
element.setAttribute(HTML.ATTR_STYLE, HTML.ATTR_DISPLAY
+ Constants.COLON
+ RichFacesTabTemplate.DISABLED_ELEMENT_STYLE
+ Constants.SEMICOLON);
}
} catch (XPCOMException exeption) {
// Ignore
}
}
super.validate(pageContext, sourceNode, visualDocument, data);
if ((storedTabHeaders == null) || (storedTabHeaders.size() < 1)){
return;
}
for (nsIDOMElement tab : storedTabHeaders) {
String value = tab.getAttribute(VpeVisualDomBuilder.VPE_USER_TOGGLE_ID);
ComponentUtil.applyAttributeValueOnChildren(
VpeVisualDomBuilder.VPE_USER_TOGGLE_ID,
value,ComponentUtil.getElementChildren(tab));
ComponentUtil.applyAttributeValueOnChildren(
VpeVisualDomBuilder.VPE_USER_TOGGLE_LOOKUP_PARENT,
Constants.TRUE, ComponentUtil.getElementChildren(tab));
}
}
}