
com.adobe.granite.ui.components.AttrBuilder Maven / Gradle / Ivy
/*************************************************************************
*
* ADOBE CONFIDENTIAL
* __________________
*
* Copyright 2012 Adobe Systems Incorporated
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of Adobe Systems Incorporated and its suppliers,
* if any. The intellectual and technical concepts contained
* herein are proprietary to Adobe Systems Incorporated and its
* suppliers and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe Systems Incorporated.
**************************************************************************/
package com.adobe.granite.ui.components;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import com.adobe.granite.xss.XSSAPI;
/**
* A builder to generate HTML attributes. This builder is designed to be secured
* using {@link XSSAPI}. It will encode the value automatically. If the value is
* null
, it will be ignored.
*/
public class AttrBuilder {
private final HttpServletRequest req;
private final XSSAPI xssAPI;
private Map data = new LinkedHashMap();
private Map encodings = new LinkedHashMap<>();
private Set classes = new HashSet();
private enum Encoding {
HREF, HTML_ATTR
}
public AttrBuilder(HttpServletRequest req, XSSAPI xssAPI) {
this.req = req;
this.xssAPI = xssAPI;
}
/**
* Gets the raw {@link Map} of attributes, with un-encoded values
*
* @return {@link Map} of attributes
*/
public Map getData() {
return data;
}
/**
* Adds relationship. Currently it is implemented as class
* attribute.
* @param value the relationship to add
*/
public void addRel(String value) {
addClass(value);
}
/**
* Adds class
attribute with the given value.
* @param value the class attribute to add
*/
public void addClass(String value) {
if (value == null || value.length() == 0) return;
if (classes.add(value)) {
add("class", value);
}
}
/**
* Adds an attribute that behave like href
attribute. i.e. the
* value will be prepended with context path (if absolute path) and checked
* using {@link XSSAPI#getValidHref(String)}.
* @param name the name of the attribute to add
* @param value the value of the specified attribute
*/
public void addHref(String name, String value) {
if (value == null || value.length() == 0) return;
if (value.startsWith("/")) {
value = req.getContextPath() + value;
}
data.put(name, value);
encodings.put(name, Encoding.HREF);
}
/**
* Adds {@code disabled} attribute.
* @param disabled the boolean value of the {@code disabled} attribute
*/
public void addDisabled(boolean disabled) {
this.addBoolean("disabled", disabled);
}
/**
* Adds {@code checked} attribute.
* @param checked the boolean value of the {@code checked} attribute
*/
public void addChecked(boolean checked) {
this.addBoolean("checked", checked);
}
/**
* Adds {@code selected} attribute.
* @param selected the boolean value of the {@code selected} attribute
*/
public void addSelected(boolean selected) {
this.addBoolean("selected", selected);
}
/**
* Adds {@code multiple} attribute.
* @param multiple the boolean value of the {@code multiple} attribute
*/
public void addMultiple(boolean multiple) {
this.addBoolean("multiple", multiple);
}
/**
* Adds boolean attribute (behaves like disabled
) for the given name.
* When the given value is true
, it will be printed as "disabled=''", instead of "disabled='true'".
* When the given value is false
, it will NOT be printed, instead of "disabled='false'".
* @param name the name of the boolean attribute to add
* @param value the boolean value of the attribute
*/
public void addBoolean(String name, boolean value) {
if (!value) return;
add(name, "");
}
/**
* Adds the given name as data-* attribute.
* @param name the name of the data-* attribute to add
* @param value the value of the attribute
*/
public void addOther(String name, String value) {
add("data-" + xssAPI.encodeForHTML(name), value);
}
/**
* Adds the given data as data-* attributes. Entries with keys specified in
* exclusions parameter or having namespace (e.g. jcr:primaryType) will be
* excluded.
* @param data the map containing key/value pairs to add as data-* attributes
* @param exclusions the keys which must not be added as data-* attributes
*/
public void addOthers(Map data, String... exclusions) {
List blacklisted = Arrays.asList(exclusions);
for (Entry e : data.entrySet()) {
String key = e.getKey();
if (key.indexOf(":") >= 0) continue;
if (blacklisted.indexOf(key) >= 0) continue;
Object value = e.getValue();
if (value.getClass().isArray()) {
for (Object o : (Object[]) value) {
addOther(key, o.toString());
}
} else {
addOther(key, value.toString());
}
}
}
/**
* Adds attribute with the given name. The value will be added to existing attribute using space-delimited convention.
* e.g. class="class1 class2"
* @param name the name of the attribute to add
* @param value the boolean value of the attribute
*/
public void add(String name, Boolean value) {
if (value == null || name == null || name.length() == 0) return;
addNoCheck(name, value.toString());
}
/**
* Adds attribute with the given name. The value will be added to existing attribute using space-delimited convention.
* e.g. class="class1 class2"
* @param name the name of the attribute to add
* @param value the integer value of the attribute
*/
public void add(String name, Integer value) {
if (value == null || name == null || name.length() == 0) return;
addNoCheck(name, value.toString());
}
/**
* Adds attribute with the given name. The value will be added to existing attribute using space-delimited convention.
* e.g. class="class1 class2"
* @param name the name of the attribute to add
* @param value the double value of the attribute
*/
public void add(String name, Double value) {
if (value == null || name == null || name.length() == 0) return;
addNoCheck(name, value.toString());
}
/**
* Adds attribute with the given name. The value will be added to existing attribute using space-delimited convention.
* e.g. class="class1 class2"
* @param name the name of the attribute to add
* @param value the string value of the attribute
*/
public void add(String name, String value) {
if (value == null || name == null || name.length() == 0) return;
addNoCheck(name, value);
encodings.put(name, Encoding.HTML_ATTR);
}
/**
* Sets attribute with the given name. Existing value previously set will be replaced by the given value.
* @param name the name of the attribute to set or replace (if exists)
* @param value the string value of the attribute
*/
public void set(String name, String value) {
if (value == null || name == null || name.length() == 0) return;
data.put(name, value);
encodings.put(name, Encoding.HTML_ATTR);
}
private void addNoCheck(String name, String v) {
if (data.containsKey(name)) {
v = data.get(name) + " " + v;
}
data.put(name, v);
}
/**
* Returns {@code true} if there is no attribute in this builder, {@code false} otherwise.
* @return {@code true} if there is no attribute in this builder, {@code false} otherwise
*/
public boolean isEmpty() {
return data.isEmpty();
}
/**
* Builds the attributes in the form of {@code =''*}.
* @return the string containing the built attributes
*/
public String build() {
try {
StringWriter out = new StringWriter();
build(out);
return out.toString();
} catch (IOException impossible) {
throw new RuntimeException(impossible);
}
}
/**
* Builds the attributes in the form of {@code =''*}*.
* @param out the writer
* @throws IOException in case there's an error when appending to the writer
*/
public void build(Writer out) throws IOException {
for (Entry e : data.entrySet()) {
String key = e.getKey();
String value = e.getValue();
Encoding encoding = encodings.get(e.getKey());
if (encoding != null && value != null && value.length() > 0) {
switch (encoding) {
case HREF:
value = xssAPI.getValidHref(value);
break;
case HTML_ATTR:
value = xssAPI.encodeForHTMLAttr(value);
break;
}
}
out.append(" ").append(key).append("=\"").append(value).append("\"");
}
}
@Override
public String toString() {
return build();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy