Skip to content

Commit

Permalink
Merge pull request #301 from symphony-youri/PLAT-11463-multi-select
Browse files Browse the repository at this point in the history
Multi select element
  • Loading branch information
symphony-youri authored Oct 27, 2021
2 parents 825c09c + 27ab359 commit 78021f6
Show file tree
Hide file tree
Showing 4 changed files with 557 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ public enum BiFields {
HIGHLIGHTED_OPTIONS("highlighted_options", BiEventType.MESSAGEML_ELEMENT_SENT),
VALIDATION_STRICT("validation_strict", BiEventType.MESSAGEML_ELEMENT_SENT),
REQUIRED("required", BiEventType.MESSAGEML_ELEMENT_SENT),
MULTI_SELECT("is_multi_select", BiEventType.MESSAGEML_ELEMENT_SENT),
MESSAGE_LENGTH("message_length", BiEventType.MESSAGEML_MESSAGE_SENT),
ENTITY_JSON_SIZE("entities_json_size", BiEventType.MESSAGEML_MESSAGE_SENT),
FREEMARKER("use_freemarker", BiEventType.MESSAGEML_MESSAGE_SENT),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -989,4 +989,20 @@ protected void throwInvalidInputException(org.w3c.dom.Node item) throws InvalidI
throw new InvalidInputException("Attribute \"" + item.getNodeName()
+ "\" is not allowed in \"" + getMessageMLTag() + "\"");
}

protected int checkIntegerAttribute(String attributeName, int minValue, String errorMessage)
throws InvalidInputException {
int value = 0;
if (getAttribute(attributeName) != null) {
try {
value = Integer.parseInt(getAttribute(attributeName));
if (value < minValue) {
throw new InvalidInputException(errorMessage);
}
} catch (NumberFormatException e) {
throw new InvalidInputException(errorMessage, e);
}
}
return value;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,36 @@
import java.util.Map;

/**
* Class representing dropdown menu - Symphony Elements.
*
* @author lumoura
* @since 3/22/18
* This class represents the Symphony Element Dialog which is represented with tag name "select" (drop down menu).
* The messageML representation of the select element can contain the following attributes:
* <ul>
* <li> name (required) -> to identify this element</li>
* <li> required -> true/false, to enforce a non empty option to be selected</li>
* <li> data-placeholder -> string, text displayed in the dropdown menu before an option is selected</li>
* <li> title -> string, the description that will be displayed when clicking the tooltip icon</li>
* <li> label -> string, definition of the label that will be displayed on top of the Masked Text Field Element</li>
* <li> multiple -> true/false, to allow for multiple options to be selected</li>
* <li> min -> integer, minimum number of options to select if multiple=true</li>
* <li> max -> integer, maximum number of options to select if multiple=true</li>
* </ul>
* It can contain the following child tags:
* <ul>
* <li> option (required) -> the possible options to select {@link Option}</li>
* </ul>
*/

public class Select extends FormElement implements LabelableElement, TooltipableElement {

public static final String MESSAGEML_TAG = "select";
public static final String ELEMENT_ID = "dropdown";
private static final String REQUIRED_ATTR = "required";
private static final String OPTION_SELECTED_ATTR = "selected";
private static final String DATA_PLACEHOLDER_ATTR = "data-placeholder";
private static final String MULTIPLE_ATTR = "multiple";
private static final String MML_MIN_ATTR = "min";
private static final String MIN_ATTR = "data-min";
private static final String MML_MAX_ATTR = "max";
private static final String MAX_ATTR = "data-max";

public Select(Element parent) {
super(parent, MESSAGEML_TAG);
Expand All @@ -59,31 +77,64 @@ public void validate() throws InvalidInputException {
if (getAttribute(NAME_ATTR) == null) {
throw new InvalidInputException("The attribute \"name\" is required");
}
assertAttributeNotBlank(NAME_ATTR);

assertContentModel(Collections.singleton(Option.class));
assertContainsChildOfType(Collections.singleton(Option.class));

if(getAttribute(REQUIRED_ATTR) != null) {
if (getAttribute(REQUIRED_ATTR) != null) {
assertAttributeValue(REQUIRED_ATTR, Arrays.asList(Boolean.TRUE.toString(), Boolean.FALSE.toString()));
}

assertOnlyOneOptionSelected();
assertAttributeNotBlank(NAME_ATTR);
if (getAttribute(MULTIPLE_ATTR) != null) {
assertAttributeValue(MULTIPLE_ATTR, Arrays.asList(Boolean.TRUE.toString(), Boolean.FALSE.toString()));
}

boolean multipleAttributeValue = Boolean.parseBoolean(getAttribute(MULTIPLE_ATTR));
if (getAttribute(MIN_ATTR) != null && !multipleAttributeValue) {
throw new InvalidInputException("Attribute \"min\" is not allowed. Attribute \"multiple\" missing");
}

if (getAttribute(MAX_ATTR) != null && !multipleAttributeValue) {
throw new InvalidInputException("Attribute \"max\" is not allowed. Attribute \"multiple\" missing");
}

int min = checkIntegerAttribute(MIN_ATTR, 0, "Attribute \"min\" is not valid, it must be >= 0");
int max = checkIntegerAttribute(MAX_ATTR, 1, "Attribute \"max\" is not valid, it must be >= 1");
if (max > 0 && min > max) {
throw new InvalidInputException("Attribute \"min\" is greater than attribute \"max\"");
}

if (multipleAttributeValue && Boolean.parseBoolean(getAttribute(REQUIRED_ATTR))
&& getAttribute(MIN_ATTR) != null && min == 0) {
// multiple=true required=true min=0
throw new InvalidInputException("Attribute \"min\" cannot be 0 if \"required\" is true");
}

if (!multipleAttributeValue) {
assertOnlyOneOptionSelected();
}
}

@Override
protected void buildAttribute(MessageMLParser parser,
Node item) throws InvalidInputException {
protected void buildAttribute(MessageMLParser parser, Node item) throws InvalidInputException {
switch (item.getNodeName()) {
case NAME_ATTR:
case REQUIRED_ATTR:
case DATA_PLACEHOLDER_ATTR:
case LABEL:
case TITLE:
case MULTIPLE_ATTR:
setAttribute(item.getNodeName(), getStringAttribute(item));
break;
case MML_MIN_ATTR:
setAttribute(MIN_ATTR, getStringAttribute(item));
break;
case MML_MAX_ATTR:
setAttribute(MAX_ATTR, getStringAttribute(item));
break;
case ID_ATTR:
if(format != FormatEnum.PRESENTATIONML){
if (format != FormatEnum.PRESENTATIONML) {
throwInvalidInputException(item);
}
fillAttributes(parser, item);
Expand All @@ -94,7 +145,7 @@ protected void buildAttribute(MessageMLParser parser,
}

@Override
public String getElementId(){
public String getElementId() {
return ELEMENT_ID;
}

Expand All @@ -106,6 +157,7 @@ public void updateBiContext(BiContext context) {
this.putOneIfPresent(attributesMapBi, BiFields.LABEL.getValue(), LABEL);
this.putOneIfPresent(attributesMapBi, BiFields.PLACEHOLDER.getValue(), DATA_PLACEHOLDER_ATTR);
this.putOneIfPresent(attributesMapBi, BiFields.REQUIRED.getValue(), REQUIRED_ATTR);
this.putOneIfPresent(attributesMapBi, BiFields.MULTI_SELECT.getValue(), MULTIPLE_ATTR);

context.addItem(new BiItem(BiFields.SELECT.getValue(), attributesMapBi));
}
Expand All @@ -116,7 +168,7 @@ private void assertOnlyOneOptionSelected() throws InvalidInputException {
.filter(selectedAttr -> selectedAttr != null && selectedAttr.equalsIgnoreCase(Boolean.TRUE.toString()))
.count();

if(numberOfSelectedOptions > 1) {
if (numberOfSelectedOptions > 1) {
throw new InvalidInputException("Element \"select\" can only have one selected \"option\"");
}
}
Expand Down
Loading

0 comments on commit 78021f6

Please sign in to comment.