/******************************************************************************* * Copyright (c) 2007 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: * 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.HashMap; import java.util.Map; import java.util.Set; import org.jboss.tools.jsf.vpe.richfaces.ComponentUtil; import org.jboss.tools.vpe.editor.context.VpePageContext; import org.jboss.tools.vpe.editor.mapping.AttributeData; import org.jboss.tools.vpe.editor.mapping.NodeData; import org.jboss.tools.vpe.editor.mapping.VpeElementData; import org.jboss.tools.vpe.editor.template.VpeCreationData; import org.jboss.tools.vpe.editor.util.Constants; import org.jboss.tools.vpe.editor.util.HTML; import org.jboss.tools.vpe.editor.util.VisualDomUtil; import org.mozilla.interfaces.nsIDOMDocument; import org.mozilla.interfaces.nsIDOMElement; import org.mozilla.interfaces.nsIDOMHTMLInputElement; import org.mozilla.interfaces.nsIDOMText; import org.w3c.dom.Element; import org.w3c.dom.Node; /** * Template for input number slider control * * @author Sergey Dzmitrovich */ public class InputNumberSliderTemplate extends AbstractEditableRichFacesTemplate { /** path to file which contains css styles for component */ private static final String STYLE_PATH = "/inputNumberSlider/numberSlider.css"; //$NON-NLS-1$ /** path to bar image */ private static final String SPACER_IMAGE_PATH = "/inputNumberSlider/spacer.gif"; //$NON-NLS-1$ /** "showInput" attribute */ private static final String SHOW_INPUT_ATTR = "showInput"; //$NON-NLS-1$ /** "showBoundaryValues" attribute */ private static final String SHOW_BOUNDARY_VALUES = "showBoundaryValues"; //$NON-NLS-1$ /** "inputPosition" attribute */ private static final String INPUT_POSITION_ATTR = "inputPosition"; //$NON-NLS-1$ /** "minValue" attribute */ private static final String MIN_VALUE_ATTR = "minValue"; //$NON-NLS-1$ /** "maxValue" attribute */ private static final String MAX_VALUE_ATTR = "maxValue"; //$NON-NLS-1$ /** "barStyle" attribute */ private static final String BAR_STYLE_ATTR = "barStyle"; //$NON-NLS-1$ /** default min value */ private static final String MIN_VALUE_DEFAULT = "0"; //$NON-NLS-1$ /** default max value */ private static final String MAX_VALUE_DEFAULT = "100"; //$NON-NLS-1$ /** default input size */ private static final String INPUT_SIZE_DEFAULT = "3"; //$NON-NLS-1$ /** default slider width */ private static final String SLYDER_WIDTH_DEFAULT = "200"; //$NON-NLS-1$ /** default input field block style */ private static final String INPUT_FIELD_STYLE = "text-align: left; vertical-align: bottom;"; //$NON-NLS-1$ /** spacer image style */ private static final String SPACER_IMAGE_STYLE = "display: block;"; //$NON-NLS-1$ /** HANDLER_WRAPPER_STYLE */ private static final String HANDLER_WRAPPER_STYLE = "position: relative;"; //$NON-NLS-1$ /** HANDLER_STYLE */ private static final String HANDLER_STYLE = "visibility: visible;"; //$NON-NLS-1$ /** * Contains default CSS styles for different elements which can define using attributes * key + "Class" = name of some element's style attribute */ private static final Map<String, String> defaultStyleClasses; static { defaultStyleClasses = new HashMap<String, String>(); // general style defaultStyleClasses.put("style", "dr-insldr rich-slider"); //$NON-NLS-1$//$NON-NLS-2$ // input style defaultStyleClasses.put("input", "rich-inslider-field"); //$NON-NLS-1$//$NON-NLS-2$ // bar style defaultStyleClasses.put("bar", "dr-insldr-track rich-inslider-track"); //$NON-NLS-1$//$NON-NLS-2$ // bar style defaultStyleClasses.put("handle", "dr-insldr-handler rich-inslider-handler"); //$NON-NLS-1$//$NON-NLS-2$ } /* Default and RichFaces styles */ /** min value style classes */ private static final String MIN_VALUE_STYLE_CLASSES = "dr-insldr-left-num rich-inslider-left-num"; //$NON-NLS-1$ /** max value style classes */ private static final String MAX_VALUE_STYLE_CLASSES = "dr-insldr-right-num rich-inslider-right-num"; //$NON-NLS-1$ /** input left style classes */ private static final String INPUT_LEFT_STYLE_CLASSES = "dr-insldr-field dr-insldr-field-left"; //$NON-NLS-1$ /** input right style classes */ private static final String INPUT_RIGHT_STYLE_CLASSES = "dr-insldr-field dr-insldr-field-right"; //$NON-NLS-1$ /** slider style classes */ private static final String SLIDER_STYLE_CLASSES = "dr-insldr-size dr-insldr-vert-spacer"; //$NON-NLS-1$ /** track decor style classes */ private static final String TRACK_DECOR_1_CLASSES = "dr-insldr-track-decor-1"; //$NON-NLS-1$ /** slider style classes */ private static final String TRACK_DECOR_2_CLASSES = "dr-insldr-track-decor-2"; //$NON-NLS-1$ /** contains prepare css styles (added user css classes besides default styles) */ private static final Map<String, String> styleClasses = new HashMap<String, String>(); /** * 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) { // Set a css for this element ComponentUtil.setCSSLink(pageContext, STYLE_PATH, "inputNumberSlider"); //$NON-NLS-1$ // cast to Element Element sourceElement = (Element) sourceNode; // prepare style classes for input number slider part controls prepareData(sourceElement); // create and initialize basic table element nsIDOMElement basicTable = visualDocument.createElement(HTML.TAG_TABLE); String style = new StringBuilder(HTML.STYLE_PARAMETER_WIDTH + Constants.COLON). append(getNumberValue(sourceElement, RichFaces.ATTR_WIDTH, SLYDER_WIDTH_DEFAULT)). append(Constants.PIXEL + Constants.SEMICOLON). append(getAttribute(sourceElement, RichFaces.ATTR_STYLE)).append(Constants.SEMICOLON).toString(); basicTable.setAttribute(HTML.ATTR_STYLE, style); basicTable.setAttribute(HTML.ATTR_CLASS, styleClasses.get("style")); //$NON-NLS-1$ basicTable.setAttribute(HTML.ATTR_CELLPADDING, MIN_VALUE_DEFAULT); basicTable.setAttribute(HTML.ATTR_CELLSPACING, MIN_VALUE_DEFAULT); basicTable.setAttribute(HTML.ATTR_BORDER, MIN_VALUE_DEFAULT); VpeElementData elementData = new VpeElementData(); // create block with min/max and input components nsIDOMElement valuesBlock = createValuesBlock(sourceElement, visualDocument, elementData); // create slider component nsIDOMElement sliderBlock = createSliderBlock(sourceElement, visualDocument); basicTable.appendChild(valuesBlock); basicTable.appendChild(sliderBlock); /* * https://jira.jboss.org/jira/browse/JBIDE-3225 * Component should render its children. */ VpeCreationData creationData = VisualDomUtil.createTemplateWithTextContainer( sourceElement, basicTable, HTML.TAG_DIV, visualDocument); creationData.setElementData(elementData); return creationData; } /** * Prepare style classes. * * @param sourceElement Element source object */ private void prepareData(Element sourceElement) { // prepare style classes Set<String> styleClassesKeys = defaultStyleClasses.keySet(); styleClasses.clear(); for (String key : styleClassesKeys) { if (sourceElement.hasAttribute(key + "Class")) { //$NON-NLS-1$ styleClasses.put(key, defaultStyleClasses.get(key) + Constants.WHITE_SPACE + sourceElement.getAttribute(key + "Class")); //$NON-NLS-1$ } else { styleClasses.put(key, defaultStyleClasses.get(key)); } } } /** * Create value block container with min, max, input components. * * @param sourceElement The current node of the source tree. * @param visualDocument The document of the visual tree. * @param elementData the VpeElementData object * @return nsIDOMElement object */ private nsIDOMElement createValuesBlock(Element sourceElement, nsIDOMDocument visualDocument, VpeElementData elementData) { // create numbers block nsIDOMElement valuesBlock = visualDocument.createElement(HTML.TAG_TR); // create minValue block nsIDOMElement minValueTD = visualDocument.createElement(HTML.TAG_TD); minValueTD.setAttribute(HTML.ATTR_CLASS, MIN_VALUE_STYLE_CLASSES); // create maxValue block nsIDOMElement maxValueTD = visualDocument.createElement(HTML.TAG_TD); maxValueTD.setAttribute(HTML.ATTR_CLASS, MAX_VALUE_STYLE_CLASSES); // checks if min/max values should be shown on component if (isShowBoundaryValues(sourceElement)) { NodeData minValueData = null; // create minValue text nsIDOMText minValueText = visualDocument.createTextNode(getNumberValue(sourceElement, MIN_VALUE_ATTR, MIN_VALUE_DEFAULT)); if (sourceElement.hasAttribute(MIN_VALUE_ATTR)) { minValueData = new NodeData(sourceElement.getAttributeNode(MIN_VALUE_ATTR), minValueText); } else { minValueData = new AttributeData(MIN_VALUE_ATTR, minValueText); } // add text to TD minValueTD.appendChild(minValueText); elementData.addNodeData(minValueData); NodeData maxValueData; // create maxValue text nsIDOMText maxValueText = visualDocument.createTextNode(getNumberValue(sourceElement, MAX_VALUE_ATTR, MAX_VALUE_DEFAULT)); if (sourceElement.hasAttribute(MAX_VALUE_ATTR)) { maxValueData = new NodeData(sourceElement.getAttributeNode(MAX_VALUE_ATTR), maxValueText); } else { maxValueData = new AttributeData(MAX_VALUE_ATTR, maxValueText); } // add text to tD maxValueTD.appendChild(maxValueText); elementData.addNodeData(maxValueData); } valuesBlock.appendChild(minValueTD); valuesBlock.appendChild(maxValueTD); // checks if input field should be shown on component if (isShowInput(sourceElement)) { nsIDOMElement inputTd = createInputBlock(sourceElement, visualDocument, elementData); // the location of input field (left/right) if (isRightInputPosition(sourceElement)) { valuesBlock.appendChild(inputTd); } else { valuesBlock.insertBefore(inputTd, minValueTD); } } return valuesBlock; } /** * Create input block container with input component. * * @param sourceElement The current node of the source tree. * @param visualDocument The document of the visual tree. * @param elementData the VpeElementData object * @return nsIDOMElement object */ private nsIDOMElement createInputBlock(Element sourceElement, nsIDOMDocument visualDocument, VpeElementData elementData) { // create input block nsIDOMElement inputTD = visualDocument.createElement(HTML.TAG_TD); inputTD.setAttribute(HTML.ATTR_STYLE, INPUT_FIELD_STYLE); inputTD.setAttribute(HTML.ATTR_ROWSPAN, "2"); //$NON-NLS-1$ // create input field nsIDOMElement inputField = visualDocument.createElement(HTML.TAG_INPUT); inputField.setAttribute(HTML.ATTR_TYPE, HTML.VALUE_TYPE_TEXT); inputField.setAttribute(HTML.ATTR_SIZE, getNumberValue(sourceElement, RichFaces.ATTR_INPUT_SIZE, INPUT_SIZE_DEFAULT)); inputField.setAttribute(HTML.ATTR_STYLE, getAttribute(sourceElement, RichFaces.ATTR_INPUT_STYLE)); NodeData attributeData = null; inputField.setAttribute(HTML.ATTR_VALUE, ComponentUtil.getAttribute(sourceElement, RichFaces.ATTR_VALUE)); if (sourceElement.hasAttribute(RichFaces.ATTR_VALUE)) { attributeData = new NodeData(sourceElement.getAttributeNode(RichFaces.ATTR_VALUE), inputField); } else { attributeData = new AttributeData(RichFaces.ATTR_VALUE, inputField); } elementData.addNodeData(attributeData); // get input class attribute String inputClass = null; if (isRightInputPosition(sourceElement)) { inputClass = INPUT_RIGHT_STYLE_CLASSES; } else { inputClass = INPUT_LEFT_STYLE_CLASSES; } inputClass = new StringBuilder(inputClass).append(Constants.WHITE_SPACE). append(styleClasses.get("input")).toString(); //$NON-NLS-1$ inputField.setAttribute(HTML.ATTR_CLASS, inputClass); nsIDOMHTMLInputElement iDOMInputElement = queryInterface(inputField, nsIDOMHTMLInputElement.class); iDOMInputElement.setReadOnly(false); inputTD.appendChild(inputField); return inputTD; } /** * Create slider block container with corresponding components. * * @param sourceElement The current node of the source tree. * @param visualDocument The document of the visual tree. * @return nsIDOMElement object */ private nsIDOMElement createSliderBlock(Element sourceElement, nsIDOMDocument visualDocument) { // create slider block - TR tag nsIDOMElement sliderBlock = visualDocument.createElement(HTML.TAG_TR); // create TD nsIDOMElement sliderTD = visualDocument.createElement(HTML.TAG_TD); sliderTD.setAttribute(HTML.ATTR_CLASS, SLIDER_STYLE_CLASSES); sliderTD.setAttribute(HTML.ATTR_COLSPAN, "2"); //$NON-NLS-1$ // create wrapper DIV component for slider element nsIDOMElement handlerWrapper = visualDocument.createElement(HTML.TAG_DIV); handlerWrapper.setAttribute(HTML.ATTR_STYLE, HANDLER_WRAPPER_STYLE); nsIDOMElement handler = visualDocument.createElement(HTML.TAG_DIV); handler.setAttribute(HTML.ATTR_STYLE, HANDLER_STYLE); handler.setAttribute(HTML.ATTR_CLASS, styleClasses.get("handle")); //$NON-NLS-1$ handlerWrapper.appendChild(handler); // create bar DIV tag nsIDOMElement barDiv = visualDocument.createElement(HTML.TAG_DIV); barDiv.setAttribute(HTML.TAG_STYLE, ComponentUtil.getAttribute(sourceElement, BAR_STYLE_ATTR)); barDiv.setAttribute(HTML.ATTR_CLASS, styleClasses.get("bar")); //$NON-NLS-1$ // create table nsIDOMElement barTable = visualDocument.createElement(HTML.TAG_TABLE); barTable.setAttribute(HTML.ATTR_CLASS, TRACK_DECOR_1_CLASSES); barTable.setAttribute(HTML.ATTR_CELLPADDING, MIN_VALUE_DEFAULT); barTable.setAttribute(HTML.ATTR_CELLSPACING, MIN_VALUE_DEFAULT); // create TR nsIDOMElement barTR = visualDocument.createElement(HTML.TAG_TR); // create TD nsIDOMElement barTD = visualDocument.createElement(HTML.TAG_TD); barTD.setAttribute(HTML.ATTR_CLASS, TRACK_DECOR_2_CLASSES); // create image nsIDOMElement barImage = visualDocument.createElement(HTML.TAG_IMG); ComponentUtil.setImg(barImage, SPACER_IMAGE_PATH); barImage.setAttribute(HTML.ATTR_STYLE, SPACER_IMAGE_STYLE); // insert image to TD barTD.appendChild(barImage); // insert TD to TR barTR.appendChild(barTD); // insert TR to table barTable.appendChild(barTR); // insert table to bar barDiv.appendChild(barTable); sliderTD.appendChild(handlerWrapper); sliderTD.appendChild(barDiv); sliderBlock.appendChild(sliderTD); return sliderBlock; } /** * Method is used retrieve attribute value from sourceElement for corresponding attributeName. * If sourceElement doesn't contain attribute with name equals attributeName return default value. * * @param sourceElement DOM Element * @param attributeName the name of attribute * @param defaultValue the default value * @return the value of attribute with corresponding name for source element */ private String getNumberValue(Element sourceElement, String attributeName, String defaultValue) { // if source element has attribute if (sourceElement.hasAttribute(attributeName)) { String stringValue = sourceElement.getAttribute(attributeName); try { // decode attribute's value Integer.decode(stringValue); // if it is number (there is not exception) return attribute's value return stringValue; } catch (NumberFormatException e) { // if attribute's value is not number do nothing and then return default value } } return defaultValue; } /** * If input field must be represented. In this case return true, false - otherwise. * * @param sourceElement DOM source Element object * @return true if input field must be represented, false - otherwise */ private boolean isShowInput(Element sourceElement) { // if source element has "showInput" attribute if (sourceElement.hasAttribute(SHOW_INPUT_ATTR)) { String showInput = sourceElement.getAttribute(SHOW_INPUT_ATTR); // if this attribute equals "true" if (Constants.TRUE.equalsIgnoreCase(showInput)) { return true; } // in other cases return false return false; } // default value is true return true; } /** * Return true if input position is right. Return false if input position is left. * * @param sourceElement DOM source Element object * @return false if input position is "left", true - otherwise */ private boolean isRightInputPosition(Element sourceElement) { if (sourceElement.hasAttribute(INPUT_POSITION_ATTR) && ("left".equalsIgnoreCase(sourceElement.getAttribute(INPUT_POSITION_ATTR)))) { //$NON-NLS-1$ return false; } return true; } /** * Method checks if the min/max values are shown on the right/left borders of a control. * * @param sourceElement DOM source Element object * @return true if min/max value must be shown, false - otherwise */ private boolean isShowBoundaryValues(Element sourceElement) { if ((sourceElement.hasAttribute(SHOW_BOUNDARY_VALUES) && Constants.FALSE.equalsIgnoreCase(sourceElement.getAttribute(SHOW_BOUNDARY_VALUES)))) { return false; } return true; } }