/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.asual.summer.core.faces;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import javax.faces.view.Location;
import javax.faces.view.facelets.Tag;
import javax.faces.view.facelets.TagAttribute;
import javax.faces.view.facelets.TagDecorator;
import com.asual.summer.core.util.StringUtils;
import com.sun.faces.facelets.tag.TagAttributeImpl;
import com.sun.faces.facelets.tag.TagAttributesImpl;
import com.sun.faces.facelets.tag.jsf.html.HtmlDecorator;
/**
*
* @author Rostislav Hristov
*
*/
public final class FacesDecorator implements TagDecorator {
public final static String COMPOSITE = "http://www.asual.com/summer/composite";
public final static String STANDARD = "http://www.asual.com/summer/standard";
public final static String QNAME = "qName";
public final static String ATTRIBUTES = "dataEmpty|dataEmptyOption|dataRepeat|dataRepeatBegin|dataRepeatEnd|" +
"dataRepeatSize|dataRepeatStep|dataValue|dataVar|dataVarStatus|dataPack|dataEscape|dataError|dataLabel|dataLegend|dataTemplate.*";
private List<String> reservedTags = Arrays.asList(new String[] {
"repeat",
"tag",
"template"
});
private List<String> headTags = Arrays.asList(new String[] {
"base",
"link",
"meta",
"script",
"style"
//title
});
private List<String> bodyTags = Arrays.asList(new String[] {
"a",
"abbr",
"address",
"area",
"article",
"aside",
"audio",
"b",
"bdo",
"blockquote",
"body",
"br",
"button",
"canvas",
"caption",
"cite",
"code",
"col",
"colgroup",
"command",
"datalist",
"dd",
"del",
"details",
"dfn",
"div",
"dl",
"dt",
"em",
"embed",
//"fieldset",
"figcaption",
"figure",
"footer",
//"form",
"h1",
"h2",
"h3",
"h4",
"h5",
"h6",
//"head",
"header",
"hgroup",
"hr",
//"html",
"i",
"iframe",
"img",
"input",
"ins",
"keygen",
"kbd",
"label",
"legend",
"li",
"map",
"mark",
"menu",
"meter",
"nav",
"noscript",
"object",
"ol",
"optgroup",
"option",
"output",
"p",
"param",
"pre",
"progress",
"q",
"rp",
"rt",
"ruby",
"samp",
"section",
"select",
"small",
"source",
"span",
"strong",
"sub",
"summary",
"sup",
"table",
"tbody",
"td",
"textarea",
"tfoot",
"th",
"thead",
"time",
"tr",
"ul",
"var",
"video"
});
public FacesDecorator() {
super();
}
public Tag decorate(Tag tag) {
Location location = tag.getLocation();
String namespace = tag.getNamespace();
String qName = tag.getQName().toLowerCase();
TagAttributeImpl tagNameAttr = null;
TagAttributeImpl tagTargetAttr = null;
List<TagAttribute> attrs = new ArrayList<TagAttribute>(Arrays.asList(tag.getAttributes().getAll()));
Collections.sort(attrs, new Comparator<TagAttribute>() {
public int compare(TagAttribute ta1, TagAttribute ta2) {
return ta1.getQName().compareTo(ta2.getQName());
}
});
if (StringUtils.isEmpty(namespace) && !HtmlDecorator.XhtmlNamespace.equals(namespace) && !reservedTags.contains(qName)) {
String name = qName;
if (headTags.contains(qName)) {
name = "output";
tagNameAttr = new TagAttributeImpl(location, namespace, QNAME, QNAME, qName);
tagTargetAttr = new TagAttributeImpl(location, namespace, "target", "target", "head");
} else if (bodyTags.contains(qName)) {
name = "tag";
tagNameAttr = new TagAttributeImpl(location, namespace, QNAME, QNAME, qName);
}
for (TagAttribute attr : attrs) {
if ("data-error".equals(attr.getQName())) {
tagNameAttr = new TagAttributeImpl(location, namespace, QNAME, QNAME, qName);
name = qName;
} else if ("data-label".equals(attr.getQName()) && !StringUtils.isEmpty(attr.getValue())) {
tagNameAttr = new TagAttributeImpl(location, namespace, QNAME, QNAME, qName);
name = qName;
} else if ("data-template".equals(attr.getQName())) {
tagNameAttr = new TagAttributeImpl(location, namespace, QNAME, QNAME, qName);
name = "html".equals(qName) ? "html" : "template";
} else if ("data-repeat".equals(attr.getQName())) {
tagNameAttr = new TagAttributeImpl(location, namespace, QNAME, QNAME, qName);
if (!"select".equals(name)) {
name = "repeat";
}
} else if ("target".equals(attr.getQName())) {
tagTargetAttr = null;
}
if (attr.getQName().startsWith("data-") && !attr.getQName().equals("data-rendered")) {
String replace = convertName(attr.getQName());
if (replace.matches(ATTRIBUTES)) {
attrs.set(attrs.indexOf(attr),
new TagAttributeImpl(location, attr.getNamespace(), replace, replace, attr.getValue()));
}
}
if ("id".equals(attr.getQName())) {
if (attr.getValue().contains("${")) {
replaceAttr(attrs, attr, attr.getValue(), "id", "idx");
} else {
replaceAttr(attrs, attr, "${'" + attr.getValue() + "'}", "id", "idx");
}
}
replaceAttr(attrs, attr, attr.getValue(), "class", "styleClass");
replaceAttr(attrs, attr, attr.getValue(), "data-rendered", "rendered");
}
if (tagNameAttr != null) {
attrs.add(tagNameAttr);
}
if (tagTargetAttr != null) {
attrs.add(tagTargetAttr);
}
return new Tag(location, headTags.contains(qName) || "repeat".equals(name) ? STANDARD : COMPOSITE, name, name,
new TagAttributesImpl(attrs.toArray(new TagAttribute[] {})));
}
return tag;
}
private String convertName(String name) {
String[] parts = name.split("-");
int l = parts.length;
for (int i = 1; i < l; i++) {
parts[i] = StringUtils.toTitleCase(parts[i]);
}
return StringUtils.join(parts, "");
}
private void replaceAttr(List<TagAttribute> attrs, TagAttribute attr, String value, String search, String replace) {
if (search.equals(attr.getQName())) {
attrs.set(attrs.indexOf(attr), new TagAttributeImpl(
attr.getLocation(), attr.getNamespace(), replace, replace, value));
}
}
}