package org.nutz.lang.util;
import java.util.ArrayList;
import java.util.List;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings;
import org.nutz.lang.meta.Pair;
/**
* 简便的 Tag 实现
*
* @author zozoh(zozohtnt@gmail.com)
*/
public class Tag extends SimpleNode<HtmlToken> {
public static Tag tag(String name, String... attrs) {
return NEW(name).attrs(attrs);
}
public static Tag NEW(String name) {
Tag tag = new Tag();
tag.set(new HtmlToken().setName(name));
return tag;
}
public static Tag text(String text) {
Tag tag = new Tag();
if (null != text) {
text = text.replace("&", "&");
text = text.replace("<", "<").replace(">", ">");
}
tag.set(new HtmlToken().setValue(text));
return tag;
}
public boolean isBlock() {
return get().isBlock();
}
public boolean isInline() {
return get().isInline();
}
public boolean isNoChild() {
return get().isNoChild();
}
public boolean isHtml() {
return "html".equalsIgnoreCase(get().getName());
}
public boolean isBody() {
return "body".equalsIgnoreCase(get().getName());
}
public boolean isChildAllInline() {
if (!get().isElement())
return false;
for (Node<HtmlToken> ht : this.getChildren())
if (ht.get().isBlock())
return false;
return true;
}
public String name() {
return get().getName();
}
public Tag attr(String name, String value) {
get().attr(name, value);
return this;
}
public Tag attr(String name, int value) {
return attr(name, String.valueOf(value));
}
public Tag attrs(String... attrs) {
if (null != attrs) {
for (String attr : attrs) {
if (null != attr && attr.length() > 1) {
char c = attr.charAt(0);
switch (c) {
case '.':
this.addClass(attr.substring(1));
break;
case '#':
this.id(attr.substring(1));
break;
default:
Pair<String> p = Pair.create(attr);
this.attr(p.getName(), p.getValue());
}
}
}
}
return this;
}
public Tag addClass(String name) {
String cns = get().getAttrVal("class");
String[] nms = Strings.splitIgnoreBlank(cns, " ");
if (null == nms) {
get().attr("class", name);
} else {
if (!Lang.contains(nms, name)) {
get().attr("class", cns + " " + name);
}
}
return this;
}
public boolean hasClass(String name) {
String cns = get().getAttrVal("class");
if (null == cns || cns.length() < name.length())
return false;
return (" " + cns + " ").indexOf(" " + name + " ") != -1;
}
public Tag add(String tagName, String... attrs) {
Tag re = Tag.tag(tagName, attrs);
this.add(re);
return re;
}
public Tag id(String id) {
get().attr("id", id);
return this;
}
public String id() {
return get().getAttrVal("id");
}
public Tag setText(String text) {
this.add(Tag.text(text));
return this;
}
public List<Tag> childrenTag() {
List<Node<HtmlToken>> children = this.getChildren();
List<Tag> list = new ArrayList<Tag>(children.size());
for (Node<HtmlToken> nd : children) {
list.add((Tag) nd);
}
return list;
}
public String toString() {
return toString(0);
}
public String toString(int level) {
StringBuilder sb = new StringBuilder();
__join_to_string(sb, this, level, true);
return sb.toString();
}
public String toOuterHtml(boolean autoIndent) {
int level = autoIndent ? 0 : -1;
StringBuilder sb = new StringBuilder();
__join_to_string(sb, this, level, false);
return sb.toString();
}
public String toInnerHtml(boolean autoIndent) {
int level = autoIndent ? 0 : -1;
StringBuilder sb = new StringBuilder();
for (Node<HtmlToken> child : this.getChildren()) {
Tag childTag = (Tag) child;
HtmlToken token = childTag.get();
__join_to_string(sb, childTag, level, false);
if (token.isBlock() || token.isBody())
sb.append('\n');
}
return sb.toString();
}
private static void __join_to_string(StringBuilder sb,
Tag tag,
int level,
boolean closeNoChild) {
// 纯文本
if (tag.get().isText()) {
sb.append(tag.get().getValue());
return;
}
// 统一的缩进前缀
String prefix = level >= 0 ? Strings.dup(' ', level * 4) : null;
// 无子节点的标签
if (tag.isNoChild()) {
__join_tag_prefix(sb, tag, prefix);
sb.append('<').append(tag.name());
__join_attributes(sb, tag);
if (closeNoChild)
sb.append('/');
sb.append('>');
}
// 行内元素
else if (tag.isInline()) {
__join_tag_prefix(sb, tag, prefix);
__join_tag_begin(sb, tag);
for (Node<HtmlToken> child : tag.getChildren()) {
__join_to_string(sb, (Tag) child, level, closeNoChild);
}
__join_tag_end(sb, tag);
}
// 那么就是块元素咯
else {
__join_tag_prefix(sb, tag, prefix);
__join_tag_begin(sb, tag);
for (Node<HtmlToken> child : tag.getChildren()) {
Tag childTag = (Tag) child;
HtmlToken token = child.get();
if (token.isBlock() || token.isBody())
sb.append('\n');
__join_to_string(sb, childTag, level >= 0 ? level + 1 : level, closeNoChild);
}
sb.append('\n');
__join_tag_prefix(sb, tag, prefix);
__join_tag_end(sb, tag);
}
}
private static void __join_tag_prefix(StringBuilder sb, Tag tag, String prefix) {
if (null != prefix && prefix.length() > 0)
sb.append(prefix);
}
private static void __join_tag_begin(StringBuilder sb, Tag tag) {
sb.append('<').append(tag.name());
__join_attributes(sb, tag);
sb.append('>');
}
private static void __join_tag_end(StringBuilder sb, Tag tag) {
sb.append("</").append(tag.name()).append('>');
}
private static void __join_attributes(StringBuilder sb, Tag tag) {
for (Pair<String> attr : tag.get().getAttributes())
sb.append(' ').append(attr.toString());
}
}