/******************************************************************************* * 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; } } }