/*******************************************************************************
* Copyright (c) 2007 Exadel, Inc. and Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* 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.text.DateFormatSymbols;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.List;
import java.util.Locale;
import java.util.WeakHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
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.mapping.AttributeData;
import org.jboss.tools.vpe.editor.mapping.VpeElementData;
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.interfaces.nsIDOMNodeList;
import org.mozilla.interfaces.nsIDOMText;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
/**
* Displays template for calendar
*
* @author dsakovich@exadel.com
*
*/
public class RichFacesCalendarTemplate extends VpeAbstractTemplate implements
VpeToggableTemplate {
private static final WeakHashMap<Node, Object> expandedCalendars = new WeakHashMap<Node, Object>();
final static int COLUMN = 8;
final static String FILL_WIDTH = "100%"; //$NON-NLS-1$
final static int NUM_DAYS_IN_WEEK = 7;
final static int NUM_WEEK_ON_PAGE = 6;
final static int NUM_MONTHS = 12;
final static int CALENDAR_WIDTH = 200;
final static int CALENDAR_INPUT_WIDTH = CALENDAR_WIDTH - 20;
final static int CALENDAR_IMAGE_WIDTH = 20;
final static int CALENDAR_CUSTOM_IMAGE_WIDTH = 40;
final static int CALENDAR_BUTTON_WIDTH = 80;
static final String DEFAULT_DATE_PATTERN = "MMM dd,yyyy"; //$NON-NLS-1$
/* rich:calendar attributes */
/* CSS classes */
static final String CSS_R_C_INPUT = "rich-calendar-input"; //$NON-NLS-1$
static final String CSS_R_C_BUTTON = "rich-calendar-button"; //$NON-NLS-1$
static final String CSS_R_C_EXTERIOR = "rich-calendar-exterior"; //$NON-NLS-1$
static final String CSS_R_C_HEADER = "rich-calendar-header"; //$NON-NLS-1$
static final String CSS_R_C_TOOL = "rich-calendar-tool"; //$NON-NLS-1$
static final String CSS_R_C_MONTH = "rich-calendar-month"; //$NON-NLS-1$
static final String CSS_R_C_TOOL_CLOSE = "rich-calendar-tool-close"; //$NON-NLS-1$
static final String CSS_R_C_DAYS = "rich-calendar-days"; //$NON-NLS-1$
static final String CSS_R_C_WEEKENDS = "rich-calendar-weekends"; //$NON-NLS-1$
static final String CSS_R_C_WEEK = "rich-calendar-week"; //$NON-NLS-1$
static final String CSS_R_C_CELL = "rich-calendar-cell"; //$NON-NLS-1$
static final String CSS_R_C_CELL_SIZE = "rich-calendar-cell-size"; //$NON-NLS-1$
static final String CSS_R_C_HOLLY = "rich-calendar-holly"; //$NON-NLS-1$
static final String CSS_R_C_BOUNDARY_DATES = "rich-calendar-boundary-dates"; //$NON-NLS-1$
static final String CSS_R_C_BTN = "rich-calendar-btn"; //$NON-NLS-1$
static final String CSS_R_C_TODAY = "rich-calendar-today"; //$NON-NLS-1$
static final String CSS_R_C_SELECT = "rich-calendar-select"; //$NON-NLS-1$
static final String CSS_R_C_TOOLFOOTER = "rich-calendar-toolfooter"; //$NON-NLS-1$
static final String CSS_R_C_FOOTER = "rich-calendar-footer"; //$NON-NLS-1$
static final String CSS_R_C_HEADER_OPTIONAL = "rich-calendar-header-optional"; //$NON-NLS-1$
static final String CSS_R_C_FOOTER_OPTIONAL = "rich-calendar-footer-optional"; //$NON-NLS-1$
static final String CSS_R_C_TOOL_BTN = "rich-calendar-tool-btn"; //$NON-NLS-1$
private final static String WEEK_DAY_HTML_CLASS_ATTR = CSS_R_C_DAYS;
private final static String HOL_WEEK_DAY_HTML_CLASS_ATTR = CSS_R_C_DAYS
+ " " + CSS_R_C_WEEKENDS; //$NON-NLS-1$
private final static String TODAY_HTML_CLASS_ATTR = CSS_R_C_CELL_SIZE
+ " " + CSS_R_C_CELL + " " + CSS_R_C_TODAY; //$NON-NLS-1$ //$NON-NLS-2$
private final static String CUR_MONTH_HTML_CLASS_ATTR = CSS_R_C_CELL_SIZE
+ " " + CSS_R_C_CELL; //$NON-NLS-1$
private final static String HOL_CUR_MONTH_HTML_CLASS_ATTR = CSS_R_C_CELL_SIZE
+ " " + CSS_R_C_CELL + " " + CSS_R_C_HOLLY; //$NON-NLS-1$ //$NON-NLS-2$
private final static String OTHER_MONTH_HTML_CLASS_ATTR = CSS_R_C_CELL_SIZE
+ " " + CSS_R_C_CELL + " " + CSS_R_C_BOUNDARY_DATES; //$NON-NLS-1$ //$NON-NLS-2$
private final static String HOL_OTHER_MONTH_HTML_CLASS_ATTR = CSS_R_C_CELL_SIZE
+ " " + CSS_R_C_CELL + " " + CSS_R_C_HOLLY + " " + CSS_R_C_BOUNDARY_DATES; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
/* Attribute values */
private static final String DIRECTIONS_TOP_LEFT = "top-left"; //$NON-NLS-1$
private static final String DIRECTIONS_TOP_RIGHT = "top-right"; //$NON-NLS-1$
private static final String DIRECTIONS_BOTTOM_LEFT = "bottom-left"; //$NON-NLS-1$
private static final String DIRECTIONS_BOTTOM_RIGHT = "bottom-right"; //$NON-NLS-1$
final static String DIRECTION_PATTERN = "(top|bottom)-(left|right)"; //$NON-NLS-1$
final static String UNDEFINED = "undefined"; //$NON-NLS-1$
final static int DEFAULT_CELL_WIDTH = 25;
final static int DEFAULT_CELL_HEIGHT = 22;
final static int DEFAULT_OPTIONAL_CELL_HEIGHT = 26;
final static int JOINT_POINT_BOTTOM = 5;
final static int JOINT_POINT_TOP = -17;
final static String TOP = "top"; //$NON-NLS-1$
final static String LEFT = "left"; //$NON-NLS-1$
final static String HIDDEN = "hidden"; //$NON-NLS-1$
/*
* ++++++++++++++++++++++++++++++++++++++++++++++++++++ NEW FIELDS
*/
static final String ATTR_SHOW_SHOW_WEEKS_DAY_BAR = "showWeekDaysBar"; //$NON-NLS-1$
static final String ATTR_SHOW_WEEKS_BAR = "showWeeksBar"; //$NON-NLS-1$
static final String ATTR_SHOW_HEADER = "showHeader"; //$NON-NLS-1$
static final String ATTR_SHOW_FOOTER = "showFooter"; //$NON-NLS-1$
static final String ATTR_CELL_HEIGHT = "cellHeight"; //$NON-NLS-1$
static final String ATTR_CELL_WIDTH = "cellWidth"; //$NON-NLS-1$
static final String ATTR_BUTTON_LABEL = "buttonLabel"; //$NON-NLS-1$
static final String ATTR_SHOW_APPLY_BUTTON = "showApplyButton"; //$NON-NLS-1$
static final String ATTR_DATE_PATTERN = "datePattern"; //$NON-NLS-1$
static final String ATTR_FIRST_WEEK_DAY = "firstWeekDay"; //$NON-NLS-1$
static final String ATTR_WEEK_DAY_LABELS_SHORT = "weekDayLabelsShort"; //$NON-NLS-1$
static final String ATTR_MONTH_LABELS = "monthLabels"; //$NON-NLS-1$
static final String ATTR_ENABLE_MANUAL_INPUT = "enableManualInput"; //$NON-NLS-1$
static final String ATTR_TODAY_CONTROL_MODE = "todayControlMode"; //$NON-NLS-1$
static final String NAME_FACET_OPTIONAL_FOOTER = "optionalFooter"; //$NON-NLS-1$
static final String NAME_FACET_OPTIONAL_HEADER = "optionalHeader"; //$NON-NLS-1$
static final String NAME_FACET_WEEK_DAY = "weekDay"; //$NON-NLS-1$
static final String NAME_FACET_WEEK_NUMBER = "weekNumber"; //$NON-NLS-1$
static final boolean FACET_SEARCH_ORDER = true; // it means that facet will
// be look for from end
final private static String DEFAULT_INPUT_STYLE = "vertical-align: middle;";//$NON-NLS-1$
final private static String POSITION_RELATIVE_STYLE = "position: relative;";//$NON-NLS-1$
final private static String POSITION_ABSOLUTE_STYLE = "position: absolute;";//$NON-NLS-1$
final private static String STYLE_PATH = "calendar/calendar.css"; //$NON-NLS-1$
final private static String DEFAULT_BUTTON_ICON = "calendar/calendar.gif"; //$NON-NLS-1$
final private static String DEFAULT_BUTTON_ICON_DISABLED = "calendar/disabled_button.gif"; //$NON-NLS-1$
final private static String SPARATOR_IMG = "calendar/separator.gif"; //$NON-NLS-1$
final private static String DEFAULT_BUTTON_STYLE = "vertical-align: middle;";//$NON-NLS-1$
final private static String NEXT_MONTH_CONTROL = ">";//$NON-NLS-1$
final private static String PREVIOUS_MONTH_CONTROL = "<";//$NON-NLS-1$
final private static String NEXT_YEAR_CONTROL = ">>";//$NON-NLS-1$
final private static String PREVIOUS_YEAR_CONTROL = "<<";//$NON-NLS-1$
final private static String APPLY_CONTROL = "Apply"; //$NON-NLS-1$
final private static String TODAY_CONTROL = "Today"; //$NON-NLS-1$
final private static String CLOSE_CONTROL = "X"; //$NON-NLS-1$
private int tableWidth;
private int tableHeight;
private Calendar calendar;
private Locale locale;
private String[] weekDays;
private String[] months;
private int horizontalOffset;
private int verticalOffset;
private String currentMonthControl;
private String currentDayControl;
private DirectionData direction;
private DirectionData jointPoint;
private int cellHeight;
private int cellWidth;
private int zindex;
private String value;
private String inputStyle;
private String inputClass;
private String inputSize;
private boolean disabled;
private String buttonIcon;
private String buttonLabel;
private String buttonClass;
private String style;
private String styleClass;
private boolean showInput;
private boolean showWeekDaysBar;
private boolean showWeeksBar;
private boolean showHeader;
private boolean showFooter;
private boolean showApplyButton;
private boolean showTodayControl;
private boolean popup;
private int firstWeekDay;
private String datePattern;
/**
* Instantiates a new rich faces calendar template.
*/
public RichFacesCalendarTemplate() {
super();
}
/**
* Creates a node of the visual tree on the node of the source tree. This
* visual node should not have the parent node This visual node can have
* child nodes.
*
* @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.
* @return The information on the created node of the visual tree.
*/
public VpeCreationData create(VpePageContext pageContext, Node sourceNode,
nsIDOMDocument visualDocument) {
Element source = (Element) sourceNode;
readAttributes(pageContext, sourceNode);
ComponentUtil.setCSSLink(pageContext, STYLE_PATH, "calendar"); //$NON-NLS-1$
nsIDOMElement wrapper = visualDocument.createElement(HTML.TAG_SPAN);
VpeCreationData creationData = new VpeCreationData(wrapper, true);
nsIDOMElement calendar;
nsIDOMElement calendarWithPopup;
if (!popup) {
if (disabled) {
calendar = visualDocument.createElement(HTML.TAG_DIV);
} else {
calendar = createCalendar(visualDocument, creationData, source);
}
wrapper.appendChild(calendar);
} else {
calendarWithPopup = createPopupCalendar(visualDocument, source,
creationData);
wrapper.appendChild(calendarWithPopup);
}
return creationData;
}
/**
* Checks, whether it is necessary to re-create an element at change of
* attribute
*
* @param pageContext
* Contains the information on edited page.
* @param sourceElement
* The current element of the source tree.
* @param visualDocument
* The document of the visual tree.
* @param visualNode
* The current node of the visual tree.
* @param data
* The arbitrary data, built by a method <code>create</code>
* @param name
* Atrribute name
* @param value
* Attribute value
* @return <code>true</code> if it is required to re-create an element at a
* modification of attribute, <code>false</code> otherwise.
*/
public boolean recreateAtAttrChange(VpePageContext pageContext,
Element sourceElement, nsIDOMDocument visualDocument,
nsIDOMElement visualNode, Object data, String name, String value) {
return true;
}
/**
*
* @param visualDocument
* @return Node of the visual tree.
*/
private nsIDOMElement createCalendar(nsIDOMDocument visualDocument,
VpeCreationData creationData, Element sourceElement) {
nsIDOMElement table = visualDocument.createElement(HTML.TAG_TABLE);
table.setAttribute(HTML.ATTR_CELLPADDING, "0"); //$NON-NLS-1$
table.setAttribute(HTML.ATTR_BORDER, "0"); //$NON-NLS-1$
table.setAttribute(HTML.ATTR_CELLSPACING, "0"); //$NON-NLS-1$
table.setAttribute(HTML.ATTR_CLASS, CSS_R_C_EXTERIOR
+ Constants.WHITE_SPACE + styleClass);
table.setAttribute(HTML.ATTR_STYLE, style);
nsIDOMElement tbody = visualDocument.createElement(HTML.TAG_TBODY);
nsIDOMElement optionalHeader = null;
nsIDOMElement header = null;
nsIDOMElement calendarBody = createCalendarBody(visualDocument,
creationData, sourceElement);
nsIDOMElement footer = null;
nsIDOMElement optionalFooter = null;
Element optionalHeaderFacet = ComponentUtil.getFacetElement(
sourceElement, NAME_FACET_OPTIONAL_HEADER, FACET_SEARCH_ORDER);
if (optionalHeaderFacet != null) {
optionalHeader = createCustomBlock(visualDocument,
optionalHeaderFacet, creationData, CSS_R_C_HEADER_OPTIONAL);
tableHeight += DEFAULT_OPTIONAL_CELL_HEIGHT;
}
if (showHeader) {
Element headerFacet = ComponentUtil.getFacetElement(sourceElement,
RichFaces.NAME_FACET_HEADER, FACET_SEARCH_ORDER);
if (headerFacet != null) {
header = createCustomBlock(visualDocument, headerFacet,
creationData, CSS_R_C_HEADER);
} else {
List<Cell> headerContent = new ArrayList<Cell>();
headerContent
.add(new Cell(PREVIOUS_YEAR_CONTROL, CSS_R_C_TOOL));
headerContent
.add(new Cell(PREVIOUS_MONTH_CONTROL, CSS_R_C_TOOL));
headerContent.add(new Cell(currentMonthControl, CSS_R_C_MONTH));
headerContent.add(new Cell(NEXT_MONTH_CONTROL, CSS_R_C_TOOL));
headerContent.add(new Cell(NEXT_YEAR_CONTROL, CSS_R_C_TOOL));
if (popup)
headerContent.add(new Cell(CLOSE_CONTROL, CSS_R_C_TOOL
+ Constants.WHITE_SPACE + CSS_R_C_TOOL_CLOSE, true,
true));
header = createHeaderBlock(visualDocument, CSS_R_C_HEADER,
headerContent);
}
}
if (showFooter) {
Element footerFacet = ComponentUtil.getFacetElement(sourceElement,
RichFaces.NAME_FACET_FOOTER, FACET_SEARCH_ORDER);
if (footerFacet != null) {
footer = createCustomBlock(visualDocument, footerFacet,
creationData, CSS_R_C_FOOTER);
} else {
List<Cell> footerContent = new ArrayList<Cell>();
if (showTodayControl)
footerContent.add(new Cell(TODAY_CONTROL,
CSS_R_C_TOOLFOOTER, showTodayControl
&& showApplyButton));
if (popup && showApplyButton)
footerContent.add(new Cell(APPLY_CONTROL,
CSS_R_C_TOOLFOOTER, false, true));
footer = createFooterBlock(visualDocument, CSS_R_C_FOOTER,
footerContent);
}
}
Element optionalFooterFacet = ComponentUtil.getFacetElement(
sourceElement, NAME_FACET_OPTIONAL_FOOTER, FACET_SEARCH_ORDER);
if (optionalFooterFacet != null) {
optionalFooter = createCustomBlock(visualDocument,
optionalFooterFacet, creationData, CSS_R_C_FOOTER_OPTIONAL);
tableHeight += DEFAULT_OPTIONAL_CELL_HEIGHT;
}
if (optionalHeader != null) {
tbody.appendChild(optionalHeader);
}
if (null != header) {
tbody.appendChild(header);
}
tbody.appendChild(calendarBody);
if (null != footer) {
tbody.appendChild(footer);
}
if (optionalFooter != null) {
tbody.appendChild(optionalFooter);
}
table.appendChild(tbody);
return table;
}
/**
*
* @param visualDocument
* @return Node of the visual tree.
*/
private nsIDOMElement createCalendarBody(nsIDOMDocument visualDocument,
VpeCreationData creationData, Element sourceElement) {
nsIDOMElement tbody = visualDocument.createElement(HTML.TAG_TBODY);
nsIDOMElement weekDaysTR = visualDocument.createElement(HTML.TAG_TR);
// Create week days row
if (showWeekDaysBar) {
Element weekDayFacet = ComponentUtil.getFacetElement(sourceElement,
NAME_FACET_WEEK_DAY, FACET_SEARCH_ORDER);
for (int i = 0; i < COLUMN; i++) {
nsIDOMElement td = visualDocument.createElement(HTML.TAG_TD);
if ((i == 0) && (showWeeksBar)) {
td.setAttribute(HTML.ATTR_CLASS, WEEK_DAY_HTML_CLASS_ATTR);
// nsIDOMElement br = visualDocument
// .createElement(HTML.TAG_BR);
// td.appendChild(br);
weekDaysTR.appendChild(td);
} else if (i > 0) {
int dayIndex = (i - 1 + firstWeekDay) % NUM_DAYS_IN_WEEK;
if ((dayIndex + 1) == Calendar.SUNDAY
|| (dayIndex + 1) == Calendar.SATURDAY) {
td.setAttribute(HTML.ATTR_CLASS,
HOL_WEEK_DAY_HTML_CLASS_ATTR);
} else {
td.setAttribute(HTML.ATTR_CLASS,
WEEK_DAY_HTML_CLASS_ATTR);
}
if (weekDayFacet != null) {
VpeChildrenInfo childrenInfo = new VpeChildrenInfo(td);
childrenInfo.addSourceChild(weekDayFacet);
creationData.addChildrenInfo(childrenInfo);
} else {
nsIDOMNode weekDayNode = visualDocument
.createTextNode(i == 0 ? Constants.EMPTY
: weekDays[dayIndex]);
td.appendChild(weekDayNode);
}
weekDaysTR.appendChild(td);
}
}
tbody.appendChild(weekDaysTR);
} // showWeekDaysBar
// Calendar body
int month = calendar.get(Calendar.MONTH);
int dayN = calendar.get(Calendar.DAY_OF_MONTH);
// shift 'cal' to month's start
calendar.add(Calendar.DAY_OF_MONTH, -dayN);
// shift 'cal' to week's start
calendar.add(Calendar.DAY_OF_MONTH, -(calendar
.get(Calendar.DAY_OF_WEEK) - calendar.getFirstDayOfWeek()));
Element weekNumberFacet = ComponentUtil.getFacetElement(sourceElement,
NAME_FACET_WEEK_NUMBER, FACET_SEARCH_ORDER);
// for number of week
for (int i = NUM_WEEK_ON_PAGE; i > 0; i--) {
nsIDOMElement tr = visualDocument.createElement(HTML.TAG_TR);
if (showWeeksBar) {
// Week in year
nsIDOMElement weekTD = visualDocument
.createElement(HTML.TAG_TD);
weekTD.setAttribute(HTML.ATTR_CLASS, CSS_R_C_WEEK);
if (weekNumberFacet != null) {
VpeChildrenInfo childrenInfo = new VpeChildrenInfo(weekTD);
childrenInfo.addSourceChild(weekNumberFacet);
creationData.addChildrenInfo(childrenInfo);
} else {
nsIDOMText weekText = visualDocument.createTextNode(String
.valueOf(calendar.get(Calendar.WEEK_OF_YEAR)));
weekTD.appendChild(weekText);
}
tr.appendChild(weekTD);
}
// for number of days in week
for (int j = NUM_DAYS_IN_WEEK; j > 0; j--) {
nsIDOMElement td = visualDocument.createElement(HTML.TAG_TD);
String currentAttr = Constants.EMPTY;
int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
// if 'cal' is a member of month
if (calendar.get(Calendar.MONTH) == month) {
// if this is current day
if (calendar.get(Calendar.DAY_OF_MONTH) == dayN
&& calendar.get(Calendar.MONTH) == month) {
currentAttr = TODAY_HTML_CLASS_ATTR;
}
// if this is holiday
else if (dayOfWeek == Calendar.SATURDAY
|| dayOfWeek == Calendar.SUNDAY) {
currentAttr = HOL_CUR_MONTH_HTML_CLASS_ATTR;
} else {
currentAttr = CUR_MONTH_HTML_CLASS_ATTR;
}
}
// if 'cal' isn't a member of month
else {
// if this is holiday
if (dayOfWeek == Calendar.SATURDAY
|| dayOfWeek == Calendar.SUNDAY) {
currentAttr = HOL_OTHER_MONTH_HTML_CLASS_ATTR;
} else {
currentAttr = OTHER_MONTH_HTML_CLASS_ATTR;
}
}
td.setAttribute(HTML.ATTR_CLASS, currentAttr);
// if (socellWidth) && attrPresents(cellHeight)) {
td.setAttribute(HTML.ATTR_STYLE, HTML.STYLE_PARAMETER_WIDTH
+ Constants.COLON + cellWidth
+ "px;" + HTML.STYLE_PARAMETER_HEIGHT //$NON-NLS-1$
+ Constants.COLON + cellHeight + "px;"); //$NON-NLS-1$
nsIDOMText text = visualDocument.createTextNode(Constants.EMPTY
+ calendar.get(Calendar.DAY_OF_MONTH));
td.appendChild(text);
tr.appendChild(td);
calendar.add(Calendar.DAY_OF_MONTH, 1);
}
tbody.appendChild(tr);
}
calendar.set(Calendar.MONTH, month);
calendar.set(Calendar.DAY_OF_MONTH, dayN);
return tbody;
}
/*
* (non-Javadoc)
*
* @see
* org.jboss.tools.vpe.editor.template.VpeAbstractTemplate#setAttribute(
* org.jboss.tools.vpe.editor.context.VpePageContext, org.w3c.dom.Element,
* org.mozilla.interfaces.nsIDOMDocument, org.mozilla.interfaces.nsIDOMNode,
* java.lang.Object, java.lang.String, java.lang.String)
*/
public void setAttribute(VpePageContext pageContext, Element sourceElement,
nsIDOMDocument visualDocument, nsIDOMNode visualNode, Object data,
String name, String value) {
super.setAttribute(pageContext, sourceElement, visualDocument,
visualNode, data, name, value);
if (name.equalsIgnoreCase(RichFaces.ATTR_VALUE)) {
String popup = sourceElement.getAttribute(RichFaces.ATTR_POPUP);
if (popup != null && popup.equalsIgnoreCase(Constants.FALSE))
return;
nsIDOMElement element = queryInterface(visualNode, nsIDOMElement.class);
nsIDOMNodeList list = element.getChildNodes();
nsIDOMNode tableNode = list.item(0);
nsIDOMElement input = queryInterface(tableNode, nsIDOMElement.class);
input.setAttribute(HTML.ATTR_VALUE, value);
}
}
/**
* Read attributes from the source element.
*
* @param sourceNode
* the source node
*/
private void readAttributes(VpePageContext pageContext, Node sourceNode) {
Element sourceElement = (Element) sourceNode;
// style
style = sourceElement.getAttribute(RichFaces.ATTR_STYLE);
// style
styleClass = sourceElement.getAttribute(RichFaces.ATTR_STYLE_CLASS);
// input must be showed if there is no "showInput" attribute or if it
// equals "true"
showInput = (!sourceElement.hasAttribute(RichFaces.ATTR_SHOW_INPUT) || Constants.TRUE
.equalsIgnoreCase(sourceElement
.getAttribute(RichFaces.ATTR_SHOW_INPUT)));
// inputStyle
inputStyle = DEFAULT_INPUT_STYLE + Constants.SEMICOLON
+ sourceElement.getAttribute(RichFaces.ATTR_INPUT_STYLE);
String inputClassAttrVal = sourceElement.hasAttribute(RichFaces.ATTR_INPUT_CLASS) ? sourceElement.getAttribute(RichFaces.ATTR_INPUT_CLASS) : null;
// inputClass
inputClass = CSS_R_C_INPUT + Constants.WHITE_SPACE + inputClassAttrVal;
// inputSize
inputSize = sourceElement.hasAttribute(RichFaces.ATTR_INPUT_SIZE) ? sourceElement
.getAttribute(RichFaces.ATTR_INPUT_SIZE)
: Constants.EMPTY;
// disabled
disabled = Constants.TRUE.equalsIgnoreCase(sourceElement
.getAttribute(RichFaces.ATTR_DISABLED));
// buttonLabel
buttonLabel = sourceElement.getAttribute(ATTR_BUTTON_LABEL);
// buttonIcon
if (disabled) {
if (sourceElement.hasAttribute(RichFaces.ATTR_BUTTON_ICON_DISABLED))
buttonIcon = ComponentUtil
.getAbsoluteWorkspacePath(
sourceElement
.getAttribute(RichFaces.ATTR_BUTTON_ICON_DISABLED),
pageContext);
else {
buttonIcon = Constants.FILE_PREFIX
+ ComponentUtil
.getAbsoluteResourcePath(DEFAULT_BUTTON_ICON_DISABLED);
}
} else {
if (sourceElement.hasAttribute(RichFaces.ATTR_BUTTON_ICON))
buttonIcon = ComponentUtil.getAbsoluteWorkspacePath(
sourceElement.getAttribute(RichFaces.ATTR_BUTTON_ICON),
pageContext);
else {
buttonIcon = Constants.FILE_PREFIX
+ ComponentUtil
.getAbsoluteResourcePath(DEFAULT_BUTTON_ICON);
}
}
buttonIcon = buttonIcon.replace('\\', '/');
// buttonClass
buttonClass = sourceElement.hasAttribute(RichFaces.ATTR_BUTTON_CLASS) ? sourceElement.getAttribute(RichFaces.ATTR_BUTTON_CLASS) : null;
// showWeekDaysBar
showWeekDaysBar = (!sourceElement
.hasAttribute(ATTR_SHOW_SHOW_WEEKS_DAY_BAR) || Constants.TRUE
.equalsIgnoreCase(sourceElement
.getAttribute(ATTR_SHOW_SHOW_WEEKS_DAY_BAR)));
// showWeeksBar
showWeeksBar = (!sourceElement.hasAttribute(ATTR_SHOW_WEEKS_BAR) || Constants.TRUE
.equalsIgnoreCase(sourceElement
.getAttribute(ATTR_SHOW_WEEKS_BAR)));
// showHeader
showHeader = (!sourceElement.hasAttribute(ATTR_SHOW_HEADER) || Constants.TRUE
.equalsIgnoreCase(sourceElement.getAttribute(ATTR_SHOW_HEADER)));
// showApplyButton
showApplyButton = Constants.TRUE.equalsIgnoreCase(sourceElement
.getAttribute(ATTR_SHOW_APPLY_BUTTON));
showTodayControl = !HIDDEN.equalsIgnoreCase(sourceElement
.getAttribute(ATTR_TODAY_CONTROL_MODE));
// showFooter
showFooter = (!sourceElement.hasAttribute(ATTR_SHOW_FOOTER) || Constants.TRUE
.equalsIgnoreCase(sourceElement.getAttribute(ATTR_SHOW_FOOTER)))
&& (showApplyButton || showTodayControl);
// popup
popup = (!sourceElement.hasAttribute(RichFaces.ATTR_POPUP) || Constants.TRUE
.equalsIgnoreCase(sourceElement
.getAttribute(RichFaces.ATTR_POPUP)));
// value
value = sourceElement.hasAttribute(RichFaces.ATTR_VALUE) ? sourceElement
.getAttribute(RichFaces.ATTR_VALUE)
: Constants.EMPTY;
// locale
locale = getLocale(sourceElement);
// calendar
calendar = Calendar.getInstance(locale);
// weekDays
weekDays = getWeekDays(sourceElement, locale);
// months
months = getMonths(sourceElement, locale);
// firstWeekDay
firstWeekDay = getFirstWeekDay(sourceElement, ATTR_FIRST_WEEK_DAY,
calendar.getFirstDayOfWeek() - 1);
calendar.setFirstDayOfWeek(firstWeekDay + 1);
// currentDayControl
currentMonthControl = months[calendar.get(Calendar.MONTH)]
+ Constants.COMMA + Constants.WHITE_SPACE
+ calendar.get(Calendar.YEAR);
// currentDayControl
SimpleDateFormat sdf = new SimpleDateFormat(DEFAULT_DATE_PATTERN);
if (sourceElement.hasAttribute(ATTR_DATE_PATTERN)) {
datePattern = sourceElement.getAttribute(ATTR_DATE_PATTERN);
try {
sdf.applyPattern(datePattern);
} catch (IllegalArgumentException e) {
// DEFAULT_DATE_PATTERN is used in this case
}
}
// currentDayControl
currentDayControl = sdf.format(calendar.getTime());
// cellWidth
cellWidth = ComponentUtil.parseSizeAttribute(sourceElement,
ATTR_CELL_WIDTH, DEFAULT_CELL_WIDTH);
// cellHeight
cellHeight = ComponentUtil.parseSizeAttribute(sourceElement,
ATTR_CELL_HEIGHT, DEFAULT_CELL_HEIGHT);
// tableWidth
tableWidth = (showWeeksBar ? DEFAULT_CELL_WIDTH : 0) + cellWidth
* NUM_DAYS_IN_WEEK;
// tableHeight
tableHeight = (showHeader ? DEFAULT_CELL_HEIGHT : 0)
+ (showFooter ? DEFAULT_CELL_HEIGHT : 0)
+ (showWeekDaysBar ? DEFAULT_CELL_HEIGHT : 0) + cellHeight
* NUM_WEEK_ON_PAGE;
// jointPoint
jointPoint = getDirection(sourceElement, RichFaces.ATTR_JOINT_POINT,
DIRECTIONS_BOTTOM_LEFT);
// direction
direction = getDirection(sourceElement, RichFaces.ATTR_DIRECTION,
DIRECTIONS_BOTTOM_RIGHT);
// zindex
zindex = ComponentUtil.parseNumberAttribute(sourceElement,
RichFaces.ATTR_ZINDEX, 3);
// horizontalOffset
horizontalOffset = ComponentUtil.parseNumberAttribute(sourceElement,
RichFaces.ATTR_HORIZONTAL_OFFSET, 0);
// verticalOffset
verticalOffset = ComponentUtil.parseNumberAttribute(sourceElement,
RichFaces.ATTR_VERTICAL_OFFSET, 0);
}
public void stopToggling(Node sourceNode) {
}
public void toggle(VpeVisualDomBuilder builder, Node sourceNode,
String toggleId) {
if (isExpanded(sourceNode)) {
expandedCalendars.remove(sourceNode);
} else {
expandedCalendars.put(sourceNode, null);
}
}
private boolean isExpanded(Node sourceNode) {
return expandedCalendars.containsKey(sourceNode);
}
/**
* @param visualDocument
* @param sourceElement
* @param creationData
* @return
*/
private nsIDOMElement createPopupCalendar(nsIDOMDocument visualDocument,
Element sourceElement, VpeCreationData creationData) {
nsIDOMElement popupCalendar = visualDocument
.createElement(HTML.TAG_SPAN);
if (showInput) {
nsIDOMElement input = visualDocument.createElement(HTML.TAG_INPUT);
input.setAttribute(HTML.ATTR_TYPE, HTML.VALUE_TYPE_TEXT);
input.setAttribute(HTML.ATTR_STYLE, inputStyle);
input.setAttribute(HTML.ATTR_CLASS, inputClass);
input.setAttribute(HTML.ATTR_SIZE, inputSize);
input.setAttribute(HTML.ATTR_VALUE, value);
popupCalendar.appendChild(input);
VpeElementData elementData = new VpeElementData();
if (sourceElement.hasAttribute(RichFaces.ATTR_VALUE)) {
Attr attr = sourceElement
.getAttributeNode(RichFaces.ATTR_VALUE);
elementData.addNodeData(new AttributeData(attr, input, true));
} else {
elementData.addNodeData(new AttributeData(RichFaces.ATTR_VALUE,
input, true));
}
creationData.setElementData(elementData);
}
nsIDOMElement button;
if ((buttonLabel == null) || (buttonLabel.length() == 0)) {
button = visualDocument.createElement(HTML.TAG_IMG);
button.setAttribute(HTML.ATTR_SRC, buttonIcon);
} else {
button = visualDocument.createElement(HTML.TAG_BUTTON);
button.setAttribute(HTML.ATTR_TYPE, HTML.VALUE_TYPE_BUTTON);
nsIDOMNode buttonText = visualDocument.createTextNode(buttonLabel);
button.appendChild(buttonText);
}
button.setAttribute(HTML.ATTR_STYLE, DEFAULT_BUTTON_STYLE);
button.setAttribute(HTML.ATTR_CLASS, CSS_R_C_BUTTON
+ Constants.WHITE_SPACE + buttonClass);
button.setAttribute(VpeVisualDomBuilder.VPE_USER_TOGGLE_ID,
Constants.TRUE);
popupCalendar.appendChild(button);
if (isExpanded(sourceElement)) {
nsIDOMElement wrapper = visualDocument
.createElement(HTML.ATTR_SPAN);
wrapper.setAttribute(HTML.ATTR_STYLE, POSITION_RELATIVE_STYLE);
nsIDOMElement calendar = createCalendar(visualDocument,
creationData, sourceElement);
int top = (jointPoint.isTop() ? JOINT_POINT_TOP
: JOINT_POINT_BOTTOM)
+ ((direction.isTop() ? -1 : 1) * ((direction.isTop() ? tableHeight
: 0) + verticalOffset));
int left = (direction.isLeft() ? -1 : 1)
* ((direction.isLeft() ? tableWidth : 0) + horizontalOffset);
calendar.setAttribute(HTML.ATTR_STYLE, POSITION_ABSOLUTE_STYLE
+ HTML.STYLE_PARAMETER_ZINDEX + Constants.COLON + zindex
+ Constants.SEMICOLON + HTML.STYLE_PARAMETER_TOP
+ Constants.COLON + top + Constants.PIXEL
+ Constants.SEMICOLON + HTML.STYLE_PARAMETER_LEFT
+ Constants.COLON + left + Constants.PIXEL
+ Constants.SEMICOLON + HTML.STYLE_PARAMETER_WIDTH
+ Constants.COLON + tableWidth + Constants.PIXEL
+ Constants.SEMICOLON
+ calendar.getAttribute(HTML.ATTR_STYLE));
wrapper.appendChild(calendar);
if (jointPoint.isLeft()) {
popupCalendar.insertBefore(wrapper, popupCalendar
.getFirstChild());
} else {
popupCalendar.appendChild(wrapper);
}
}
return popupCalendar;
}
@Override
public void setPseudoContent(VpePageContext pageContext,
Node sourceContainer, nsIDOMNode visualContainer,
nsIDOMDocument visualDocument) {
}
/**
*
* @param sourceElement
* @return
*/
private Locale getLocale(Element sourceElement) {
Locale locale;
if (sourceElement.hasAttribute(RichFaces.ATTR_LOCALE)) {
String localeAttr = sourceElement
.getAttribute(RichFaces.ATTR_LOCALE);
String[] localeInformation = localeAttr.split(Constants.UNDERSCORE);
String language = localeInformation[0];
String country = localeInformation.length > 1 ? localeInformation[1]
: Constants.EMPTY;
locale = new Locale(language, country);
} else {
locale = Locale.getDefault();
}
return locale;
}
/**
* @param sourceElement
* @param attributeName
* @param defaultValue
* @return
*/
private int getFirstWeekDay(Element sourceElement, String attributeName,
int defaultValue) {
// if source element has attribute
if (sourceElement.hasAttribute(attributeName)) {
// getAttribute
String stringValue = sourceElement.getAttribute(attributeName);
try {
// decode attribute's value
int intValue = Integer.decode(stringValue);
// richfaces Calendar counts weekdays from 0 but
// java.util.Calendar counts weekdays from 1
return intValue < 0 ? NUM_DAYS_IN_WEEK + intValue
% NUM_DAYS_IN_WEEK : intValue % NUM_DAYS_IN_WEEK;
} catch (NumberFormatException e) {
// if attribute's value is not number do nothing and then return
// default value
}
}
return defaultValue;
}
/**
* @param sourceElement
* @param locale
* @return
*/
private String[] getWeekDays(Element sourceElement, Locale locale) {
String[] days = new String[NUM_DAYS_IN_WEEK];
if (sourceElement.hasAttribute(ATTR_WEEK_DAY_LABELS_SHORT)) {
String attrValue = sourceElement
.getAttribute(ATTR_WEEK_DAY_LABELS_SHORT);
String[] parsedDays = attrValue.split(Constants.COMMA);
System.arraycopy(parsedDays, 0, days, 0, parsedDays.length);
if (parsedDays.length < NUM_DAYS_IN_WEEK) {
Arrays.fill(days, parsedDays.length, days.length - 1,
Constants.EMPTY);
}
} else {
DateFormatSymbols formatSymbols = new DateFormatSymbols(locale);
System.arraycopy(formatSymbols.getShortWeekdays(), 1, days, 0,
NUM_DAYS_IN_WEEK);
}
return days;
}
/**
* @param locale
* @return
*/
private String[] getMonths(Element sourceElement, Locale locale) {
String[] months;
if (sourceElement.hasAttribute(ATTR_MONTH_LABELS)) {
months = new String[NUM_MONTHS];
String attrValue = sourceElement.getAttribute(ATTR_MONTH_LABELS);
String[] parsedMonths = attrValue.split(Constants.COMMA);
System.arraycopy(parsedMonths, 0, months, 0, parsedMonths.length);
if (parsedMonths.length < NUM_MONTHS) {
Arrays.fill(months, parsedMonths.length, months.length - 1,
UNDEFINED);
}
} else {
DateFormatSymbols formatSymbols = new DateFormatSymbols(locale);
months = formatSymbols.getMonths();
}
return months;
}
/**
*
* @param visualDocument
* @param customChild
* @param creationData
* @param blockClass
* @param content
* @return
*/
private nsIDOMElement createCustomBlock(nsIDOMDocument visualDocument,
Node customChild, VpeCreationData creationData, String blockClass) {
nsIDOMElement blockTr = visualDocument.createElement(HTML.TAG_TR);
nsIDOMElement blockTd = visualDocument.createElement(HTML.TAG_TD);
blockTd.setAttribute(HTML.ATTR_COLSPAN, String.valueOf(COLUMN));
blockTd.setAttribute(HTML.ATTR_CLASS, blockClass);
blockTr.appendChild(blockTd);
VpeChildrenInfo childrenInfo = new VpeChildrenInfo(blockTd);
childrenInfo.addSourceChild(customChild);
creationData.addChildrenInfo(childrenInfo);
return blockTr;
}
/**
*
* @param visualDocument
* @param style
* @param arrayContent
* @param arrayContentStyles
* @return
*/
private nsIDOMElement createHeaderBlock(nsIDOMDocument visualDocument,
String blockClass, List<Cell> content) {
nsIDOMElement blockTr = visualDocument.createElement(HTML.TAG_TR);
nsIDOMElement blockTd = visualDocument.createElement(HTML.TAG_TD);
blockTd.setAttribute(HTML.ATTR_COLSPAN, String.valueOf(COLUMN));
blockTd.setAttribute(HTML.ATTR_CLASS, blockClass);
nsIDOMElement blockTable = visualDocument.createElement(HTML.TAG_TABLE);
blockTable.setAttribute(HTML.ATTR_CELLPADDING, "0"); //$NON-NLS-1$
blockTable.setAttribute(HTML.ATTR_CELLSPACING, "0"); //$NON-NLS-1$
blockTable.setAttribute(HTML.ATTR_BORDER, "0"); //$NON-NLS-1$
blockTable.setAttribute(HTML.ATTR_WIDTH, FILL_WIDTH);
nsIDOMElement tbody = visualDocument.createElement(HTML.TAG_TBODY);
nsIDOMElement tr = visualDocument.createElement(HTML.TAG_TR);
for (Cell cell : content) {
nsIDOMElement td = visualDocument.createElement(HTML.TAG_TD);
td.setAttribute(HTML.ATTR_CLASS, cell.getCellClass());
nsIDOMElement div = visualDocument.createElement(HTML.TAG_DIV);
div.setAttribute(HTML.ATTR_CLASS, CSS_R_C_TOOL_BTN);
nsIDOMText text1 = visualDocument
.createTextNode(cell.getCellText());
div.appendChild(text1);
if (cell.isToggle()) {
div.setAttribute(VpeVisualDomBuilder.VPE_USER_TOGGLE_ID,
Constants.TRUE);
}
if (cell.isSeparate()) {
td.setAttribute(HTML.ATTR_STYLE, ComponentUtil
.getBackgoundImgStyle(SPARATOR_IMG));
}
td.appendChild(div);
tr.appendChild(td);
}
tbody.appendChild(tr);
blockTable.appendChild(tbody);
blockTd.appendChild(blockTable);
blockTr.appendChild(blockTd);
return blockTr;
}
/**
*
* @param visualDocument
* @param style
* @param arrayContent
* @param arrayContentStyles
* @return
*/
private nsIDOMElement createFooterBlock(nsIDOMDocument visualDocument,
String blockClass, List<Cell> content) {
nsIDOMElement blockTr = visualDocument.createElement(HTML.TAG_TR);
nsIDOMElement blockTd = visualDocument.createElement(HTML.TAG_TD);
blockTd.setAttribute(HTML.ATTR_COLSPAN, String.valueOf(COLUMN));
blockTd.setAttribute(HTML.ATTR_CLASS, blockClass);
nsIDOMElement blockTable = visualDocument.createElement(HTML.TAG_TABLE);
blockTable.setAttribute(HTML.ATTR_CELLPADDING, "0"); //$NON-NLS-1$
blockTable.setAttribute(HTML.ATTR_CELLSPACING, "0"); //$NON-NLS-1$
blockTable.setAttribute(HTML.ATTR_BORDER, "0"); //$NON-NLS-1$
blockTable.setAttribute(HTML.ATTR_WIDTH, FILL_WIDTH);
nsIDOMElement tbody = visualDocument.createElement(HTML.TAG_TBODY);
nsIDOMElement tr = visualDocument.createElement(HTML.TAG_TR);
nsIDOMElement fillingTd = visualDocument.createElement(HTML.TAG_TD);
fillingTd.setAttribute(HTML.ATTR_WIDTH, FILL_WIDTH);
tr.appendChild(fillingTd);
for (Cell cell : content) {
nsIDOMElement td = visualDocument.createElement(HTML.TAG_TD);
td.setAttribute(HTML.ATTR_CLASS, cell.getCellClass());
nsIDOMElement div = visualDocument.createElement(HTML.TAG_DIV);
div.setAttribute(HTML.ATTR_CLASS, CSS_R_C_TOOL_BTN);
nsIDOMText text = visualDocument.createTextNode(cell.getCellText());
if (cell.isToggle()) {
div.setAttribute(VpeVisualDomBuilder.VPE_USER_TOGGLE_ID,
Constants.TRUE);
}
if (cell.isSeparate()) {
td.setAttribute(HTML.ATTR_STYLE, ComponentUtil
.getBackgoundImgStyle(SPARATOR_IMG));
}
div.appendChild(text);
td.appendChild(div);
tr.appendChild(td);
}
tbody.appendChild(tr);
blockTable.appendChild(tbody);
blockTd.appendChild(blockTable);
blockTr.appendChild(blockTd);
return blockTr;
}
private DirectionData getDirection(Element sourceElement,
String attributeName, String defaultDirection) {
String value = defaultDirection;
DirectionData directionData = new DirectionData();
if (sourceElement.hasAttribute(attributeName)) {
String attributeValue = sourceElement.getAttribute(attributeName)
.toLowerCase();
Matcher matcher = Pattern.compile(DIRECTION_PATTERN).matcher(value);
if (matcher.find()) {
value = attributeValue;
}
}
directionData.setTop(value.startsWith(TOP));
directionData.setLeft(value.endsWith(LEFT));
return directionData;
}
class DirectionData {
private boolean top;
private boolean left;
public boolean isTop() {
return top;
}
public void setTop(boolean top) {
this.top = top;
}
public boolean isLeft() {
return left;
}
public void setLeft(boolean left) {
this.left = left;
}
}
class Cell {
private String cellText;
private String cellClass;
private boolean separate;
private boolean toggle;
public boolean isToggle() {
return toggle;
}
public void setToggle(boolean toggle) {
this.toggle = toggle;
}
public Cell(String cellText, String cellClass) {
this.cellText = cellText;
this.cellClass = cellClass;
this.separate = false;
this.toggle = false;
}
public Cell(String cellText, String cellClass, boolean separate) {
this.cellText = cellText;
this.cellClass = cellClass;
this.separate = separate;
this.toggle = false;
}
public Cell(String cellText, String cellClass, boolean separate,
boolean toggle) {
this.cellText = cellText;
this.cellClass = cellClass;
this.separate = separate;
this.toggle = toggle;
}
public String getCellText() {
return cellText;
}
public void setCellText(String cellText) {
this.cellText = cellText;
}
public String getCellClass() {
return cellClass;
}
public void setCellClass(String cellClass) {
this.cellClass = cellClass;
}
public boolean isSeparate() {
return separate;
}
public void setSeparate(boolean separate) {
this.separate = separate;
}
}
}