private void handleItemCompact( ContentHandler contentHandler, String optionQName, XFormsValueControl xformsControl, boolean isMultiple, Item item) throws SAXException { final String itemClasses = getItemClasses(item, null); final AttributesImpl optionAttributes = getAttributes(XMLUtils.EMPTY_ATTRIBUTES, itemClasses, null); // Add item attributes to option addItemAttributes(item, optionAttributes); optionAttributes.addAttribute( "", "value", "value", ContentHandlerHelper.CDATA, item.getExternalValue(pipelineContext)); // Figure out whether what items are selected boolean isSelected = isSelected(pipelineContext, handlerContext, xformsControl, isMultiple, item); if (isSelected) optionAttributes.addAttribute( "", "selected", "selected", ContentHandlerHelper.CDATA, "selected"); // xhtml:option contentHandler.startElement( XMLConstants.XHTML_NAMESPACE_URI, "option", optionQName, optionAttributes); final String label = item.getLabel(); if (label != null) contentHandler.characters(label.toCharArray(), 0, label.length()); contentHandler.endElement(XMLConstants.XHTML_NAMESPACE_URI, "option", optionQName); }
private static boolean isSelected( PipelineContext pipelineContext, HandlerContext handlerContext, XFormsValueControl xformsControl, boolean isMultiple, Item item) { boolean isSelected; if (!handlerContext.isTemplate() && xformsControl != null) { final String itemValue = ((item.getValue() == null) ? "" : item.getValue()).trim(); final String controlValue = ((xformsControl.getValue(pipelineContext) == null) ? "" : xformsControl.getValue(pipelineContext)) .trim(); isSelected = XFormsItemUtils.isSelected(isMultiple, controlValue, itemValue); } else { isSelected = false; } return isSelected; }
private static void addItemAttributes(Item item, AttributesImpl spanAttributes) { final Map<String, String> itemAttributes = item.getAttributes(); if (itemAttributes != null && itemAttributes.size() > 0) { for (final Map.Entry<String, String> entry : itemAttributes.entrySet()) { final String attributeName = entry.getKey(); if (!attributeName.equals("class")) { // class is handled separately spanAttributes.addAttribute( "", attributeName, attributeName, ContentHandlerHelper.CDATA, entry.getValue()); } } } }
private static String getItemClasses(Item item, String initialClasses) { final Map<String, String> itemAttributes = item.getAttributes(); final StringBuilder sb = (initialClasses != null) ? new StringBuilder(initialClasses) : new StringBuilder(); if (itemAttributes != null) { final String itemClassValue = itemAttributes.get("class"); if (itemClassValue != null) { if (sb.length() > 0) sb.append(' '); sb.append(itemClassValue); } } return sb.toString(); }
@Override public void storeExternalValue(PropertyContext propertyContext, String value, String type) { if (!(this instanceof XFormsSelectControl)) { // kind of a HACK due to the way our class hierarchy is setup // Handle xforms:select1-specific logic // Decrypt incoming value. With open selection, values are sent to the client. if (isEncryptItemValues()) { try { value = XFormsItemUtils.decryptValue(propertyContext, value); } catch (IllegalArgumentException e) { getIndentedLogger() .logError( "", "exception decrypting value", "control id", getEffectiveId(), "value", value); throw e; } } // Current control value final String controlValue = getValue(propertyContext); // Iterate over all the items final Itemset itemset = getItemset(propertyContext); final List<XFormsEvent> selectEvents = new ArrayList<XFormsEvent>(); final List<XFormsEvent> deselectEvents = new ArrayList<XFormsEvent>(); if (itemset != null) { for (Item currentItem : itemset.toList()) { final String currentItemValue = currentItem.getValue(); final boolean itemWasSelected = controlValue.equals(currentItemValue); final boolean itemIsSelected; if (value.equals(currentItemValue)) { // Value is currently selected in the UI itemIsSelected = true; } else { // Value is currently NOT selected in the UI itemIsSelected = false; } // Handle xforms-select / xforms-deselect // TODO: Dispatch to itemset or item once we support doing that if (!itemWasSelected && itemIsSelected) { selectEvents.add(new XFormsSelectEvent(containingDocument, this, currentItemValue)); } else if (itemWasSelected && !itemIsSelected) { deselectEvents.add(new XFormsDeselectEvent(containingDocument, this, currentItemValue)); } } } // Dispatch xforms-deselect events if (deselectEvents.size() > 0) { for (XFormsEvent currentEvent : deselectEvents) { currentEvent .getTargetObject() .getXBLContainer(containingDocument) .dispatchEvent(propertyContext, currentEvent); } } // Select events must be sent after all xforms-deselect events final boolean hasSelectedItem = selectEvents.size() > 0; if (hasSelectedItem) { for (XFormsEvent currentEvent : selectEvents) { currentEvent .getTargetObject() .getXBLContainer(containingDocument) .dispatchEvent(propertyContext, currentEvent); } } if (hasSelectedItem || isOpenSelection()) { // Only then do we store the external value. This ensures that if the value is NOT in the // itemset AND // we are a closed selection then we do NOT store the value in instance. super.storeExternalValue(propertyContext, value, type); } } else { // Forward to superclass super.storeExternalValue(propertyContext, value, type); } }
public static void handleItemFull( PipelineContext pipelineContext, HandlerContext handlerContext, ContentHandler contentHandler, AttributesImpl reusableAttributes, Attributes attributes, String xhtmlPrefix, String spanQName, XFormsContainingDocument containingDocument, XFormsValueControl xformsControl, String effectiveId, String itemEffectiveId, boolean isMultiple, String type, Item item, boolean isFirst) throws SAXException { // Whether this is selected boolean isSelected = isSelected(pipelineContext, handlerContext, xformsControl, isMultiple, item); // xhtml:span enclosing input and label final String itemClasses = getItemClasses(item, isSelected ? "xforms-selected" : "xforms-deselected"); final AttributesImpl spanAttributes = getAttributes(reusableAttributes, XMLUtils.EMPTY_ATTRIBUTES, itemClasses, null); // Add item attributes to span addItemAttributes(item, spanAttributes); contentHandler.startElement( XMLConstants.XHTML_NAMESPACE_URI, "span", spanQName, spanAttributes); { { // xhtml:input final String inputQName = XMLUtils.buildQName(xhtmlPrefix, "input"); reusableAttributes.clear(); reusableAttributes.addAttribute( "", "id", "id", ContentHandlerHelper.CDATA, itemEffectiveId); reusableAttributes.addAttribute("", "type", "type", ContentHandlerHelper.CDATA, type); // Get group name from selection control if possible, otherwise use effective id final String name = (!isMultiple && xformsControl instanceof XFormsSelect1Control) ? ((XFormsSelect1Control) xformsControl).getGroupName() : effectiveId; reusableAttributes.addAttribute("", "name", "name", ContentHandlerHelper.CDATA, name); reusableAttributes.addAttribute( "", "value", "value", ContentHandlerHelper.CDATA, item.getExternalValue(pipelineContext)); if (!handlerContext.isTemplate() && xformsControl != null) { if (isSelected) { reusableAttributes.addAttribute( "", "checked", "checked", ContentHandlerHelper.CDATA, "checked"); } if (isFirst) { // Handle accessibility attributes handleAccessibilityAttributes(attributes, reusableAttributes); } } handleDisabledAttribute(reusableAttributes, containingDocument, xformsControl); contentHandler.startElement( XMLConstants.XHTML_NAMESPACE_URI, "input", inputQName, reusableAttributes); contentHandler.endElement(XMLConstants.XHTML_NAMESPACE_URI, "input", inputQName); } // We don't output the label within <input></input>, because XHTML won't display it. final String label = item.getLabel(); if (label != null) { // allow null label to tell not to output the <label> element at all reusableAttributes.clear(); outputLabelFor( handlerContext, reusableAttributes, itemEffectiveId, itemEffectiveId, LHHAC.LABEL, "label", label, false, false); // TODO: may be HTML for full appearance } } contentHandler.endElement(XMLConstants.XHTML_NAMESPACE_URI, "span", spanQName); }
public void outputContent( String uri, String localname, Attributes attributes, String effectiveId, final XFormsValueControl xformsSelect1Control, Itemset itemset, final boolean isMultiple, final boolean isFull, boolean isBooleanInput) throws SAXException { final ContentHandler contentHandler = handlerContext.getController().getOutput(); final AttributesImpl containerAttributes = getContainerAttributes( uri, localname, attributes, effectiveId, xformsSelect1Control, !isFull); final String xhtmlPrefix = handlerContext.findXHTMLPrefix(); if (!isStaticReadonly(xformsSelect1Control)) { if (isFull) { // Full appearance outputFull( uri, localname, attributes, effectiveId, xformsSelect1Control, itemset, isMultiple, isBooleanInput); } else { if (isOpenSelection) { if (isAutocomplete) { // Create xhtml:span final String spanQName = XMLUtils.buildQName(xhtmlPrefix, "span"); contentHandler.startElement( XMLConstants.XHTML_NAMESPACE_URI, "span", spanQName, containerAttributes); { { // Create xhtml:input final String inputQName = XMLUtils.buildQName(xhtmlPrefix, "input"); reusableAttributes.clear(); reusableAttributes.addAttribute( "", "type", "type", ContentHandlerHelper.CDATA, "text"); reusableAttributes.addAttribute( "", "name", "name", ContentHandlerHelper.CDATA, "xforms-select1-open-input-" + effectiveId); reusableAttributes.addAttribute( "", "class", "class", ContentHandlerHelper.CDATA, "xforms-select1-open-input"); reusableAttributes.addAttribute( "", "autocomplete", "autocomplete", ContentHandlerHelper.CDATA, "off"); final String value = (xformsSelect1Control == null) ? null : xformsSelect1Control.getValue(pipelineContext); // NOTE: With open selection, we send all values to the client but not encrypt them // because the client matches on values reusableAttributes.addAttribute( "", "value", "value", ContentHandlerHelper.CDATA, (value == null) ? "" : value); handleDisabledAttribute( reusableAttributes, containingDocument, xformsSelect1Control); contentHandler.startElement( XMLConstants.XHTML_NAMESPACE_URI, "input", inputQName, reusableAttributes); contentHandler.endElement(XMLConstants.XHTML_NAMESPACE_URI, "input", inputQName); } { // Create xhtml:select final String selectQName = XMLUtils.buildQName(xhtmlPrefix, "select"); reusableAttributes.clear(); reusableAttributes.addAttribute( "", "class", "class", ContentHandlerHelper.CDATA, "xforms-select1-open-select"); if (isCompact) reusableAttributes.addAttribute( "", "multiple", "multiple", ContentHandlerHelper.CDATA, "multiple"); // Handle accessibility attributes handleAccessibilityAttributes(attributes, reusableAttributes); contentHandler.startElement( XMLConstants.XHTML_NAMESPACE_URI, "select", selectQName, reusableAttributes); final String optionQName = XMLUtils.buildQName(xhtmlPrefix, "option"); handleItemCompact( contentHandler, optionQName, xformsSelect1Control, isMultiple, EMPTY_TOP_LEVEL_ITEM); if (itemset != null) { for (final Item item : itemset.toList()) { if (item.getValue() != null) handleItemCompact( contentHandler, optionQName, xformsSelect1Control, isMultiple, item); } } contentHandler.endElement(XMLConstants.XHTML_NAMESPACE_URI, "select", selectQName); } } contentHandler.endElement(XMLConstants.XHTML_NAMESPACE_URI, "span", spanQName); } else { // We do not support other appearances or regular open selection for now throw new ValidationException( "Open selection currently only supports the xxforms:autocomplete appearance.", new ExtendedLocationData( handlerContext.getLocationData(), "producing markup for xforms:" + localname + " control", (xformsSelect1Control != null) ? xformsSelect1Control.getControlElement() : null)); } } else if (isTree) { // xxforms:tree appearance // Create xhtml:div with tree info final String divQName = XMLUtils.buildQName(xhtmlPrefix, "div"); handleDisabledAttribute(containerAttributes, containingDocument, xformsSelect1Control); contentHandler.startElement( XMLConstants.XHTML_NAMESPACE_URI, "div", divQName, containerAttributes); if (itemset != null) { // can be null if the control is non-relevant outputJSONTreeInfo(xformsSelect1Control, itemset, isMultiple, contentHandler); } contentHandler.endElement(XMLConstants.XHTML_NAMESPACE_URI, "div", divQName); } else if (isMenu) { // xxforms:menu appearance // Create enclosing xhtml:div final String divQName = XMLUtils.buildQName(xhtmlPrefix, "div"); final String ulQName = XMLUtils.buildQName(xhtmlPrefix, "ul"); final String liQName = XMLUtils.buildQName(xhtmlPrefix, "li"); final String aQName = XMLUtils.buildQName(xhtmlPrefix, "a"); handleDisabledAttribute(containerAttributes, containingDocument, xformsSelect1Control); contentHandler.startElement( XMLConstants.XHTML_NAMESPACE_URI, "div", divQName, containerAttributes); if (itemset != null) { // can be null if the control is non-relevant // Create xhtml:div with initial menu entries { itemset.visit( contentHandler, new ItemsetListener() { private boolean groupJustStarted = false; public void startLevel(ContentHandler contentHandler, Item item) throws SAXException { final boolean isTopLevel = item == null; reusableAttributes.clear(); final String divClasses = isTopLevel ? "yuimenubar" : "yuimenu"; reusableAttributes.addAttribute( "", "class", "class", ContentHandlerHelper.CDATA, divClasses); contentHandler.startElement( XMLConstants.XHTML_NAMESPACE_URI, "div", divQName, reusableAttributes); reusableAttributes.clear(); reusableAttributes.addAttribute( "", "class", "class", ContentHandlerHelper.CDATA, "bd"); contentHandler.startElement( XMLConstants.XHTML_NAMESPACE_URI, "div", divQName, reusableAttributes); reusableAttributes.clear(); // NOTE: We just decide to put item classes on <ul> final String classes = isTopLevel ? "first-of-type" : getItemClasses(item, "first-of-type"); reusableAttributes.addAttribute( "", "class", "class", ContentHandlerHelper.CDATA, classes); contentHandler.startElement( XMLConstants.XHTML_NAMESPACE_URI, "ul", ulQName, reusableAttributes); groupJustStarted = true; } public void endLevel(ContentHandler contentHandler) throws SAXException { contentHandler.endElement(XMLConstants.XHTML_NAMESPACE_URI, "ul", ulQName); contentHandler.endElement(XMLConstants.XHTML_NAMESPACE_URI, "div", divQName); contentHandler.endElement(XMLConstants.XHTML_NAMESPACE_URI, "div", divQName); groupJustStarted = false; } public void startItem(ContentHandler contentHandler, Item item, boolean first) throws SAXException { final String liClasses; { final StringBuilder sb = new StringBuilder(item.isTopLevel() ? "yuimenubaritem" : "yuimenuitem"); if (groupJustStarted) sb.append(" first-of-type"); liClasses = getItemClasses(item, sb.toString()); } reusableAttributes.clear(); reusableAttributes.addAttribute( "", "class", "class", ContentHandlerHelper.CDATA, liClasses); contentHandler.startElement( XMLConstants.XHTML_NAMESPACE_URI, "li", liQName, reusableAttributes); reusableAttributes.clear(); reusableAttributes.addAttribute( "", "href", "href", ContentHandlerHelper.CDATA, "#"); contentHandler.startElement( XMLConstants.XHTML_NAMESPACE_URI, "a", aQName, reusableAttributes); final String text = item.getLabel(); contentHandler.characters(text.toCharArray(), 0, text.length()); contentHandler.endElement(XMLConstants.XHTML_NAMESPACE_URI, "a", aQName); groupJustStarted = false; } public void endItem(ContentHandler contentHandler) throws SAXException { contentHandler.endElement(XMLConstants.XHTML_NAMESPACE_URI, "li", liQName); groupJustStarted = false; } }); } // Create xhtml:div with tree info reusableAttributes.clear(); reusableAttributes.addAttribute( "", "class", "class", ContentHandlerHelper.CDATA, "xforms-initially-hidden"); contentHandler.startElement( XMLConstants.XHTML_NAMESPACE_URI, "div", divQName, reusableAttributes); if (itemset != null) { // can be null if the control is non-relevant outputJSONTreeInfo(xformsSelect1Control, itemset, isMultiple, contentHandler); } contentHandler.endElement(XMLConstants.XHTML_NAMESPACE_URI, "div", divQName); } contentHandler.endElement(XMLConstants.XHTML_NAMESPACE_URI, "div", divQName); } else { // Create xhtml:select final String selectQName = XMLUtils.buildQName(xhtmlPrefix, "select"); containerAttributes.addAttribute( "", "name", "name", ContentHandlerHelper.CDATA, effectiveId); // necessary for noscript mode if (isCompact) containerAttributes.addAttribute( "", "multiple", "multiple", ContentHandlerHelper.CDATA, "multiple"); // Handle accessibility attributes handleAccessibilityAttributes(attributes, containerAttributes); handleDisabledAttribute(containerAttributes, containingDocument, xformsSelect1Control); contentHandler.startElement( XMLConstants.XHTML_NAMESPACE_URI, "select", selectQName, containerAttributes); { final String optionQName = XMLUtils.buildQName(xhtmlPrefix, "option"); final String optGroupQName = XMLUtils.buildQName(xhtmlPrefix, "optgroup"); if (itemset != null) { // Work in progress for in-bounds/out-of-bounds // if (!((XFormsSelect1Control) // xformsControl).isInBounds(items)) { // // Control is out of bounds so add first item with out // of bound value to handle this // handleItemCompact(contentHandler, optionQName, // xformsControl, isMultiple, // new // XFormsItemUtils.Item(XFormsProperties.isEncryptItemValues(containingDocument), // Collections.EMPTY_LIST, "", // xformsControl.getValue(pipelineContext), 1)); // } itemset.visit( contentHandler, new ItemsetListener() { private int optgroupCount = 0; public void startLevel(ContentHandler contentHandler, Item item) throws SAXException {} public void endLevel(ContentHandler contentHandler) throws SAXException { if (optgroupCount-- > 0) { // End xhtml:optgroup contentHandler.endElement( XMLConstants.XHTML_NAMESPACE_URI, "optgroup", optGroupQName); } } public void startItem(ContentHandler contentHandler, Item item, boolean first) throws SAXException { final String label = item.getLabel(); final String value = item.getValue(); if (value == null) { final String itemClasses = getItemClasses(item, null); final AttributesImpl optGroupAttributes = getAttributes(XMLUtils.EMPTY_ATTRIBUTES, itemClasses, null); if (label != null) optGroupAttributes.addAttribute( "", "label", "label", ContentHandlerHelper.CDATA, label); // Start xhtml:optgroup contentHandler.startElement( XMLConstants.XHTML_NAMESPACE_URI, "optgroup", optGroupQName, optGroupAttributes); optgroupCount++; } else { handleItemCompact( contentHandler, optionQName, xformsSelect1Control, isMultiple, item); } } public void endItem(ContentHandler contentHandler) throws SAXException {} }); } } contentHandler.endElement(XMLConstants.XHTML_NAMESPACE_URI, "select", selectQName); } } } else { // Read-only mode final String spanQName = XMLUtils.buildQName(xhtmlPrefix, "span"); contentHandler.startElement( XMLConstants.XHTML_NAMESPACE_URI, "span", spanQName, containerAttributes); if (!handlerContext.isTemplate()) { final String value = (xformsSelect1Control == null || xformsSelect1Control.getValue(pipelineContext) == null) ? "" : xformsSelect1Control.getValue(pipelineContext); final StringBuilder sb = new StringBuilder(); if (itemset != null) { int selectedFound = 0; for (final Item currentItem : itemset.toList()) { if (XFormsItemUtils.isSelected(isMultiple, value, currentItem.getValue())) { if (selectedFound > 0) sb.append(" - "); sb.append(currentItem.getLabel()); selectedFound++; } } } if (sb.length() > 0) { final String result = sb.toString(); contentHandler.characters(result.toCharArray(), 0, result.length()); } } contentHandler.endElement(XMLConstants.XHTML_NAMESPACE_URI, "span", spanQName); } }