package xapi.elemental; import elemental.client.Browser; import elemental.dom.DocumentFragment; import elemental.dom.Element; import elemental.html.DivElement; import elemental.html.Location; import xapi.elemental.api.ElementIterable; import xapi.elemental.api.ElementalService; import xapi.elemental.api.PotentialNode; import xapi.inject.X_Inject; import xapi.ui.html.X_Html; import xapi.util.api.ConvertsValue; import com.google.gwt.core.client.MagicMethod; import javax.inject.Provider; public class X_Elemental { public static boolean addClassName(final Element e, final String cls) { if (!hasClassName(e, cls)) { e.setClassName(e.getClassName() + " " + cls); return true; } return false; } public static void alert(final String msg) { Browser.getWindow().alert(msg); } public static Iterable<Element> attachTo(final Element body, final String html) { final DivElement wrapper = Browser.getDocument().createDivElement(); wrapper.setInnerHTML(html); final Iterable<Element> iter = ElementIterable.forEach(wrapper.getChildren()); for (final Element e : iter) { body.appendChild(e); } return iter; } public static void attachToBody(final Element element) { Browser.getDocument().getBody().appendChild(element); } public static String concatClass(final String is, final String value) { final String clsName = " " + is + " "; return clsName.contains(" " + value + " ") ? is : is + " " + value; } public static void detachElement(final Element el) { final Element par = el.getParentElement(); if (par != null) { par.removeChild(el); } } public static native <E extends Element> E getById(String id) /*-{ return $doc.getElementById(id); }-*/; public static ElementalService getElementalService() { return SERVICE.get(); } public static String getHost() { final Location loc = Browser.getWindow().getLocation(); return loc.getProtocol() + "//" + loc.getHost() + "/"; } public static String getHrefById(final String id) { final Element el = Browser.getDocument().getElementById(id); return el == null ? "" : el.getAttribute("href"); } public static String getInnerTextStringById(final String id) { final Element el = Browser.getDocument().getElementById(id); return el == null ? "" : el.getInnerText(); } public static boolean hasClassName(final Element e, final String cls) { return (" " + e.getClassName() + " ") .contains(" " + cls + " "); } @MagicMethod(doNotVisit=true) public static void injectCss(final Class<?> cls) { X_Html.injectCss(cls, SERVICE.get()); } public static Element newDiv() { return (Element) X_Elemental.DIV.cloneNode(false); } public static boolean removeClassName(final Element e, final String cls) { if (hasClassName(e, cls)) { final String clsName = " " + e.getClassName() + " "; e.setClassName(clsName.replace(" " + cls + " ", " ").trim()); return true; } return false; } @MagicMethod(doNotVisit=true) public static <T, E extends Element> E toElement( final Class<? super T> model, final Class<?> template, final T obj) { return SERVICE.get().toElement(model, template, obj); } @MagicMethod(doNotVisit=true) public static <T, E extends Element> E toElement( final Class<? super T> cls, final T obj) { return SERVICE.get().toElement(cls, obj); } @SuppressWarnings("unchecked" ) public static <E extends Element> E toElement(final String string) { final Element clone = (Element) X_Elemental.DIV.cloneNode(false); clone.setInnerHTML(string); return (E) clone.getFirstElementChild(); } public static DocumentFragment toFragment(final String string) { final DocumentFragment frag = Browser.getDocument().createDocumentFragment(); final Element clone = (Element) X_Elemental.DIV.cloneNode(false); clone.setInnerHTML(string); for (Element element : ElementIterable.forEach(clone.getChildren())) { frag.appendChild(element); } return frag; } @MagicMethod(doNotVisit=true) public static <T, E extends Element> ConvertsValue<T, PotentialNode<E>> toElementBuilder( final Class<T> cls) { return SERVICE.get().toElementBuilder(cls); } @MagicMethod(doNotVisit=true) public static <T, E extends Element> ConvertsValue<T, PotentialNode<E>> toElementBuilder( final Class<T> model, final Class<?> template) { return SERVICE.get().toElementBuilder(model, template); } public static Iterable<Element> toElements(final String string) { final Element clone = (Element) X_Elemental.DIV.cloneNode(false); clone.setInnerHTML(string); return ElementIterable.forEach(clone.getChildNodes()); } static final DivElement DIV = Browser.getDocument().createDivElement(); private static final Provider<ElementalService> SERVICE = X_Inject .singletonLazy(ElementalService.class); private X_Elemental() {} public static void removeFromParent(Element e) { if (e.getParentElement() != null) { e.getParentElement().removeChild(e); } } public static Element getShadowRoot(Element element) { return getElementalService().getShadowRoot(element); } public static void reflow(Element e) { if (e != null) { Browser.getWindow().getComputedStyle(e, null); // triggers a reflow (recomputation of gui layout) for the given element. } } public static String escapeHTML(String html) { return getElementalService().escapeHTML(html); } /** * This method, in a browser, is fast, but insecure. * * It utilitizes a textarea's existing support for translating text into html entities, * and the testing done on the textarea shows that it can handle <script>alert('hack')</script>, * without running any script. */ public static String unescapeHTML(String html) { return getElementalService().unescapeHTML(html); } public static String getDataAttr(String ... parts) { StringBuilder b = new StringBuilder(); for (String part : parts) { for (String chunk : part.split("-")) { if (chunk.length() == 0) { // consider warning here; the use of -- seems fishy... continue; } if (b.length() == 0) { b.append(chunk); } else { b.append(Character.toUpperCase(chunk.charAt(0))); if (chunk.length() > 1) { b.append(chunk.substring(1)); } } } } return b.toString(); } public static void insertAfter(Element newNode, Element afterNode) { final Element parent = afterNode.getParentElement(); assert parent != null : "You cannot perform insertAfter() with a detached element to wrap"; final Element next = afterNode.getNextElementSibling(); if (next == null) { parent.appendChild(newNode); } else { parent.insertBefore(newNode, next); } } public static void insertAfter(Iterable<Element> newNodes, Element afterNode) { final Element parent = afterNode.getParentElement(); assert parent != null : "You cannot perform insertAfter() with a detached element to wrap"; final Element next = afterNode.getNextElementSibling(); if (next == null) { newNodes.forEach(parent::appendChild); } else { newNodes.forEach(e->parent.insertBefore(e, afterNode)); } } }