package xapi.polymer.pickers; import static com.google.gwt.regexp.shared.RegExp.quote; import static xapi.components.impl.JsSupport.getString; import static xapi.components.impl.JsSupport.newElement; import static xapi.components.impl.JsSupport.not; import static xapi.components.impl.JsSupport.removeFromParent; import static xapi.components.impl.JsSupport.setObject; import java.util.function.Consumer; import java.util.function.Function; import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.js.JsProperty; import com.google.gwt.core.client.js.JsType; import elemental.dom.Element; import elemental.js.util.JsArrayOfString; import elemental.js.util.JsMapFromStringTo; import elemental.util.MapFromStringTo; import xapi.components.api.IsWebComponent; import xapi.components.api.OnWebComponentAttributeChanged; import xapi.components.api.OnWebComponentCreated; import xapi.components.api.WebComponent; import xapi.components.api.WebComponentFactory; import xapi.components.api.WebComponentMethod; import xapi.polymer.core.PolymerElement; @JsType @WebComponent(tagName=ListItemElement.TAG_NAME) public interface ListItemElement extends IsWebComponent<Element>, OnWebComponentAttributeChanged, OnWebComponentCreated<Element>, AbstractPickerElement<Element> { String TAG_NAME = "xapi-item-list"; WebComponentFactory<ListItemElement> NEW_LIST_ITEM = GWT.create(ListItemElement.class); @JsProperty @WebComponentMethod(mapToAttribute = true) JsArrayOfString getValue(); @JsProperty @WebComponentMethod(mapToAttribute = true) void setValue(JsArrayOfString property); default void setValueFromString(String properties) { element().setAttribute("value", properties); } default String[] valueArray() { JsArrayOfString arr = getValue(); String[] value = new String[arr.length()]; MapFromStringTo<Element> map = getItemMap(); for (int i = arr.length(); i-->0; ){ value[i] = getString(map.get(arr.get(i)), "originalValue"); } return value; } @JsProperty String getJoiner(); @JsProperty ListItemElement setJoiner(String joiner); @JsProperty boolean getRemovable(); @JsProperty ListItemElement setRemovable(boolean allowRemove); @JsProperty MapFromStringTo<Element> getItemMap(); @JsProperty ListItemElement setItemMap(MapFromStringTo<Element> itemMap); default MapFromStringTo<Element> initItemMap() { MapFromStringTo<Element> map = getItemMap(); if (map == null) { map = JsMapFromStringTo.create(); setItemMap(map); } return map; } @Override default void onCreated(Element element) { initializePolymer("paper-shadow"); } @JsProperty Function<String, Element> itemBuilder(); @JsProperty ListItemElement itemBuilder(Function<String, Element> builder); @JsProperty Consumer<Element> onItemBuilt(); @JsProperty ListItemElement onItemBuilt(Consumer<Element> callback); default Element newItemElement(String bit) { Function<String, Element> builder = itemBuilder(); Element item; if (builder == null) { item = newElement("paper-item"); item.setInnerText(bit); } else { item = builder.apply(bit); } if (getRemovable()) { PolymerElement remover = PolymerElement.newIcon("close"); remover.onClick(e->{ removeFromParent(item); Element el = element(); String joiner = getJoiner(); if (joiner == null) { joiner = " "; } String oldVal = el.getAttribute("value"); String newVal = (joiner+oldVal+joiner).replaceFirst(joiner+bit+joiner, ""); el.setAttribute("value", newVal); }); item.appendChild(remover.element()); } setObject(item, "originalValue", bit); Consumer<Element> callback = onItemBuilt(); if (callback != null) { callback.accept(item); } return item; } default void addValue(String item) { String joiner = getJoiner(); if (joiner == null) { joiner = " "; String escaped = item.replaceAll("([ ][ ]+)", " "); MapFromStringTo<Element> map = initItemMap(); map.put(escaped, newItemElement(item)); item = escaped; } Element ele = element(); String before = ele.getAttribute("value"); if (not(before)) { ele.setAttribute("value", item); } else { ele.setAttribute("value", before+joiner+item); } } @Override default void onAttributeChanged(String name, String oldVal, String newVal) { MapFromStringTo<Element> map; switch (name) { case "value": map = getItemMap(); if (newVal == null) { setItemMap(null); getPolymer().element().setInnerHTML(""); return; } if (map == null) { map = JsMapFromStringTo.create(); setItemMap(map); } String joiner = getJoiner(); if (joiner == null) { joiner = " "; } String[] bits = newVal.split(quote(joiner)); JsArrayOfString value = JsArrayOfString.create(); getPolymer().setInnerHTML(""); for (String bit : bits) { if (bit.length() == 0) { continue; } value.push(bit); Element existing = map.get(bit); if (existing == null) { existing = newItemElement(bit); } getPolymer().appendChild(existing); } // TODO maintain selection state break; } } }