package xapi.dev.ui.html; import static xapi.collect.X_Collect.newList; import static xapi.collect.X_Collect.newStringMap; import javax.inject.Named; import xapi.annotation.compile.Import; import xapi.collect.api.IntTo; import xapi.collect.api.StringTo; import xapi.ui.html.api.Css; import xapi.ui.html.api.El; import xapi.ui.html.api.Html; import xapi.ui.html.api.HtmlTemplate; import xapi.ui.html.api.NoUi; import xapi.ui.html.api.Style; import com.google.gwt.core.ext.typeinfo.HasAnnotations; import com.google.gwt.core.ext.typeinfo.JClassType; import com.google.gwt.core.ext.typeinfo.JMethod; public class HtmlGeneratorNode { private final HasAnnotations source; private final String name; private final StringTo<HtmlGeneratorNode> children; private final IntTo<El> elements; final IntTo<HtmlTemplate> templates; private final StringTo<HtmlTemplate> namedTemplates; private final IntTo<Style> styles; private final IntTo<Css> css; private final IntTo<Import> imports; private final Html html; private String elementKey; private boolean dynamic = true; private HtmlGeneratorNode(HasAnnotations source, String name) { this.source = source; this.name = name; this.children = newStringMap(HtmlGeneratorNode.class); this.elements = newList(El.class); this.styles = newList(Style.class); this.namedTemplates = newStringMap(HtmlTemplate.class); this.templates = newList(HtmlTemplate.class); this.css = newList(Css.class); this.imports = newList(Import.class); this.html = source.getAnnotation(Html.class); addEl(source.getAnnotation(El.class)); if (html != null) { dynamic = html.isDynamic(); for (El e : html.body()) { addEl(e); } for (HtmlTemplate template : html.templates()) { addTemplate(template); } for (Css css : html.css()) { addCss(css); } } addTemplate(source.getAnnotation(HtmlTemplate.class)); addCss(source.getAnnotation(Css.class)); addStyle(source.getAnnotation(Style.class)); addImports(source.getAnnotation(Import.class)); } public HtmlGeneratorNode addTemplate(HtmlTemplate template) { if (template != null) { // TODO check if the template is import-based, text-based, or both. templates.add(template); addImports(template.imports()); if (template.name().length() > 0) { namedTemplates.put(template.name(), template); } Class<?>[] refs = template.references(); if (refs.length > 0) { } } return this; } public HtmlGeneratorNode addImports(Import ... imports) { if (imports.length > 0 && imports[0] != null) { this.imports.addAll(imports); } return this; } public HtmlGeneratorNode addStyle(Style ... style) { if (style.length > 0 && style[0] != null) { this.styles.addAll(style); } return this; } public HtmlGeneratorNode addCss(Css css) { if (css != null) { this.css.add(css); addStyle(css.style()); } return this; } public void addEl(El e) { if (e == null) { return; } elements.add(e); addStyle(e.style()); addImports(e.imports()); } public HtmlGeneratorNode(JClassType fromClass) { this(fromClass, fromClass.isAnnotationPresent(Named.class) ? fromClass.getAnnotation(Named.class).value() : fromClass.getSimpleSourceName()); for (JMethod method : fromClass.getMethods()) { if (isValidMethod(method)) { addChild(new HtmlGeneratorNode(method)); } } } protected boolean isValidMethod(JMethod method) { return method.isAnnotationPresent(NoUi.class) ? false : method.getParameterTypes().length == 0 || method.getAnnotation(Html.class) != null || method.getAnnotation(El.class) != null || method.getAnnotation(Css.class) != null || method.getAnnotation(Style.class) != null || method.getAnnotation(Import.class) != null || method.getAnnotation(HtmlTemplate.class) != null ; } public HtmlGeneratorNode(JMethod fromMethod) { this(fromMethod, fromMethod.isAnnotationPresent(Named.class) ? fromMethod.getAnnotation(Named.class).value() : fromMethod.getName()); } /** * @return the source */ public HasAnnotations getSource() { return source; } /** * @return the name */ public String getName() { return name; } public void addChild(HtmlGeneratorNode node) { children.put(node.getName(), node); } /** * @return the html */ public Html getHtml() { return html; } /** * @return the elements */ public Iterable<El> getElements() { return elements.forEach(); } /** * @return the css */ public Iterable<Css> getCss() { return css.forEach(); } /** * @return the imports */ public Iterable<Import> getImports() { return imports.forEach(); } /** * @return the styles */ public Iterable<Style> getStyles() { return styles.forEach(); } /** * @return if there are any elements */ public boolean hasElements() { return !elements.isEmpty(); } /** * @return if there are any css */ public boolean hasCss() { return !css.isEmpty(); } /** * @return if there are any imports */ public boolean hasImports() { return !imports.isEmpty(); } /** * @return if there are any styles */ public boolean hasStyles() { return !styles.isEmpty(); } public JClassType isClassType() { return source instanceof JClassType ? (JClassType)source : null; } public JMethod isMethodType() { return source instanceof JMethod ? (JMethod)source : null; } /** * @return the actual dom tag name to use for the generated node. * Html.ROOT_ELEMENT is translated to "div" */ public String rootElementTag() { return html == null ? elements.isEmpty() ? El.DIV : elements.at(0).tag() : html.document().equals(Html.ROOT_ELEMENT) ? El.DIV : html.document(); } public boolean isEmpty() { if (html == null) { return elements.isEmpty(); } if (elements.isEmpty()) { // yes, an == reference; // In case you want to use "x-root" as an element, // the only document value you should use for "empty" // is a reference to Html.ROOT_ELEMENT if (html.document().equals(Html.ROOT_ELEMENT)) { return templates.isEmpty(); } } return false; } public String escape(String template, String methodName, String accessor) { int ind = template.indexOf('$'); if (ind >= 0) { // // return } return template; } public boolean hasTemplates() { return !templates.isEmpty(); } public Iterable<HtmlTemplate> getTemplates() { return templates.forEach(); } public HtmlGeneratorNode getNode(String name) { return children.get(name); } public void setNameElement(String elementKey) { this.elementKey = elementKey; } /** * @return the elementKey */ public String getNameElement() { return elementKey; } public boolean hasChildren() { for (HtmlTemplate template : getTemplates()) { if (template.wrapsChildren()) { return true; } } for (El el : getElements()) { for(String html : el.html()) { if (html.contains(HtmlTemplate.KEY_CHILDREN)) { return true; } } } return false; } public boolean isDynamic() { return dynamic ; } }