/* * 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)); } } }