Skip to content

Commit

Permalink
AGNT-536 Add support for formnovalidate, richtextarea and datetime (#398
Browse files Browse the repository at this point in the history
)

* AGNT-536 Add support for formnovalidate, richtextarea and datetime

* Fix typo
  • Loading branch information
FabienVSymphony authored Jan 27, 2025
1 parent b5e8fd9 commit 00f8e0a
Show file tree
Hide file tree
Showing 37 changed files with 908 additions and 85 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import freemarker.template.TemplateExceptionHandler;
import org.apache.commons.io.input.ReaderInputStream;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import org.symphonyoss.symphony.messageml.bi.BiContext;
import org.symphonyoss.symphony.messageml.bi.BiFields;
Expand All @@ -40,6 +39,7 @@
import org.symphonyoss.symphony.messageml.elements.ExpandableCard;
import org.symphonyoss.symphony.messageml.elements.ExpandableCardBody;
import org.symphonyoss.symphony.messageml.elements.ExpandableCardHeader;
import org.symphonyoss.symphony.messageml.elements.RichTextArea;
import org.symphonyoss.symphony.messageml.elements.Tag;
import org.symphonyoss.symphony.messageml.elements.Form;
import org.symphonyoss.symphony.messageml.elements.FormElement;
Expand Down Expand Up @@ -76,6 +76,7 @@
import org.symphonyoss.symphony.messageml.elements.TableRow;
import org.symphonyoss.symphony.messageml.elements.TextArea;
import org.symphonyoss.symphony.messageml.elements.TextField;
import org.symphonyoss.symphony.messageml.elements.DateTime;
import org.symphonyoss.symphony.messageml.elements.TimePicker;
import org.symphonyoss.symphony.messageml.elements.TimezonePicker;
import org.symphonyoss.symphony.messageml.elements.TooltipableElement;
Expand All @@ -85,9 +86,6 @@
import org.symphonyoss.symphony.messageml.util.IDataProvider;
import org.symphonyoss.symphony.messageml.util.NoOpEntityResolver;
import org.symphonyoss.symphony.messageml.util.NullErrorHandler;
import org.symphonyoss.symphony.messageml.util.instrument.resolver.InstrumentKind;
import org.symphonyoss.symphony.messageml.util.instrument.resolver.InstrumentResolution;
import org.symphonyoss.symphony.messageml.util.instrument.resolver.ResolutionResults;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
Expand All @@ -107,7 +105,6 @@
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
Expand Down Expand Up @@ -638,6 +635,12 @@ public Element createElement(org.w3c.dom.Element element, Element parent) throws
case Tag.MESSAGEML_TAG:
return new Tag(parent, ++index);

case RichTextArea.MESSAGEML_TAG:
return new RichTextArea(parent, messageFormat);

case DateTime.MESSAGEML_TAG:
return new DateTime(parent, ++index);

default:
throw new InvalidInputException("Invalid MessageML content at element \"" + tag + "\"");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public enum BiFields {
FORM("form", BiEventType.MESSAGEML_ELEMENT_SENT),
BUTTON("button", BiEventType.MESSAGEML_ELEMENT_SENT),
TEXT_AREA("textarea", BiEventType.MESSAGEML_ELEMENT_SENT),
RICH_TEXT_AREA("richtextarea", BiEventType.MESSAGEML_MESSAGE_SENT),
TEXT_FIELD("textfield", BiEventType.MESSAGEML_ELEMENT_SENT),
CHECKBOX("checkbox", BiEventType.MESSAGEML_ELEMENT_SENT),
RADIO("radio", BiEventType.MESSAGEML_ELEMENT_SENT),
Expand Down Expand Up @@ -79,7 +80,8 @@ public enum BiFields {
POPUPS("popups", BiEventType.MESSAGEML_MESSAGE_SENT, "0"),
OPENIM("uiactions_openim", BiEventType.MESSAGEML_MESSAGE_SENT, "0"),
OPENDIALOG("uiactions_opendialog", BiEventType.MESSAGEML_MESSAGE_SENT, "0"),
COUNT("count", BiEventType.NONE, "0");
COUNT("count", BiEventType.NONE, "0"),
DATE_TIME("datetime", BiEventType.MESSAGEML_MESSAGE_SENT, "0");

private final String value;
private final BiEventType type;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import java.util.Map;
import java.util.Set;

import static org.symphonyoss.symphony.messageml.elements.FormElement.FORMNOVALIDATE_ATTR;
import static org.symphonyoss.symphony.messageml.elements.FormElement.FORMNOVALIDATE_PML_ATTR;
import static org.symphonyoss.symphony.messageml.elements.FormElement.NAME_ATTR;
import static org.symphonyoss.symphony.messageml.elements.FormElement.TYPE_ATTR;

Expand Down Expand Up @@ -88,6 +90,18 @@ public void buildAttribute(MessageMLParser parser, Node item) throws InvalidInpu
}
setAttribute(TooltipableElement.DATA_TITLE, getStringAttribute(item));
break;
case FORMNOVALIDATE_ATTR:
if (format != FormatEnum.MESSAGEML) {
throwInvalidInputException(item);
}
setAttribute(FORMNOVALIDATE_ATTR, getStringAttribute(item));
break;
case FORMNOVALIDATE_PML_ATTR:
if (format != FormatEnum.PRESENTATIONML) {
throwInvalidInputException(item);
}
setAttribute(FORMNOVALIDATE_PML_ATTR, getStringAttribute(item));
break;
default:
throwInvalidInputException(item);
}
Expand All @@ -103,14 +117,18 @@ void asPresentationML(XmlPrintStream out, MessageMLContext context) {
}

private Map<String, String> getPresentationMLAttributes() {
Map<String, String> attributes = getAttributes();
if (format == FormatEnum.MESSAGEML && attributes.containsKey(TooltipableElement.TITLE)) {
Map<String, String> presentationAttributes = new LinkedHashMap<>(attributes);
presentationAttributes.put(TooltipableElement.DATA_TITLE, attributes.get(TooltipableElement.TITLE));
presentationAttributes.remove(TooltipableElement.TITLE);
return presentationAttributes;
Map<String, String> presentationAttributes = new LinkedHashMap<>(getAttributes());
if (format == FormatEnum.MESSAGEML) {
if (presentationAttributes.containsKey(TooltipableElement.TITLE)) {
presentationAttributes.put(TooltipableElement.DATA_TITLE, presentationAttributes.get(TooltipableElement.TITLE));
presentationAttributes.remove(TooltipableElement.TITLE);
}
if (presentationAttributes.containsKey(FORMNOVALIDATE_ATTR)) {
presentationAttributes.put(FORMNOVALIDATE_PML_ATTR, presentationAttributes.get(FORMNOVALIDATE_ATTR));
presentationAttributes.remove(FORMNOVALIDATE_ATTR);
}
}
return attributes;
return presentationAttributes;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,13 @@ protected void buildAttribute(MessageMLParser parser,
case LABEL:
case DISABLED_ATTR:
case READONLY_ATTR:
case FORMNOVALIDATE_ATTR:
setAttribute(item.getNodeName(), getStringAttribute(item));
break;
case FORMNOVALIDATE_PML_ATTR:
if(this.format != FormatEnum.PRESENTATIONML){
throwInvalidInputException(item);
}
setAttribute(item.getNodeName(), getStringAttribute(item));
break;
case ID_ATTR:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ protected void buildAttribute(MessageMLParser parser, Node item) throws InvalidI
case DISABLED_DATE_ATTR:
case HIGHLIGHTED_DATE_ATTR:
case FORMAT_ATTR:
case FORMNOVALIDATE_ATTR:
if (this.format != FormatEnum.MESSAGEML) {
throwInvalidInputException(item);
}
Expand All @@ -82,6 +83,7 @@ protected void buildAttribute(MessageMLParser parser, Node item) throws InvalidI
case PRESENTATIONML_DISABLED_DATE_ATTR:
case PRESENTATIONML_HIGHLIGHTED_DATE_ATTR:
case PRESENTATIONML_FORMAT_ATTR:
case FORMNOVALIDATE_PML_ATTR:
if (this.format != FormatEnum.PRESENTATIONML) {
throwInvalidInputException(item);
}
Expand Down Expand Up @@ -203,6 +205,12 @@ private Map<String, Object> buildDataPickerInputAttributes() {
if (getAttribute(PRESENTATIONML_FORMAT_ATTR) != null) {
presentationAttrs.put(PRESENTATIONML_FORMAT_ATTR, getAttribute(PRESENTATIONML_FORMAT_ATTR));
}
if (getAttribute(FORMNOVALIDATE_ATTR) != null) {
presentationAttrs.put(FORMNOVALIDATE_PML_ATTR, getAttribute(FORMNOVALIDATE_ATTR));
}
if(getAttribute(FORMNOVALIDATE_PML_ATTR) != null) {
presentationAttrs.put(FORMNOVALIDATE_PML_ATTR, getAttribute(FORMNOVALIDATE_ATTR));
}
return presentationAttrs;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ protected void buildAttribute(MessageMLParser parser,
case REQUIRED_ATTR:
setAttribute(REQUIRED_ATTR, getStringAttribute(item));
break;
case FORMNOVALIDATE_ATTR:
setAttribute(FORMNOVALIDATE_ATTR, getStringAttribute(item));
break;
default:
throwInvalidInputException(item);
}
Expand Down Expand Up @@ -131,6 +134,10 @@ private Map<String, String> buildDateSelectorInputAttributes() {
presentationAttrs.put(PRESENTATIONML_REQUIRED_ATTR, getAttribute(REQUIRED_ATTR));
}

if(getAttribute(FORMNOVALIDATE_ATTR) != null) {
presentationAttrs.put(FORMNOVALIDATE_PML_ATTR, getAttribute(FORMNOVALIDATE_ATTR));
}

return presentationAttrs;
}

Expand All @@ -149,6 +156,11 @@ void buildElementFromDiv(MessageMLParser parser, org.w3c.dom.Element element) th
element.removeAttribute(PRESENTATIONML_REQUIRED_ATTR);
}

if (element.hasAttribute(FORMNOVALIDATE_PML_ATTR)) {
element.setAttribute(FORMNOVALIDATE_ATTR, element.getAttribute(FORMNOVALIDATE_PML_ATTR));
element.removeAttribute(FORMNOVALIDATE_PML_ATTR);
}

NamedNodeMap attributes = element.getAttributes();

for (int i = 0; i < attributes.getLength(); i++) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
package org.symphonyoss.symphony.messageml.elements;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.commonmark.node.Node;
import org.symphonyoss.symphony.messageml.MessageMLContext;
import org.symphonyoss.symphony.messageml.MessageMLParser;
import org.symphonyoss.symphony.messageml.bi.BiContext;
import org.symphonyoss.symphony.messageml.bi.BiFields;
import org.symphonyoss.symphony.messageml.bi.BiItem;
import org.symphonyoss.symphony.messageml.exceptions.InvalidInputException;
import org.symphonyoss.symphony.messageml.markdown.nodes.DateTimeNode;
import org.symphonyoss.symphony.messageml.util.XmlPrintStream;

import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* MessageML entity that allows to display a time following local time zone and user preference
* Fields:
* * value : time value according to ISO 8601 with date, time and timezone
* * example: 2024-12-31T09:29:47Z
* * format: which format to use to display the date
* * available values: date, time, date_time, time_secs
*/
public class DateTime extends Entity {
public static final String MESSAGEML_TAG = "dateTime";
private static final String PRESENTATIONML_TAG = "time";

private static final String ENTITY_TYPE = "org.symphonyoss";
private static final String ENTITY_SUBTYPE = "org.symphonyoss.datetime";
private static final String ENTITY_VERSION = "1.0";
private static final String ENTITY_ID_PREFIX = "datetime";

private static final String ATTR_VALUE = "value";
private static final String ATTR_FORMAT = "format";

private static final String ATTR_PML_FORMAT = "data-format";
private static final String ATTR_PML_VALUE = "datetime";

private static final String DATA_NODE = "data";

private static List<String> VALID_DATE_FORMATS = Arrays.asList("date_time", "date", "time", "time_secs");

private String value;
private String dateFormat;


public DateTime(Element parent, int entityIndex) {
super(parent, MESSAGEML_TAG, PRESENTATIONML_TAG, FormatEnum.MESSAGEML);
this.entityId = getEntityId(entityIndex);
}

@Override
protected String getEntityValue() {
return value;
}

@Override
protected String getEntitySubType() {
return ENTITY_SUBTYPE;
}

@Override
protected String getEntityVersion() {
return ENTITY_VERSION;
}

@Override
protected String getEntityType() {
return ENTITY_TYPE;
}

@Override
protected String getEntityIdPrefix() {
return ENTITY_ID_PREFIX;
}

@Override
public void validate() throws InvalidInputException {
super.validate();

assertAttributeNotBlank(ATTR_VALUE);
assertDateFormat(ATTR_VALUE, DateTimeFormatter.ISO_OFFSET_DATE_TIME);

if (getAttribute(ATTR_FORMAT) != null) {
assertAttributeValue(ATTR_FORMAT, VALID_DATE_FORMATS);
}

}

@Override
protected void buildAttribute(MessageMLParser parser,
org.w3c.dom.Node item) throws InvalidInputException {
switch (item.getNodeName()) {
case ATTR_VALUE:
this.value = getStringAttribute(item);
setAttribute(ATTR_VALUE, this.value);
break;
case ATTR_FORMAT:
this.dateFormat = getStringAttribute(item);
setAttribute(ATTR_FORMAT, dateFormat);
break;
default:
throw new InvalidInputException( "Attribute \"" + item.getNodeName() + "\" is not allowed in \"" + getMessageMLTag() + "\"");
}
}


@Override
public void asPresentationML(XmlPrintStream out, MessageMLContext context) {
Map<String, String> attributes = new HashMap<>();
attributes.put(ENTITY_ID_ATTR, entityId);

if (getAttribute(ATTR_FORMAT) != null) {
attributes.put(ATTR_PML_FORMAT, getAttribute(ATTR_FORMAT));
}
attributes.put(ATTR_PML_VALUE, getAttribute(ATTR_VALUE));
out.printElement(PRESENTATIONML_TAG, value, attributes);
}

@Override
Node asMarkdown() throws InvalidInputException {
return new DateTimeNode(entityId, value, dateFormat);
}

@Override
public ObjectNode asEntityJson(ObjectNode parent) {
JsonNode entityNode = parent.path(entityId);

if (entityNode.isMissingNode()) {
ObjectNode node = new ObjectNode(JsonNodeFactory.instance);
node.put(Entity.TYPE_FIELD, getEntityType());
node.put(Entity.VERSION_FIELD, getEntityVersion());

ObjectNode dataNode = new ObjectNode(JsonNodeFactory.instance);
dataNode.put(Entity.VALUE_FIELD, value);
dataNode.put(Entity.TYPE_FIELD, getEntitySubType());
dataNode.put(ATTR_FORMAT, dateFormat);

node.set(DATA_NODE, dataNode);

parent.set(entityId, node);

return node;

} else {
//For preexisting data-entity-id the node type has already been validated by MessageMLParser
return (ObjectNode) entityNode;
}
}

@Override
public void updateBiContext(BiContext context) {
super.updateBiContext(context);
context.updateItemCount(BiFields.DATE_TIME.getValue());
context.addItem(new BiItem(BiFields.ENTITY.getValue(),
Collections.singletonMap(BiFields.ENTITY_TYPE.getValue(), this.getEntitySubType())));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@

import org.symphonyoss.symphony.messageml.exceptions.InvalidInputException;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class FormElement extends Element {
public static final String INPUT_TAG = "input";
public static final String TYPE_ATTR = "type";
public static final String FORMNOVALIDATE_ATTR = "formnovalidate";
public static final String FORMNOVALIDATE_PML_ATTR = "data-formnovalidate";


protected static final String NAME_ATTR = "name";

Expand All @@ -21,6 +26,12 @@ public FormElement(Element parent, String messageMLTag, FormatEnum format) {
@Override
public void validate() throws InvalidInputException {
super.validate();
if (getAttribute(FORMNOVALIDATE_ATTR) != null) {
assertAttributeIsBoolean(FORMNOVALIDATE_ATTR);
}
if (getAttribute(FORMNOVALIDATE_PML_ATTR) != null) {
assertAttributeIsBoolean(FORMNOVALIDATE_PML_ATTR);
}
assertParentAtAnyLevel(Collections.singleton(Form.class));
}
}
Loading

0 comments on commit 00f8e0a

Please sign in to comment.