/*
* 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.lesspack;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import javax.faces.application.ProjectStage;
import javax.faces.component.UIComponent;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import com.asual.lesscss.ResourcePackage;
import com.asual.summer.core.faces.HeadRenderer;
import com.asual.summer.core.util.RequestUtils;
import com.asual.summer.core.util.ResourceUtils;
/**
*
* @author Rostislav Hristov
*
*/
public class HeadPackRenderer extends HeadRenderer {
protected void encodeHeadResources(FacesContext context, UIComponent component) throws IOException {
if (context.isProjectStage(ProjectStage.Production)) {
ResponseWriter writer = context.getResponseWriter();
UIViewRoot viewRoot = context.getViewRoot();
ListIterator<?> iter = (viewRoot.getComponentResources(context, "head")).listIterator();
List<UIComponent> styleComponents = new ArrayList<UIComponent>();
List<UIComponent> scriptComponents = new ArrayList<UIComponent>();
List<UIComponent> tagComponents = new ArrayList<UIComponent>();
while (iter.hasNext()) {
UIComponent resource = (UIComponent) iter.next();
if (isStyle(resource)) {
if (isUnique(styleComponents, resource)) {
styleComponents.add(resource);
}
} else if (isScript(resource)) {
if (isUnique(scriptComponents, resource)) {
scriptComponents.add(resource);
}
} else {
tagComponents.add(resource);
}
}
for (UIComponent c : tagComponents) {
c.encodeAll(context);
}
String version = (String) ResourceUtils.getProperty("app.version");
String dataPack = null;
List<String> styles = new ArrayList<String>();
List<String> scripts = new ArrayList<String>();
sortByPack(styleComponents);
for (UIComponent c : styleComponents) {
if (c.isRendered()) {
Map<String, Object> attrs = c.getAttributes();
String href = (String) attrs.get("href");
String pkg = (String) attrs.get("dataPack");
if (href != null) {
preEncodeAll(context, c);
if (dataPack != null && !dataPack.equals(pkg)) {
combineStyles(writer, component, styles, dataPack, version);
}
dataPack = pkg;
styles.add(href);
} else {
combineStyles(writer, component, styles, dataPack, version);
preEncodeAll(context, c);
postEncodeAll(context, c);
}
}
}
combineStyles(writer, component, styles, dataPack, version);
dataPack = null;
sortByPack(scriptComponents);
for (UIComponent c : scriptComponents) {
if (c.isRendered()) {
Map<String, Object> attrs = c.getAttributes();
String src = (String) attrs.get("src");
String pkg = (String) attrs.get("dataPack");
if (src != null) {
preEncodeAll(context, c);
if (dataPack != null && !dataPack.equals(pkg)) {
combineScripts(writer, component, scripts, dataPack, version);
}
dataPack = pkg;
scripts.add(src);
} else {
combineScripts(writer, component, scripts, dataPack, version);
preEncodeAll(context, c);
postEncodeAll(context, c);
}
}
}
combineScripts(writer, component, scripts, dataPack, version);
} else {
super.encodeHeadResources(context, component);
}
}
private void preEncodeAll(FacesContext context, UIComponent component) throws IOException {
if (context == null) {
throw new NullPointerException();
}
if (!component.isRendered()) {
return;
}
Map<String, Object> attrs = component.getAttributes();
if ((isStyle(component) && attrs.get("href") == null) ||
(isScript(component) && attrs.get("src") == null)) {
component.encodeBegin(context);
}
}
private void postEncodeAll(FacesContext context, UIComponent component) throws IOException {
if (component.getRendersChildren()) {
component.encodeChildren(context);
} else if (component.getChildCount() > 0) {
for (UIComponent kid : component.getChildren()) {
kid.encodeAll(context);
}
}
Map<String, Object> attrs = component.getAttributes();
if ((isStyle(component) && attrs.get("href") == null) ||
(isScript(component) && attrs.get("src") == null)) {
component.encodeEnd(context);
}
}
private void writeStyle(ResponseWriter writer, UIComponent component, String href) throws IOException {
writer.startElement("link", component);
writer.writeAttribute("type", "text/css", "type");
writer.writeAttribute("rel", "stylesheet", "rel");
writer.writeAttribute("href", href, "href");
writer.endElement("link");
}
private void writeScript(ResponseWriter writer, UIComponent component, String src) throws IOException {
writer.startElement("script", component);
writer.writeAttribute("type", "text/javascript", "type");
writer.writeAttribute("src", src, "src");
writer.endElement("script");
}
private void combineStyles(ResponseWriter writer, UIComponent component, List<String> styles, String name, String version) throws IOException {
String type = "css";
List<String> pack = new ArrayList<String>();
for (String href : styles) {
if (href.startsWith("http") || !href.startsWith("/" + type)) {
writeStyle(writer, component, href);
} else {
pack.add(href);
}
}
if (pack.size() != 0) {
ResourcePackage rp = new ResourcePackage(pack.toArray(new String[]{}));
rp.setName(name);
rp.setVersion(version);
rp.setExtension(type);
writeStyle(writer, component, RequestUtils.contextRelative("/" + type + rp, true));
}
styles.clear();
}
private void combineScripts(ResponseWriter writer, UIComponent component, List<String> scripts, String name, String version) throws IOException {
String type = "js";
List<String> pack = new ArrayList<String>();
for (String src : scripts) {
if (src.startsWith("http") || !src.startsWith("/" + type)) {
writeScript(writer, component, src);
} else {
pack.add(src);
}
}
if (pack.size() != 0) {
ResourcePackage rp = new ResourcePackage(pack.toArray(new String[]{}));
rp.setName(name);
rp.setVersion(version);
rp.setExtension(type);
writeScript(writer, component, RequestUtils.contextRelative("/" + type + rp, true));
}
scripts.clear();
}
}