Author: amarkhel
Date: 2010-05-12 13:42:44 -0400 (Wed, 12 May 2010)
New Revision: 17005
Added:
root/core/trunk/impl/src/test/resources/resources/charset.css
root/core/trunk/impl/src/test/resources/resources/charset.ecss
root/core/trunk/impl/src/test/resources/resources/fake.css
root/core/trunk/impl/src/test/resources/resources/fake.ecss
root/core/trunk/impl/src/test/resources/resources/fake2.css
root/core/trunk/impl/src/test/resources/resources/fake2.ecss
root/core/trunk/impl/src/test/resources/resources/fontface.css
root/core/trunk/impl/src/test/resources/resources/fontface.ecss
root/core/trunk/impl/src/test/resources/resources/full.css
root/core/trunk/impl/src/test/resources/resources/full.ecss
root/core/trunk/impl/src/test/resources/resources/import.css
root/core/trunk/impl/src/test/resources/resources/import.ecss
root/core/trunk/impl/src/test/resources/resources/importedEL.css
root/core/trunk/impl/src/test/resources/resources/importedEL.ecss
root/core/trunk/impl/src/test/resources/resources/media.css
root/core/trunk/impl/src/test/resources/resources/media.ecss
root/core/trunk/impl/src/test/resources/resources/page.css
root/core/trunk/impl/src/test/resources/resources/page.ecss
root/core/trunk/impl/src/test/resources/resources/resource.css
root/core/trunk/impl/src/test/resources/resources/resource.ecss
root/core/trunk/impl/src/test/resources/resources/selector.css
root/core/trunk/impl/src/test/resources/resources/selector.ecss
root/core/trunk/impl/src/test/resources/resources/skin.css
root/core/trunk/impl/src/test/resources/resources/skin.ecss
root/ui/core/trunk/api/src/main/java/org/richfaces/renderkit/html/AttachQueueRenderer.java
root/ui/core/trunk/api/src/main/java/org/richfaces/renderkit/html/QueueRendererBase.java
root/ui/core/trunk/api/src/test/java/org/richfaces/component/QueueRendererTest.java
root/ui/core/trunk/api/src/test/resources/org/ajax4jsf/component/nonQueue.xhtml
root/ui/core/trunk/api/src/test/resources/org/ajax4jsf/component/queue.xhtml
Modified:
root/core/trunk/api/src/main/java/org/ajax4jsf/javascript/ScriptUtils.java
root/core/trunk/impl/src/main/java/org/ajax4jsf/component/QueueRegistry.java
root/core/trunk/impl/src/main/java/org/ajax4jsf/context/ContextInitParameters.java
root/core/trunk/impl/src/main/java/org/ajax4jsf/renderkit/AjaxRendererUtils.java
root/core/trunk/impl/src/main/java/org/ajax4jsf/util/ELUtils.java
root/core/trunk/impl/src/main/java/org/richfaces/context/PreRenderViewListener.java
root/core/trunk/impl/src/main/java/org/richfaces/resource/AbstractBaseResource.java
root/core/trunk/impl/src/main/java/org/richfaces/resource/CompiledCSSResource.java
root/core/trunk/impl/src/main/java/org/richfaces/resource/ResourceHandlerImpl.java
root/core/trunk/impl/src/main/java/org/richfaces/resource/Xcss2EcssConverter.java
root/core/trunk/impl/src/main/java/org/richfaces/resource/css/CSSVisitorImpl.java
root/core/trunk/impl/src/main/resources/META-INF/resources/basic_both.ecss
root/core/trunk/impl/src/main/resources/META-INF/resources/basic_classes.ecss
root/core/trunk/impl/src/main/resources/META-INF/resources/extended.ecss
root/core/trunk/impl/src/main/resources/META-INF/resources/extended_both.ecss
root/core/trunk/impl/src/main/resources/META-INF/resources/extended_classes.ecss
root/core/trunk/impl/src/test/java/org/richfaces/resource/ResourceHandlerImplTest.java
root/ui/core/trunk/api/src/main/java/org/richfaces/component/AbstractAttachQueue.java
root/ui/core/trunk/api/src/main/java/org/richfaces/component/AbstractQueue.java
root/ui/core/trunk/api/src/main/java/org/richfaces/renderkit/html/QueueRenderer.java
Log:
Refactor skins and migrate queue code from 3.3.x
Modified: root/core/trunk/api/src/main/java/org/ajax4jsf/javascript/ScriptUtils.java
===================================================================
--- root/core/trunk/api/src/main/java/org/ajax4jsf/javascript/ScriptUtils.java 2010-05-12
14:25:10 UTC (rev 17004)
+++ root/core/trunk/api/src/main/java/org/ajax4jsf/javascript/ScriptUtils.java 2010-05-12
17:42:44 UTC (rev 17005)
@@ -331,4 +331,58 @@
return buf == null ? s : buf.toString();
}
+
+ public static boolean shouldRenderAttribute(Object attributeVal) {
+ if (null == attributeVal) {
+ return false;
+ } else if (attributeVal instanceof Boolean
+ && ((Boolean) attributeVal).booleanValue() == Boolean.FALSE
+ .booleanValue()) {
+ return false;
+ } else if (attributeVal.toString().length() == 0) {
+ return false;
+ } else
+ return isValidProperty(attributeVal);
+ }
+
+ public static boolean shouldRenderAttribute(String attributeName, Object
attributeVal) {
+ return shouldRenderAttribute(attributeVal);
+ }
+
+ /**
+ * Test for valid value of property. by default, for non-setted properties
+ * with Java primitive types of JSF component return appropriate MIN_VALUE .
+ *
+ * @param property -
+ * value of property returned from
+ * {@link UIComponent#getAttributes()}
+ * @return true for setted property, false otherthise.
+ */
+ public static boolean isValidProperty(Object property) {
+ if (null == property) {
+ return false;
+ } else if (property instanceof Integer
+ && ((Integer) property).intValue() == Integer.MIN_VALUE) {
+ return false;
+ } else if (property instanceof Double
+ && ((Double) property).doubleValue() == Double.MIN_VALUE) {
+ return false;
+ } else if (property instanceof Character
+ && ((Character) property).charValue() == Character.MIN_VALUE) {
+ return false;
+ } else if (property instanceof Float
+ && ((Float) property).floatValue() == Float.MIN_VALUE) {
+ return false;
+ } else if (property instanceof Short
+ && ((Short) property).shortValue() == Short.MIN_VALUE) {
+ return false;
+ } else if (property instanceof Byte
+ && ((Byte) property).byteValue() == Byte.MIN_VALUE) {
+ return false;
+ } else if (property instanceof Long
+ && ((Long) property).longValue() == Long.MIN_VALUE) {
+ return false;
+ }
+ return true;
+ }
}
Modified: root/core/trunk/impl/src/main/java/org/ajax4jsf/component/QueueRegistry.java
===================================================================
---
root/core/trunk/impl/src/main/java/org/ajax4jsf/component/QueueRegistry.java 2010-05-12
14:25:10 UTC (rev 17004)
+++
root/core/trunk/impl/src/main/java/org/ajax4jsf/component/QueueRegistry.java 2010-05-12
17:42:44 UTC (rev 17005)
@@ -21,20 +21,19 @@
package org.ajax4jsf.component;
-import javax.faces.context.ExternalContext;
-import javax.faces.context.FacesContext;
import java.util.LinkedHashMap;
import java.util.Map;
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+
/**
* @author Nick Belaevski
* @since 3.3.0
*/
public final class QueueRegistry {
private static final String REGISTRY_ATTRIBUTE_NAME = QueueRegistry.class.getName();
- private boolean shouldCreateDefaultGlobalQueue = false;
private Map<String, Object> queuesData = new LinkedHashMap<String,
Object>();
-
private QueueRegistry() {
}
@@ -54,10 +53,16 @@
public void registerQueue(FacesContext context, String clientName, Object data) {
if (!containsQueue(clientName)) {
queuesData.put(clientName, data);
- } else {
+ }else{
context.getExternalContext().log("Queue with name '" +
clientName + "' has already been registered");
}
}
+
+ public void removeQueue(FacesContext context, String clientName) {
+ if (!containsQueue(clientName)) {
+ queuesData.remove(clientName);
+ }
+ }
public boolean containsQueue(String name) {
return queuesData.containsKey(name);
@@ -67,15 +72,7 @@
return queuesData;
}
- public void setShouldCreateDefaultGlobalQueue() {
- this.shouldCreateDefaultGlobalQueue = true;
- }
-
- public boolean isShouldCreateDefaultGlobalQueue() {
- return shouldCreateDefaultGlobalQueue;
- }
-
public boolean hasQueuesToEncode() {
- return shouldCreateDefaultGlobalQueue || !queuesData.isEmpty();
+ return !queuesData.isEmpty();
}
-}
+}
\ No newline at end of file
Modified:
root/core/trunk/impl/src/main/java/org/ajax4jsf/context/ContextInitParameters.java
===================================================================
---
root/core/trunk/impl/src/main/java/org/ajax4jsf/context/ContextInitParameters.java 2010-05-12
14:25:10 UTC (rev 17004)
+++
root/core/trunk/impl/src/main/java/org/ajax4jsf/context/ContextInitParameters.java 2010-05-12
17:42:44 UTC (rev 17005)
@@ -42,6 +42,7 @@
public static final String[] STD_CONTROLS_SKINNING_PARAM =
{"org.richfaces.CONTROL_SKINNING"};
public static final String[] STD_CONTROLS_SKINNING_CLASSES_PARAM =
{"org.richfaces.CONTROL_SKINNING_CLASSES"};
public static final String[] CONTROL_SKINNING_LEVEL =
{"org.richfaces.CONTROL_SKINNING_LEVEL"};
+ public static final String[] GLOBAL_QUEUE_ENABLED =
{"org.richfaces.queue.enabled"};
/**
*
*/
@@ -68,6 +69,16 @@
* @param context
* @return value of CONTROL_SKINNING_LEVEL parameter if present
*/
+ public static boolean isGlobalQueueEnabled(FacesContext context) {
+ return getBoolean(context, GLOBAL_QUEUE_ENABLED, true);
+ }
+
+ /**
+ * Defines what the skinning level used
+ *
+ * @param context
+ * @return value of CONTROL_SKINNING_LEVEL parameter if present
+ */
public static String getSkinningLevel(FacesContext context) {
return getInitParameter(context, CONTROL_SKINNING_LEVEL);
}
Modified:
root/core/trunk/impl/src/main/java/org/ajax4jsf/renderkit/AjaxRendererUtils.java
===================================================================
---
root/core/trunk/impl/src/main/java/org/ajax4jsf/renderkit/AjaxRendererUtils.java 2010-05-12
14:25:10 UTC (rev 17004)
+++
root/core/trunk/impl/src/main/java/org/ajax4jsf/renderkit/AjaxRendererUtils.java 2010-05-12
17:42:44 UTC (rev 17005)
@@ -171,6 +171,12 @@
return behavior.getOnerror();
}
},
+ queueId {
+ @Override
+ public String getAttributeValue(AjaxClientBehavior behavior) {
+ return behavior.getQueueId();
+ }
+ },
event {
@Override
public String getAttributeValue(AjaxClientBehavior behavior) {
Modified: root/core/trunk/impl/src/main/java/org/ajax4jsf/util/ELUtils.java
===================================================================
--- root/core/trunk/impl/src/main/java/org/ajax4jsf/util/ELUtils.java 2010-05-12 14:25:10
UTC (rev 17004)
+++ root/core/trunk/impl/src/main/java/org/ajax4jsf/util/ELUtils.java 2010-05-12 17:42:44
UTC (rev 17005)
@@ -78,6 +78,27 @@
return false;
}
+ public static Object evaluateValueExpression(ValueExpression expression, ELContext
elContext) {
+
+ if (expression.isLiteralText()) {
+ return expression.getExpressionString();
+ } else {
+ return expression.getValue(elContext);
+ }
+
+ }
+
+ public static ValueExpression createValueExpression(String expression) {
+
+ return createValueExpression(expression, Object.class);
+
+ }
+
+ public static ValueExpression createValueExpression(String expression, Class<?>
expectedType) {
+ FacesContext context = FacesContext.getCurrentInstance();
+ return
context.getApplication().getExpressionFactory().createValueExpression(context.getELContext(),
expression, expectedType);
+ }
+
private static Class<?> resolveType(Type type) {
Class<?> result = Object.class;
Modified:
root/core/trunk/impl/src/main/java/org/richfaces/context/PreRenderViewListener.java
===================================================================
---
root/core/trunk/impl/src/main/java/org/richfaces/context/PreRenderViewListener.java 2010-05-12
14:25:10 UTC (rev 17004)
+++
root/core/trunk/impl/src/main/java/org/richfaces/context/PreRenderViewListener.java 2010-05-12
17:42:44 UTC (rev 17005)
@@ -21,8 +21,15 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.ajax4jsf.component.QueueRegistry;
import org.ajax4jsf.context.ContextInitParameters;
+import org.ajax4jsf.javascript.ScriptUtils;
+import javax.faces.component.UIComponent;
import javax.faces.component.UIOutput;
import javax.faces.context.FacesContext;
import javax.faces.event.AbortProcessingException;
@@ -30,15 +37,31 @@
import javax.faces.event.SystemEvent;
import javax.faces.event.SystemEventListener;
+import org.richfaces.resource.CompiledCSSResource;
+
/**
- * This class used for determining what standard skinning resources should be encoded.
- * Implements SystemEventListener and reacts on PreRenderViewEvent
- *
+ * This class used for determining what standard resources should be encoded(queue,
skinning etc.). Implements SystemEventListener
+ * and reacts on PreRenderViewEvent
+ *
* @author amarkhel
* @since 4.0
*/
public class PreRenderViewListener implements SystemEventListener {
+ private static final String MARKER_ATTRIBBUTE = "marker";
+
+ private static final String FUNCTION_END = ");";
+
+ private static final String FUNCTION_NAME =
"RichFaces.queue.setQueueOptions(";
+
+ private static final String SCRIPT_END = "</script>";
+
+ private static final String SCRIPT_START = "<script
type=\"text/javascript\">";
+
+ private static final String QUEUE_RESOURCE = "richFacesQueueResource";
+
+ private static final String VALUE_ATTRIBBUTE = "value";
+
private static final String BASIC = "basic";
private static final String EXTENDED = "extended";
@@ -57,11 +80,10 @@
private static final String STYLESHEET_RENDERER =
"javax.faces.resource.Stylesheet";
- // private static final Logger LOG = RichfacesLogger.APPLICATION.getLogger();
private boolean useStdControlsSkinning;
private boolean useStdControlsSkinningClasses;
-
+
private boolean extendedSkinningAllowed;
/*
@@ -73,6 +95,19 @@
return true;
}
+ /*
+ * (non-Javadoc)
+ *
+ * @see
javax.faces.event.SystemEventListener#processEvent(javax.faces.event.SystemEvent)
+ */
+ public void processEvent(SystemEvent event) throws AbortProcessingException {
+
+ if (event instanceof PreRenderViewEvent) {
+ encodeSkinningResources();
+ encodeQueueResource();
+ }
+ }
+
private void setUseStdControlsSkinning(boolean stdControlsSkinning) {
this.useStdControlsSkinning = stdControlsSkinning;
}
@@ -85,7 +120,7 @@
this.extendedSkinningAllowed = extendedSkinningAllowed;
}
- private void initialize(FacesContext context) {
+ private void initializeSkinningParameters(FacesContext context) {
boolean extendedSkinningAllowed = true;
String skinningLevel = ContextInitParameters.getSkinningLevel(context);
if (skinningLevel != null && skinningLevel.length() > 0) {
@@ -120,47 +155,155 @@
}
- /*
- * (non-Javadoc)
- *
- * @see
javax.faces.event.SystemEventListener#processEvent(javax.faces.event.SystemEvent)
- */
- public void processEvent(SystemEvent event) throws AbortProcessingException {
-
- if (event instanceof PreRenderViewEvent) {
- initialize(FacesContext.getCurrentInstance());
- String resourceSuffix = null;
-
- if (useStdControlsSkinning) {
- if (useStdControlsSkinningClasses) {
- resourceSuffix = BOTH_ECSS;
+ private void encodeQueueResource() {
+ FacesContext context = FacesContext.getCurrentInstance();
+ if (QueueRegistry.getInstance(context).hasQueuesToEncode()) {
+ StringBuilder sb = constructQueueScript(context);
+ addQueueResourceToView(context, sb);
+ }
+ }
+
+ private void addQueueResourceToView(FacesContext context, StringBuilder sb) {
+ removeComponentResource(context, QUEUE_RESOURCE);
+ HashMap<String, Object> hashMap = new HashMap<String, Object>();
+ hashMap.put(MARKER_ATTRIBBUTE, QUEUE_RESOURCE);
+ hashMap.put(VALUE_ATTRIBBUTE, sb.toString());
+ addComponentResource(context, hashMap, null);
+ }
+
+ private StringBuilder constructQueueScript(FacesContext context) {
+ StringBuilder sb = new StringBuilder(1024);
+ sb.append(SCRIPT_START);
+ sb.append(FUNCTION_NAME);
+ sb.append("{");
+ addParameter(context, sb);
+ sb.append("}");
+ sb.append(FUNCTION_END);
+ sb.append(SCRIPT_END);
+ return sb;
+ }
+
+ private void addParameter(FacesContext context, StringBuilder sb) {
+ Map<String, Object> registeredQueues =
QueueRegistry.getInstance(context).getRegisteredQueues(context);
+ boolean firstElementAdded = false;
+ for (Map.Entry<String, Object> queue : registeredQueues.entrySet()) {
+ UIComponent queueComp = (UIComponent) queue.getValue();
+ firstElementAdded = appendQueueName(sb, firstElementAdded, queue);
+ appendQueueOptions(sb, queueComp);
+ }
+ }
+
+ private void appendQueueOptions(StringBuilder sb, UIComponent queueComp) {
+ boolean firstAttribbuteAdded = false;
+ for (QueueOptions queueOption : QueueOptions.values()) {
+ String attribbute = queueOption.name();
+ if (shouldRenderOption(queueComp, attribbute)) {
+ if (firstAttribbuteAdded) {
+ sb.append(",");
} else {
- resourceSuffix = ECSS;
+ firstAttribbuteAdded = true;
}
- } else {
- if (useStdControlsSkinningClasses) {
- resourceSuffix = CLASSES_ECSS;
- } else {
- // no resources
- }
+ sb.append(attribbute);
+ sb.append(":'");
+ sb.append(queueComp.getAttributes().get(attribbute));
+ sb.append("'");
}
+ }
+ sb.append("}");
+ }
- if (resourceSuffix != null) {
- addResource("basic".concat(resourceSuffix));
+ private boolean shouldRenderOption(UIComponent queueComp, String attribbute) {
+ return queueComp.getAttributes().get(attribbute) != null
+ && ScriptUtils.shouldRenderAttribute(attribbute,
queueComp.getAttributes().get(attribbute));
+ }
- if (extendedSkinningAllowed) {
- addResource("extended".concat(resourceSuffix));
- }
+ private boolean appendQueueName(StringBuilder sb, boolean firstElementAdded,
Map.Entry<String, Object> queue) {
+ if (firstElementAdded) {
+ sb.append(",");
+ } else {
+ firstElementAdded = true;
+ }
+ sb.append("'");
+ sb.append(queue.getKey());
+ sb.append("'");
+ sb.append(":{");
+ return firstElementAdded;
+ }
+
+ private void encodeSkinningResources() {
+ initializeSkinningParameters(FacesContext.getCurrentInstance());
+ String resourceSuffix = findResourceSuffix();
+
+ if (resourceSuffix != null) {
+ encodeSkinningResource(BASIC, resourceSuffix);
+
+ if (extendedSkinningAllowed) {
+ encodeSkinningResource(EXTENDED, resourceSuffix);
}
}
}
- private void addResource(String name) {
+ private void encodeSkinningResource(String resourcePrefix, String resourceSuffix) {
+ String basicPath = resourcePrefix.concat(resourceSuffix);
+ String fullPath = basicPath.concat(CompiledCSSResource.getHash(basicPath));
+ addSkinningResourceToView(basicPath, fullPath);
+ }
+
+ private String findResourceSuffix() {
+ String resourceSuffix = null;
+
+ if (useStdControlsSkinning) {
+ if (useStdControlsSkinningClasses) {
+ resourceSuffix = BOTH_ECSS;
+ } else {
+ resourceSuffix = ECSS;
+ }
+ } else {
+ if (useStdControlsSkinningClasses) {
+ resourceSuffix = CLASSES_ECSS;
+ } else {
+ // no resources
+ }
+ }
+ return resourceSuffix;
+ }
+
+ private void addSkinningResourceToView(String basePath, String fullPath) {
FacesContext context = FacesContext.getCurrentInstance();
+ removeComponentResource(context, basePath);
+ HashMap<String, Object> hashMap = new HashMap<String, Object>();
+ hashMap.put(MARKER_ATTRIBBUTE, basePath);
+ hashMap.put(NAME_ATTRIBBUTE, fullPath);
+ addComponentResource(context, hashMap, STYLESHEET_RENDERER);
+
+ }
+
+ private void addComponentResource(FacesContext context, Map<String, Object>
params, String rendererType){
UIOutput output = new UIOutput();
- output.setRendererType(STYLESHEET_RENDERER);
- output.getAttributes().put(NAME_ATTRIBBUTE, name);
+ if(rendererType != null){
+ output.setRendererType(rendererType);
+ }
+ for(Map.Entry<String, Object> parameter : params.entrySet()){
+ output.getAttributes().put(parameter.getKey(), parameter.getValue());
+ }
context.getViewRoot().addComponentResource(context, output, HEAD);
}
+
+ private void removeComponentResource(FacesContext context, String resourceId){
+ List<UIComponent> result =
context.getViewRoot().getComponentResources(context, HEAD);
+ for (UIComponent resource : result) {
+ if(resource.getAttributes().get(MARKER_ATTRIBBUTE) != null){
+ String resourceName =
resource.getAttributes().get(MARKER_ATTRIBBUTE).toString();
+ if (resourceName.equals(resourceId)) {
+ context.getViewRoot().removeComponentResource(context, resource,
HEAD);
+ break;
+ }
+ }
+ }
+ }
+ protected static enum QueueOptions {
+ onbeforedomupdate, oncomplete, onerror, onevent, onrequestdequeue,
onrequestqueue, onsubmit, requestDelay, timeout, status, queueId, ignoreDupResponses,
requestGroupingId
-}
+ }
+
+}
\ No newline at end of file
Modified:
root/core/trunk/impl/src/main/java/org/richfaces/resource/AbstractBaseResource.java
===================================================================
---
root/core/trunk/impl/src/main/java/org/richfaces/resource/AbstractBaseResource.java 2010-05-12
14:25:10 UTC (rev 17004)
+++
root/core/trunk/impl/src/main/java/org/richfaces/resource/AbstractBaseResource.java 2010-05-12
17:42:44 UTC (rev 17005)
@@ -150,7 +150,7 @@
return null;
}
- private ClassLoader getClassLoader() {
+ protected ClassLoader getClassLoader() {
Class<? extends AbstractBaseResource> thisClass = getClass();
ClassLoader classLoader = thisClass.getClassLoader();
Modified:
root/core/trunk/impl/src/main/java/org/richfaces/resource/CompiledCSSResource.java
===================================================================
---
root/core/trunk/impl/src/main/java/org/richfaces/resource/CompiledCSSResource.java 2010-05-12
14:25:10 UTC (rev 17004)
+++
root/core/trunk/impl/src/main/java/org/richfaces/resource/CompiledCSSResource.java 2010-05-12
17:42:44 UTC (rev 17005)
@@ -21,19 +21,12 @@
*/
package org.richfaces.resource;
-import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.MessageFormat;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.regex.Pattern;
-import javax.el.ELContext;
-import javax.el.ELException;
-import javax.el.ValueExpression;
import javax.faces.application.ProjectStage;
import javax.faces.application.Resource;
import javax.faces.context.FacesContext;
@@ -52,49 +45,87 @@
import com.steadystate.css.parser.CSSOMParser;
/**
- * @author amarkhel
- * Class, that represented dynamic CSS resource.
+ * @author amarkhel Class, that represented dynamic CSS resource.
*/
public class CompiledCSSResource extends AbstractBaseResource {
- private static final String SKIN = "?skin=";
+ private static final String ECSS = ".ecss";
+ private static final String CLASSPATH_BASE_PATH = "META-INF/resources/";
+
+ private static final String WEBAPP_BASE_PATH = "/resources/";
+
private static final Logger LOGGER = RichfacesLogger.RESOURCE.getLogger();
- private static final String INVALID_RESOURCE_FORMAT_COLON_ERROR =
- "Invalid resource format. Property ''{0}'' contains
more than one colon (:).";
- private static final String INVALID_RESOURCE_FORMAT_NO_LIBRARY_NAME_ERROR =
- "Invalid resource format. Property ''{0}'' cannot be
parsed to extract resource name and library name.";
- private static final String INVALID_RESOURCE_FORMAT_ERROR =
- "Invalid resource format. Property ''{0}'' cannot be
parsed.";
- private static final String NULL_STYLESHEET =
- "Parsed stylesheet for ''{0}'':''{1}''
resource is null.";
+ private static final String NULL_STYLESHEET = "Parsed stylesheet for
''{0}'':''{1}'' resource is null.";
- private Resource resourceDelegate;
+ private String resourcePath;
- public CompiledCSSResource(Resource resource) {
- this.resourceDelegate = resource;
+ public CompiledCSSResource(String resourcePath) {
+ this.resourcePath = resourcePath;
}
+ @Override
+ public String getResourceName() {
+ return this.resourcePath;
+ }
+
+ public InputStream getResourceInputStream() throws IOException {
+ String path = null;
+ if (this.resourcePath.indexOf(ECSS) != -1) {
+ path = this.resourcePath.substring(0, this.resourcePath.lastIndexOf(ECSS) +
ECSS.length());
+ } else {
+ LOGGER.error("This resource is not properly dynamic resource : " +
getResourceName());
+ return null;
+ }
+ InputStream in = null;
+ try {
+ in =
FacesContext.getCurrentInstance().getExternalContext().getResourceAsStream(WEBAPP_BASE_PATH
+ path);
+ } catch (Exception e) {
+ // Normal situation, resource not found in webapp resources
+ }
+
+ if (in != null) {
+ return in;
+ }
+ ClassLoader loader = getClassLoader();
+ in = loader.getResourceAsStream(CLASSPATH_BASE_PATH + path);
+ if (in == null) {
+ // try using this class' loader (necessary when running in OSGi)
+ in = this.getClass().getClassLoader().getResourceAsStream(CLASSPATH_BASE_PATH
+ path);
+ }
+ return in;
+
+ }
+
+ public static ClassLoader getCurrentLoader(Object fallbackClass) {
+ ClassLoader loader = Thread.currentThread().getContextClassLoader();
+ if (loader == null) {
+ loader = fallbackClass.getClass().getClassLoader();
+ }
+ return loader;
+ }
+
+ @Override
public InputStream getInputStream() throws IOException {
FacesContext ctx = FacesContext.getCurrentInstance();
InputStream stream = null;
CSSStyleSheet styleSheet = null;
try {
- stream = new BufferedInputStream(
- new ELEvaluatingInputStream(ctx,
- resourceDelegate,
- resourceDelegate.getInputStream()));
-
+ stream = getResourceInputStream();
+ if (null == stream) {
+ return null;
+ }
InputSource source = new InputSource(new InputStreamReader(stream));
CSSOMParser parser = new CSSOMParser();
- ErrorHandlerImpl errorHandler = new ErrorHandlerImpl(resourceDelegate,
- ctx.isProjectStage(ProjectStage.Production));
+ ErrorHandlerImpl errorHandler = new ErrorHandlerImpl(this,
ctx.isProjectStage(ProjectStage.Production));
parser.setErrorHandler(errorHandler);
// parse and create a stylesheet composition
styleSheet = parser.parseStyleSheet(source, null, null);
+ } catch (Exception e) {
+ System.out.println(e);
} finally {
if (stream != null) {
try {
@@ -106,17 +137,18 @@
}
if (styleSheet != null) {
- //TODO nick - handle encoding
+ // TODO nick - handle encoding
+ String encoding =
FacesContext.getCurrentInstance().getExternalContext().getResponseCharacterEncoding();
CSSVisitorImpl cssVisitor = new CSSVisitorImpl();
+ cssVisitor.setEncoding(encoding != null ? encoding : "UTF-8");
cssVisitor.visitStyleSheet(styleSheet);
String cssText = cssVisitor.getCSSText();
- return new ByteArrayInputStream(cssText.getBytes("US-ASCII"));
+ return new ByteArrayInputStream(cssText.getBytes(cssVisitor.getEncoding()));
} else {
if (!ctx.isProjectStage(ProjectStage.Production)) {
- LOGGER.info(MessageFormat.format(NULL_STYLESHEET,
resourceDelegate.getLibraryName(),
- resourceDelegate.getResourceName()));
+ LOGGER.info(MessageFormat.format(NULL_STYLESHEET, getLibraryName(),
getResourceName()));
}
return null;
}
@@ -127,33 +159,11 @@
return "text/css";
}
- public Resource getResourceDelegate() {
- return resourceDelegate;
+ public static String getHash(String path) {
+ return Integer.toHexString(getSkinHashCode());
}
- public void setResourceDelegate(Resource resourceDelegate) {
- this.resourceDelegate = resourceDelegate;
- }
-
- @Override
- public String getResourceName() {
- return resourceDelegate.getResourceName();
- }
-
- @Override
- public String getRequestPath() {
- //TODO nick - review
- String path = resourceDelegate.getRequestPath();
-
- StringBuilder b = new StringBuilder(path.length() + SKIN.length() + 8 /* hash
code max length */);
- b.append(path);
- b.append(SKIN);
- b.append(Integer.toHexString(getSkinHashCode()));
-
- return b.toString();
- }
-
- private int getSkinHashCode() {
+ private static int getSkinHashCode() {
FacesContext facesContext = FacesContext.getCurrentInstance();
Skin skin = SkinFactory.getInstance().getSkin(facesContext);
return skin.hashCode(facesContext);
@@ -161,8 +171,8 @@
@Override
public boolean userAgentNeedsUpdate(FacesContext context) {
- //TODO nick - review
- //return resourceDelegate.userAgentNeedsUpdate(context);
+ // TODO nick - review
+ // return resourceDelegate.userAgentNeedsUpdate(context);
if (context.isProjectStage(ProjectStage.Development)) {
return true;
@@ -172,7 +182,7 @@
private static final class ErrorHandlerImpl implements ErrorHandler {
- //TODO nick - sort out logging between stages
+ // TODO nick - sort out logging between stages
private boolean productionStage;
private Resource resource;
@@ -202,8 +212,7 @@
private void logException(CSSParseException e) {
String formattedMessage = MessageFormat.format("Problem parsing
''{0}'' resource: {1}",
- getResourceLocator(),
- e.getMessage());
+ getResourceLocator(), e.getMessage());
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(formattedMessage, e);
@@ -225,181 +234,4 @@
}
}
-
- private static final class ELEvaluatingInputStream extends InputStream {
-
- // Premature optimization is the root of all evil. Blah blah.
- private List<Integer> buf = new ArrayList<Integer>(1024);
- private boolean failedExpressionTest = false;
- private boolean writingExpression = false;
- private InputStream inner;
- private FacesContext ctx;
- private Resource info;
-
- private int nextRead = -1;
- // ---------------------------------------------------- Constructors
-
-
- public ELEvaluatingInputStream(FacesContext ctx,
- Resource info,
- InputStream inner) {
-
- this.inner = inner;
- this.info = info;
- this.ctx = ctx;
-
- }
-
-
- // ------------------------------------------------ Methods from InputStream
-
-
- @Override
- public int read() throws IOException {
- int i;
- char c;
-
- if (failedExpressionTest) {
- i = nextRead;
- nextRead = -1;
- failedExpressionTest = false;
- } else if (writingExpression) {
- if (0 < buf.size()) {
- i = buf.remove(0);
- } else {
- writingExpression = false;
- i = inner.read();
- }
- } else {
- // Read a character.
- i = inner.read();
- c = (char) i;
- // If it *might* be an expression...
- if (c == '#') {
- // read another character.
- i = inner.read();
- c = (char) i;
- // If it's '{', assume we have an expression.
- if (c == '{') {
- // read it into the buffer, and evaluate it into the
- // same buffer.
- readExpressionIntoBufferAndEvaluateIntoBuffer();
- // set the flag so that we need to return content
- // from the buffer.
- writingExpression = true;
- // Make sure to swallow the '{'.
- i = this.read();
- } else {
- // It's not an expression, we need to return '#',
- i = (int) '#';
- // then return whatever we just read, on the
- // *next* read;
- nextRead = (int) c;
- failedExpressionTest = true;
- }
- }
- }
-
- return i;
- }
-
- private void readExpressionIntoBufferAndEvaluateIntoBuffer()
- throws IOException {
-
- int i;
- char c;
- do {
- i = inner.read();
- c = (char) i;
- if (c == '}') {
- evaluateExpressionIntoBuffer();
- } else {
- buf.add(i);
- }
- } while (c != '}' && i != -1);
- }
-
- /*
- * At this point, we know that getBuf() returns a List<Integer>
- * that contains the bytes of the expression.
- * Turn it into a String, turn the String into a ValueExpression,
- * evaluate it, store the toString() of it in
- * expressionResult;
- */
- private void evaluateExpressionIntoBuffer() {
- char [] chars = new char[buf.size()];
- int len = buf.size();
- for (int i = 0; i < len; i++) {
- chars[i] = (char) (int) buf.get(i);
- }
- String expressionBody = new String(chars);
-
- // If this expression contains a ":"
- int colon = expressionBody.indexOf(":");
- if (-1 != colon) {
- // Make sure it contains only one ":"
- if (!isPropertyValid(expressionBody)) {
- String message =
MessageFormat.format(INVALID_RESOURCE_FORMAT_COLON_ERROR,
- expressionBody);
- throw new ELException(message);
- }
- String[] parts = split(expressionBody, ":");
- if (null == parts[0] || null == parts[1]) {
- String message =
MessageFormat.format(INVALID_RESOURCE_FORMAT_NO_LIBRARY_NAME_ERROR,
- expressionBody);
- throw new ELException(message);
-
- }
- try {
- int mark = parts[0].indexOf("[") + 2;
- char quoteMark = parts[0].charAt(mark - 1);
- parts[0] = parts[0].substring(mark, colon);
- if (parts[0].equals("this")) {
- parts[0] = info.getLibraryName();
- mark = parts[1].indexOf("]") - 1;
- parts[1] = parts[1].substring(0, mark);
- expressionBody = "resource[" + quoteMark + parts[0] +
- ":" + parts[1] + quoteMark + "]";
- }
- } catch (Exception e) {
- String message = MessageFormat.format(INVALID_RESOURCE_FORMAT_ERROR,
- expressionBody);
- throw new ELException(message);
-
- }
- }
- ELContext elContext = ctx.getELContext();
- ValueExpression ve =
- ctx.getApplication().getExpressionFactory().
- createValueExpression(elContext, "#{" +
expressionBody +
- "}", String.class);
- Object value = ve.getValue(elContext);
- String expressionResult = ((value != null) ? value.toString() :
"");
- buf.clear();
- int expressionResultLen = expressionResult.length();
- for (int i = 0; i < expressionResultLen; i++) {
- buf.add((int) expressionResult.charAt(i));
- }
- }
-
-
- private String[] split(String expressionBody, String toSplit) {
- return Pattern.compile(expressionBody).split(toSplit, 0);
- }
-
-
- @Override
- public void close() throws IOException {
- inner.close();
- super.close();
-
- }
-
-
- private boolean isPropertyValid(String property) {
- int idx = property.indexOf(':');
- return (property.indexOf(':', idx + 1) == -1);
- }
-
- }
-}
+}
\ No newline at end of file
Modified:
root/core/trunk/impl/src/main/java/org/richfaces/resource/ResourceHandlerImpl.java
===================================================================
---
root/core/trunk/impl/src/main/java/org/richfaces/resource/ResourceHandlerImpl.java 2010-05-12
14:25:10 UTC (rev 17004)
+++
root/core/trunk/impl/src/main/java/org/richfaces/resource/ResourceHandlerImpl.java 2010-05-12
17:42:44 UTC (rev 17005)
@@ -141,7 +141,7 @@
}
} else {
- // TODO log
+ LOGGER.warn("Resource key not found" + resourceName);
return null;
}
}
@@ -243,7 +243,9 @@
Map<String, String> params =
Util.parseResourceParameters(resourceKey);
resource = createHandlerDependentResource(resourceName, params);
}
-
+ if (resource == null &&
resourceName.lastIndexOf(".ecss") != -1) {
+ resource = new CompiledCSSResource(resourceName);
+ }
if (resource == null) {
logMissingResource(context, resourceName);
sendResourceNotFound(context);
@@ -440,8 +442,6 @@
if (Resource.class.isAssignableFrom(resourceClass)) {
resource = (Resource) resourceClass.newInstance();
resource.setResourceName(resourceName);
-
- //TODO nick - pass parameters via FacesContext?
if (resource instanceof Java2Dresource) {
Java2Dresource dynamicResource = (Java2Dresource) resource;
dynamicResource.populateParameters(params);
@@ -470,11 +470,10 @@
if ((resourceName != null) && ((libraryName == null) ||
(libraryName.length() == 0))
&& isResourceExists(resourceName)) {
result = createHandlerDependentResource(resourceName, params);
+ } else if (resourceName.lastIndexOf(".ecss") != -1) {
+ result = new CompiledCSSResource(resourceName);
} else {
result = defaultHandler.createResource(resourceName, libraryName,
contentType);
- if (result != null && resourceName.endsWith(".ecss")) {
- result = new CompiledCSSResource(result);
- }
}
return result;
@@ -511,4 +510,4 @@
public boolean libraryExists(String libraryName) {
return defaultHandler.libraryExists(libraryName);
}
-}
+}
\ No newline at end of file
Modified:
root/core/trunk/impl/src/main/java/org/richfaces/resource/Xcss2EcssConverter.java
===================================================================
---
root/core/trunk/impl/src/main/java/org/richfaces/resource/Xcss2EcssConverter.java 2010-05-12
14:25:10 UTC (rev 17004)
+++
root/core/trunk/impl/src/main/java/org/richfaces/resource/Xcss2EcssConverter.java 2010-05-12
17:42:44 UTC (rev 17005)
@@ -65,9 +65,9 @@
}
if (IMPORT.equals(localName)) {
String src = atts.getValue("src");
- ecssContent.append("@import url(#{resource['");
+ ecssContent.append("@import url(\"#{resource['");
ecssContent.append(src);
- ecssContent.append("']}\r\n");
+ ecssContent.append("']\"}\r\n");
}
if (VERBATIM.equals(localName)) {
verbatim = true;
@@ -107,7 +107,7 @@
if (RESOURCE.equals(localName)) {
String value = atts.getValue("f:key");
if (null != value) {
- ecssContent.append("'url(#{resource['");
+ ecssContent.append("\"url(#{resource['");
ecssContent.append(value);
}
@@ -190,7 +190,7 @@
if (hasAttribbute) {
ecssContent.setLength(ecssContent.length() - 1);
}
- ecssContent.append("']})'");
+ ecssContent.append("']})\"");
hasAttribbute = false;
}
if (ATTRIBBUTE.equals(localName)) {
@@ -262,5 +262,4 @@
public void parse(InputStream stream) throws IOException, SAXException {
saxParser.parse(stream, handler);
}
-}
-
+}
\ No newline at end of file
Modified:
root/core/trunk/impl/src/main/java/org/richfaces/resource/css/CSSVisitorImpl.java
===================================================================
---
root/core/trunk/impl/src/main/java/org/richfaces/resource/css/CSSVisitorImpl.java 2010-05-12
14:25:10 UTC (rev 17004)
+++
root/core/trunk/impl/src/main/java/org/richfaces/resource/css/CSSVisitorImpl.java 2010-05-12
17:42:44 UTC (rev 17005)
@@ -21,9 +21,20 @@
*/
package org.richfaces.resource.css;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
+import javax.el.ValueExpression;
+import javax.faces.application.Resource;
+import javax.faces.context.FacesContext;
+
+import org.ajax4jsf.util.ELUtils;
+import org.richfaces.log.RichfacesLogger;
+import org.slf4j.Logger;
import org.w3c.dom.css.CSSCharsetRule;
import org.w3c.dom.css.CSSFontFaceRule;
import org.w3c.dom.css.CSSImportRule;
@@ -35,6 +46,7 @@
import org.w3c.dom.css.CSSStyleSheet;
import org.w3c.dom.css.CSSUnknownRule;
import org.w3c.dom.stylesheets.MediaList;
+import org.richfaces.resource.CompiledCSSResource;
/**
* @author Nick Belaevski
@@ -42,6 +54,10 @@
*/
public final class CSSVisitorImpl extends AbstractCSSVisitor {
+ private static final String RESOURCE_START_PREFIX = "resource[";
+
+ private static final Logger LOGGER = RichfacesLogger.RESOURCE.getLogger();
+
private static final String NEW_LINE = "\r\n";
private String encoding;
@@ -60,6 +76,13 @@
}
}
+ /*private String escape(String cssText) {
+ cssText = cssText.replaceAll("\\\\", "\\\\\\\\");
+ cssText = cssText.replaceAll("\"", "\\\\\"");
+ cssText = cssText.replaceAll("'", "\\\\'");
+ return cssText;
+ }*/
+
private void flushPrefixes() {
if (!prefixes.isEmpty()) {
for (String prefix : prefixes) {
@@ -96,7 +119,40 @@
@Override
public void visitImportRule(CSSImportRule rule) {
//TODO nick - process imported stylesheet?
- appendCSSText(rule);
+ String resourceName = rule.getHref();
+ if (ELUtils.isValueReference(resourceName)) {
+ if (resourceName.indexOf(RESOURCE_START_PREFIX) == -1) {
+ ValueExpression ex = ELUtils.createValueExpression(resourceName);
+ resourceName = ELUtils.evaluateValueExpression(ex,
FacesContext.getCurrentInstance().getELContext()).toString();
+ } else {
+ int start = resourceName.indexOf(RESOURCE_START_PREFIX) +
RESOURCE_START_PREFIX.length();
+ int end = resourceName.lastIndexOf("]");
+ resourceName = resourceName.substring(start, end);
+ resourceName = resourceName.replaceAll("\"",
"").replaceAll("'", "").trim();
+ }
+ }
+ if (resourceName.indexOf(".ecss") != -1) {
+ resourceName = resourceName + CompiledCSSResource.getHash(resourceName);
+ }
+ Resource imported = FacesContext.getCurrentInstance().getApplication().
+ getResourceHandler().createResource(resourceName);
+ if (imported == null) {
+ LOGGER.error("Resource with name " + resourceName + "can't
be found.");
+ return;
+ }
+ String toAdd = null;
+ try {
+ toAdd = convertStreamToString(imported.getInputStream(),
this.getEncoding());
+ } catch (IOException e) {
+ LOGGER.error("Error while importing nested resource with name " +
resourceName);
+ }
+ if (toAdd != null && toAdd.length() > 0) {
+ buffer.append(toAdd);
+ buffer.append(NEW_LINE);
+ } else {
+ appendCSSText(rule);
+ }
+
}
@Override
@@ -112,6 +168,7 @@
@Override
protected void startMediaRule(CSSMediaRule rule) {
MediaList mediaList = rule.getMedia();
+ //String mediaText = escape(mediaList.getMediaText());
String mediaText = mediaList.getMediaText();
prefixes.add("@media " + mediaText);
}
@@ -123,8 +180,8 @@
@Override
protected void startPageRule(CSSPageRule rule) {
+ //String selectorText = escape(rule.getSelectorText());
String selectorText = rule.getSelectorText();
-
//TODO nick - multiple selectors?
prefixes.add("@page " + selectorText);
}
@@ -136,6 +193,7 @@
@Override
protected void startStyleRule(CSSStyleRule rule) {
+ //String selectorText = escape(rule.getSelectorText());
String selectorText = rule.getSelectorText();
prefixes.add(selectorText);
}
@@ -160,15 +218,26 @@
String value = styleDeclaration.getPropertyValue(propertyName).trim();
String priority = styleDeclaration.getPropertyPriority(propertyName);
-
+ if (ELUtils.isValueReference(value)) {
+ ValueExpression ex = ELUtils.createValueExpression(value);
+ value = ELUtils.evaluateValueExpression(ex,
FacesContext.getCurrentInstance().getELContext()).toString();
+ }
+ if (value.startsWith("\"") &&
value.endsWith("\"")) {
+ value = value.substring(1, value.length() - 1);
+ }
+ if (value.startsWith("'") &&
value.endsWith("'")) {
+ value = value.substring(1, value.length() - 1);
+ }
if (value.length() != 0 && !value.equals("\"\"")
&& !value.equals("''")) {
flushPrefixes();
//One of properties of selector is not empty
buffer.append('\t');
+ //buffer.append(escape(propertyName));
buffer.append(propertyName);
buffer.append(": ");
+ //buffer.append(escape(value));
buffer.append(value);
if (priority != null && priority.length() != 0) {
@@ -189,4 +258,28 @@
public String getCSSText() {
return buffer.toString();
}
-}
+
+ public void setEncoding(String encoding) {
+ this.encoding = encoding;
+ }
+
+ public String convertStreamToString(InputStream is, String encoding) throws
IOException {
+
+ if (is != null) {
+ StringBuilder sb = new StringBuilder();
+ String line;
+
+ try {
+ BufferedReader reader = new BufferedReader(new InputStreamReader(is,
encoding));
+ while ((line = reader.readLine()) != null) {
+ sb.append(line).append(NEW_LINE);
+ }
+ } finally {
+ is.close();
+ }
+ return sb.toString();
+ } else {
+ return "";
+ }
+ }
+}
\ No newline at end of file
Modified: root/core/trunk/impl/src/main/resources/META-INF/resources/basic_both.ecss
===================================================================
--- root/core/trunk/impl/src/main/resources/META-INF/resources/basic_both.ecss 2010-05-12
14:25:10 UTC (rev 17004)
+++ root/core/trunk/impl/src/main/resources/META-INF/resources/basic_both.ecss 2010-05-12
17:42:44 UTC (rev 17005)
@@ -1,2 +1,2 @@
-@import url(#{resource['basic.ecss']});
-@import url(#{resource['basic_classes.ecss']});
\ No newline at end of file
+@import url("#{resource['basic.ecss']}");
+@import url("#{resource['basic_classes.ecss']}");
\ No newline at end of file
Modified: root/core/trunk/impl/src/main/resources/META-INF/resources/basic_classes.ecss
===================================================================
---
root/core/trunk/impl/src/main/resources/META-INF/resources/basic_classes.ecss 2010-05-12
14:25:10 UTC (rev 17004)
+++
root/core/trunk/impl/src/main/resources/META-INF/resources/basic_classes.ecss 2010-05-12
17:42:44 UTC (rev 17005)
@@ -57,7 +57,7 @@
.rich-field{
background-color : '#{richSkin.controlBackgroundColor}';
- background-image :
'url(#{resource['org.richfaces.renderkit.html.images.ButtonBackgroundImage']})';
+ background-image :
"url(#{resource['org.richfaces.renderkit.html.images.ButtonBackgroundImage']})";
background-repeat : no-repeat;
background-position : 1px 1px;
}
@@ -68,7 +68,7 @@
.rich-field-error{
background-color : '#{richSkin.warningBackgroundColor}';
- background-image :
'url(#{resource['org.richfaces.renderkit.html.images.InputErrorIcon']})';
+ background-image :
"url(#{resource['org.richfaces.renderkit.html.images.InputErrorIcon']})";
background-repeat : no-repeat;
background-position : center left;
padding-left : 7px;
@@ -87,19 +87,19 @@
}
.rich-button{
- background-image :
'url(#{resource['org.richfaces.renderkit.html.images.StandardButtonBgImage']})';
+ background-image :
"url(#{resource['org.richfaces.renderkit.html.images.StandardButtonBgImage']})";
}
.rich-button-disabled{
- background-image :
'url(#{resource['org.richfaces.renderkit.html.images.StandardButtonBgImage']})';
+ background-image :
"url(#{resource['org.richfaces.renderkit.html.images.StandardButtonBgImage']})";
}
.rich-button-over{
- background-image :
'url(#{resource['org.richfaces.renderkit.html.images.StandardButtonBgImage']})';
+ background-image :
"url(#{resource['org.richfaces.renderkit.html.images.StandardButtonBgImage']})";
}
.rich-button-press{
- background-image :
'url(#{resource['org.richfaces.renderkit.html.images.StandardButtonPressedBgImage']})';
+ background-image :
"url(#{resource['org.richfaces.renderkit.html.images.StandardButtonPressedBgImage']})";
background-position : bottom left;
}
@@ -304,46 +304,46 @@
/*gradient styles*/
.rich-gradient-header-inverse{
- background-image :
'url(#{resource['org.richfaces.renderkit.html.gradientimages.HeaderInverseGradientImage']})';
+ background-image :
"url(#{resource['org.richfaces.renderkit.html.gradientimages.HeaderInverseGradientImage']})";
background-repeat : repeat-x;
}
.rich-gradient-header{
- background-image :
'url(#{resource['org.richfaces.renderkit.html.gradientimages.HeaderGradientImage']})';
+ background-image :
"url(#{resource['org.richfaces.renderkit.html.gradientimages.HeaderGradientImage']})";
background-repeat : repeat-x;
}
.rich-gradient-tab{
- background-image :
'url(#{resource['org.richfaces.renderkit.html.gradientimages.TabGradientImage']})';
+ background-image :
"url(#{resource['org.richfaces.renderkit.html.gradientimages.TabGradientImage']})";
background-repeat : repeat-x;
}
.rich-gradient-tab-inverse{
- background-image :
'url(#{resource['org.richfaces.renderkit.html.gradientimages.TabInverseGradientImage']})';
+ background-image :
"url(#{resource['org.richfaces.renderkit.html.gradientimages.TabInverseGradientImage']})";
background-repeat : repeat-x;
}
.rich-gradient-input{
- background-image :
'url(#{resource['org.richfaces.renderkit.html.gradientimages.InputGradientImage']})';
+ background-image :
"url(#{resource['org.richfaces.renderkit.html.gradientimages.InputGradientImage']})";
background-repeat : repeat-x;
}
.rich-gradient-menu-inverse{
- background-image :
'url(#{resource['org.richfaces.renderkit.html.gradientimages.MenuInverseGradientImage']})';
+ background-image :
"url(#{resource['org.richfaces.renderkit.html.gradientimages.MenuInverseGradientImage']})";
background-repeat : repeat-x;
}
.rich-gradient-menu{
- background-image :
'url(#{resource['org.richfaces.renderkit.html.gradientimages.MenuGradientImage']})';
+ background-image :
"url(#{resource['org.richfaces.renderkit.html.gradientimages.MenuGradientImage']})";
background-repeat : repeat-x;
}
.rich-gradient-button-inverse{
- background-image :
'url(#{resource['org.richfaces.renderkit.html.gradientimages.ButtonInverseGradientImage']})';
+ background-image :
"url(#{resource['org.richfaces.renderkit.html.gradientimages.ButtonInverseGradientImage']})";
background-repeat : repeat-x;
}
.rich-gradient-button{
- background-image :
'url(#{resource['org.richfaces.renderkit.html.gradientimages.ButtonGradientImage']})';
+ background-image :
"url(#{resource['org.richfaces.renderkit.html.gradientimages.ButtonGradientImage']})";
background-repeat : repeat-x;
}
\ No newline at end of file
Modified: root/core/trunk/impl/src/main/resources/META-INF/resources/extended.ecss
===================================================================
--- root/core/trunk/impl/src/main/resources/META-INF/resources/extended.ecss 2010-05-12
14:25:10 UTC (rev 17004)
+++ root/core/trunk/impl/src/main/resources/META-INF/resources/extended.ecss 2010-05-12
17:42:44 UTC (rev 17005)
@@ -24,7 +24,7 @@
font-family:'#{richSkin.generalFamilyFont}';
color:'#{richSkin.headerTextColor}';
background-color:'#{richSkin.headerBackgroundColor}';
- background-image:'url(#{resource['org.richfaces.renderkit.html.images.ButtonBackgroundImage']})';
+ background-image:"url(#{resource['org.richfaces.renderkit.html.images.ButtonBackgroundImage']})";
}
button[type="button"], button[type="reset"],
button[type="submit"], input[type="reset"],
input[type="submit"], input[type="button"]{
border-color:'#{richSkin.panelBorderColor}';
@@ -32,19 +32,19 @@
font-family:'#{richSkin.generalFamilyFont}';
color:'#{richSkin.headerTextColor}';
background-color:'#{richSkin.headerBackgroundColor}';
- background-image:'url(#{resource['org.richfaces.renderkit.html.images.ButtonBackgroundImage']})';
+ background-image:"url(#{resource['org.richfaces.renderkit.html.images.ButtonBackgroundImage']})";
}
*|button[disabled]{
color:'#{richSkin.tabDisabledTextColor}';
border-color:'#{richSkin.tableFooterBackgroundColor}';
background-color:'#{richSkin.tableFooterBackgroundColor}';
- background-image:'url(#{resource['org.richfaces.renderkit.html.images.ButtonDisabledBackgroundImage']})';
+ background-image:"url(#{resource['org.richfaces.renderkit.html.images.ButtonDisabledBackgroundImage']})";
}
button[type="button"][disabled], button[type="reset"][disabled],
button[type="submit"][disabled], input[type="reset"][disabled],
input[type="submit"][disabled], input[type="button"][disabled]{
color:'#{richSkin.tabDisabledTextColor}';
border-color:'#{richSkin.tableFooterBackgroundColor}';
background-color:'#{richSkin.tableFooterBackgroundColor}';
- background-image:'url(#{resource['org.richfaces.renderkit.html.images.ButtonDisabledBackgroundImage']})';
+ background-image:"url(#{resource['org.richfaces.renderkit.html.images.ButtonDisabledBackgroundImage']})";
}
@@ -68,7 +68,7 @@
font-family:'#{richSkin.generalFamilyFont}';
color:'#{richSkin.controlTextColor}';
background-color:'#{richSkin.controlBackgroundColor}';
- background-image:'url(#{resource['org.richfaces.renderkit.html.images.InputBackgroundImage']})';
+ background-image:"url(#{resource['org.richfaces.renderkit.html.images.InputBackgroundImage']})";
}
textarea[type="textarea"], input[type="text"],
input[type="password"], select{
border-color:'#{richSkin.panelBorderColor}';
@@ -76,7 +76,7 @@
font-family:'#{richSkin.generalFamilyFont}';
color:'#{richSkin.controlTextColor}';
background-color:'#{richSkin.controlBackgroundColor}';
- background-image:'url(#{resource['org.richfaces.renderkit.html.images.InputBackgroundImage']})';
+ background-image:"url(#{resource['org.richfaces.renderkit.html.images.InputBackgroundImage']})";
}
*|textarea[disabled], *|select[disabled]{
color:'#{richSkin.panelBorderColor}';
Modified: root/core/trunk/impl/src/main/resources/META-INF/resources/extended_both.ecss
===================================================================
---
root/core/trunk/impl/src/main/resources/META-INF/resources/extended_both.ecss 2010-05-12
14:25:10 UTC (rev 17004)
+++
root/core/trunk/impl/src/main/resources/META-INF/resources/extended_both.ecss 2010-05-12
17:42:44 UTC (rev 17005)
@@ -1,2 +1,2 @@
-@import url(#{resource['extended.ecss']});
-@import url(#{resource['extended_classes.ecss']});
\ No newline at end of file
+@import url("#{resource['extended.ecss']}");
+@import url("#{resource['extended_classes.ecss']}");
\ No newline at end of file
Modified:
root/core/trunk/impl/src/main/resources/META-INF/resources/extended_classes.ecss
===================================================================
---
root/core/trunk/impl/src/main/resources/META-INF/resources/extended_classes.ecss 2010-05-12
14:25:10 UTC (rev 17004)
+++
root/core/trunk/impl/src/main/resources/META-INF/resources/extended_classes.ecss 2010-05-12
17:42:44 UTC (rev 17005)
@@ -30,7 +30,7 @@
font-family:'#{richSkin.generalFamilyFont}';
color:'#{richSkin.headerTextColor}';
background-color:'#{richSkin.headerBackgroundColor}';
- background-image:'url(#{resource['org.richfaces.renderkit.html.images.ButtonBackgroundImage']})';
+ background-image:"url(#{resource['org.richfaces.renderkit.html.images.ButtonBackgroundImage']})";
}
.rich-button, .rich-container button[type="button"], .rich-button-button,
.rich-container button[type="reset"], .rich-button-reset, .rich-container
button[type="submit"], .rich-button-submit, .rich-container
input[type="reset"], .rich-input-reset, .rich-container
input[type="submit"], .rich-input-submit, .rich-container
input[type="button"], .rich-input-button {
border-color:'#{richSkin.panelBorderColor}';
@@ -38,19 +38,19 @@
font-family:'#{richSkin.generalFamilyFont}';
color:'#{richSkin.headerTextColor}';
background-color:'#{richSkin.headerBackgroundColor}';
- background-image:'url(#{resource['org.richfaces.renderkit.html.images.ButtonBackgroundImage']})';
+ background-image:"url(#{resource['org.richfaces.renderkit.html.images.ButtonBackgroundImage']})";
}
.rich-container *|button[disabled]{
color:'#{richSkin.tabDisabledTextColor}';
background-color:'#{richSkin.tableFooterBackgroundColor}';
border-color:'#{richSkin.tableFooterBackgroundColor}';
- background-image:'url(#{resource['org.richfaces.renderkit.html.images.ButtonDisabledBackgroundImage']})';
+ background-image:"url(#{resource['org.richfaces.renderkit.html.images.ButtonDisabledBackgroundImage']})";
}
.rich-button-disabled, .rich-container button[type="button"][disabled],
.rich-button-button-disabled, .rich-container button[type="reset"][disabled],
.rich-button-reset-disabled, .rich-container button[type="submit"][disabled],
.rich-button-submit-disabled, .rich-container input[type="reset"][disabled],
.rich-input-reset-disabled, .rich-container input[type="submit"][disabled],
.rich-input-submit-disabled, .rich-container input[type="button"][disabled],
.rich-input-button-disabled{
color:'#{richSkin.tabDisabledTextColor}';
background-color:'#{richSkin.tableFooterBackgroundColor}';
border-color:'#{richSkin.tableFooterBackgroundColor}';
- background-image:'url(#{resource['org.richfaces.renderkit.html.images.ButtonDisabledBackgroundImage']})';
+ background-image:"url(#{resource['org.richfaces.renderkit.html.images.ButtonDisabledBackgroundImage']})";
}
@@ -78,7 +78,7 @@
font-family:'#{richSkin.generalFamilyFont}';
color:'#{richSkin.controlTextColor}';
background-color:'#{richSkin.controlBackgroundColor}';
- background-image:'url(#{resource['org.richfaces.renderkit.html.images.InputBackgroundImage']})';
+ background-image:"url(#{resource['org.richfaces.renderkit.html.images.InputBackgroundImage']})";
}
.rich-textarea, .rich-container textarea[type="textarea"],
.rich-textarea-textarea, .rich-container input[type="text"], .rich-input-text,
.rich-container input[type="password"], .rich-input-password,
.rich-container select, .rich-select{
border-color:'#{richSkin.panelBorderColor}';
@@ -86,7 +86,7 @@
font-family:'#{richSkin.generalFamilyFont}';
color:'#{richSkin.controlTextColor}';
background-color:'#{richSkin.controlBackgroundColor}';
- background-image:'url(#{resource['org.richfaces.renderkit.html.images.InputBackgroundImage']})';
+ background-image:"url(#{resource['org.richfaces.renderkit.html.images.InputBackgroundImage']})";
}
.rich-container *|textarea[disabled], .rich-container *|select[disabled]{
color:'#{richSkin.panelBorderColor}';
Modified:
root/core/trunk/impl/src/test/java/org/richfaces/resource/ResourceHandlerImplTest.java
===================================================================
---
root/core/trunk/impl/src/test/java/org/richfaces/resource/ResourceHandlerImplTest.java 2010-05-12
14:25:10 UTC (rev 17004)
+++
root/core/trunk/impl/src/test/java/org/richfaces/resource/ResourceHandlerImplTest.java 2010-05-12
17:42:44 UTC (rev 17005)
@@ -23,10 +23,14 @@
package org.richfaces.resource;
+import java.io.BufferedReader;
import java.io.File;
+import java.io.FileReader;
import java.net.URL;
+import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
+import java.util.List;
import java.util.TimeZone;
import javax.faces.application.ResourceHandler;
@@ -246,7 +250,24 @@
resourceResponse = webClient.loadWebResponse(settings);
assertEquals(HttpServletResponse.SC_NOT_FOUND,
resourceResponse.getStatusCode());
}
+
+ public void testCompiledCssResource() throws Exception {
+ String baseResourseURL = "http://localhost/rfRes/";
+ String endResourceURL = ".jsf";
+ String resourceName = null;
+ List<String> resources = populateResourcesToCheck();
+ for (String resource : resources) {
+ resourceName = baseResourseURL + resource + endResourceURL;
+ WebRequestSettings settings =
+ new WebRequestSettings(new URL(resourceName));
+ WebResponse resourceResponse = webClient.loadWebResponse(settings);
+ assertEquals(HttpServletResponse.SC_OK, resourceResponse.getStatusCode());
+ String expected =
readFileAsString(getResourceExpectedOutputFileName(resource));
+ assertEquals(expected.trim(), resourceResponse.getContentAsString().trim());
+ }
+ }
+
public void testCreateResource() throws Exception {
setupFacesRequest();
@@ -266,4 +287,44 @@
assertTrue(resourceHandler.libraryExists("org.richfaces.resource.test"));
}
-}
+
+ private static String readFileAsString(String filePath) throws java.io.IOException {
+ ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+ File testResourceFile = new File(classLoader.getResource(RESOURCES_FOLDER_PATH +
"/" + filePath).getFile());
+ StringBuffer fileData = new StringBuffer(1000);
+ BufferedReader reader = new BufferedReader(
+ new FileReader(testResourceFile));
+ char[] buf = new char[1024];
+ int numRead = 0;
+ while ((numRead = reader.read(buf)) != -1) {
+ String readData = String.valueOf(buf, 0, numRead);
+ fileData.append(readData);
+ buf = new char[1024];
+ }
+ reader.close();
+ return fileData.toString();
+ }
+
+ private List<String> populateResourcesToCheck() {
+ List<String> resources = new ArrayList<String>();
+ resources.add("importedEL.ecss");
+ resources.add("media.ecss");
+ resources.add("fake.ecss");
+ resources.add("fake2.ecss");
+ resources.add("fontface.ecss");
+ resources.add("full.ecss");
+ resources.add("import.ecss");
+ resources.add("media.ecss");
+ resources.add("page.ecss");
+ resources.add("resource.ecss");
+ resources.add("selector.ecss");
+ resources.add("skin.ecss");
+ resources.add("charset.ecss");
+ return resources;
+ }
+
+ private String getResourceExpectedOutputFileName(String name) {
+ return name.replaceAll("ecss", "css");
+ }
+
+}
\ No newline at end of file
Added: root/core/trunk/impl/src/test/resources/resources/charset.css
===================================================================
--- root/core/trunk/impl/src/test/resources/resources/charset.css
(rev 0)
+++ root/core/trunk/impl/src/test/resources/resources/charset.css 2010-05-12 17:42:44 UTC
(rev 17005)
@@ -0,0 +1 @@
+@charset "iso-8859-1";
\ No newline at end of file
Added: root/core/trunk/impl/src/test/resources/resources/charset.ecss
===================================================================
--- root/core/trunk/impl/src/test/resources/resources/charset.ecss
(rev 0)
+++ root/core/trunk/impl/src/test/resources/resources/charset.ecss 2010-05-12 17:42:44 UTC
(rev 17005)
@@ -0,0 +1 @@
+@charset "iso-8859-1";
\ No newline at end of file
Added: root/core/trunk/impl/src/test/resources/resources/fake.css
===================================================================
Added: root/core/trunk/impl/src/test/resources/resources/fake.ecss
===================================================================
--- root/core/trunk/impl/src/test/resources/resources/fake.ecss
(rev 0)
+++ root/core/trunk/impl/src/test/resources/resources/fake.ecss 2010-05-12 17:42:44 UTC
(rev 17005)
@@ -0,0 +1,4 @@
+body {
+ padding: ;
+ border: "";
+}
\ No newline at end of file
Added: root/core/trunk/impl/src/test/resources/resources/fake2.css
===================================================================
--- root/core/trunk/impl/src/test/resources/resources/fake2.css
(rev 0)
+++ root/core/trunk/impl/src/test/resources/resources/fake2.css 2010-05-12 17:42:44 UTC
(rev 17005)
@@ -0,0 +1,3 @@
+body {
+ border: 1px solid green;
+}
\ No newline at end of file
Added: root/core/trunk/impl/src/test/resources/resources/fake2.ecss
===================================================================
--- root/core/trunk/impl/src/test/resources/resources/fake2.ecss
(rev 0)
+++ root/core/trunk/impl/src/test/resources/resources/fake2.ecss 2010-05-12 17:42:44 UTC
(rev 17005)
@@ -0,0 +1,4 @@
+body {
+ padding: ;
+ border: 1px solid green;
+}
\ No newline at end of file
Added: root/core/trunk/impl/src/test/resources/resources/fontface.css
===================================================================
--- root/core/trunk/impl/src/test/resources/resources/fontface.css
(rev 0)
+++ root/core/trunk/impl/src/test/resources/resources/fontface.css 2010-05-12 17:42:44 UTC
(rev 17005)
@@ -0,0 +1,4 @@
+@font-face {
+ font-family: Scarborough Light;
+ src: url(http://www.font.site/s/scarbo-lt);
+}
\ No newline at end of file
Added: root/core/trunk/impl/src/test/resources/resources/fontface.ecss
===================================================================
--- root/core/trunk/impl/src/test/resources/resources/fontface.ecss
(rev 0)
+++ root/core/trunk/impl/src/test/resources/resources/fontface.ecss 2010-05-12 17:42:44
UTC (rev 17005)
@@ -0,0 +1,4 @@
+@font-face {
+ font-family: "Scarborough Light";
+ src: url("http://www.font.site/s/scarbo-lt");
+}
\ No newline at end of file
Added: root/core/trunk/impl/src/test/resources/resources/full.css
===================================================================
--- root/core/trunk/impl/src/test/resources/resources/full.css
(rev 0)
+++ root/core/trunk/impl/src/test/resources/resources/full.css 2010-05-12 17:42:44 UTC
(rev 17005)
@@ -0,0 +1,26 @@
+@charset "iso-8859-1";
+body2 {
+ padding: 10px !important;
+ border: 1px solid green;
+ background-image: url(image.png);
+}
+
+@font-face {
+ font-family: Scarborough Light;
+ src: url(http://www.font.site/s/scarbo-lt);
+}
+@page :right {
+ margin-left: 3cm;
+ margin-right: 4cm;
+}
+@media screen, print {
+body {
+ line-height: 3;
+}
+}
+body {
+ padding: 10px !important;
+ border: 1px solid green;
+ background-image: url(image.png);
+ background: red
url(/rfRes/org.richfaces.renderkit.html.images.ButtonBackgroundImage/DATB/eAF79urt!-Pnr!xn4mZgYAAAREsHMw__.jsf);
+}
Added: root/core/trunk/impl/src/test/resources/resources/full.ecss
===================================================================
--- root/core/trunk/impl/src/test/resources/resources/full.ecss
(rev 0)
+++ root/core/trunk/impl/src/test/resources/resources/full.ecss 2010-05-12 17:42:44 UTC
(rev 17005)
@@ -0,0 +1,28 @@
+@charset "iso-8859-1";
+
+@import url('selector.ecss');
+
+@font-face {
+ font-family: "Scarborough Light";
+ src: url("http://www.font.site/s/scarbo-lt");
+}
+
+@page :right {
+ margin-left: 3cm;
+ margin-right: 4cm;
+}
+
+@media screen, print {
+ body {
+ line-height: 3
+ }
+}
+
+body {
+ padding: 10px !important;
+ border: 1px solid green;
+ background-image: url(image.png);
+
+ background: 'red
url(#{resource["org.richfaces.renderkit.html.images.ButtonBackgroundImage"]})';
+
+}
\ No newline at end of file
Added: root/core/trunk/impl/src/test/resources/resources/import.css
===================================================================
--- root/core/trunk/impl/src/test/resources/resources/import.css
(rev 0)
+++ root/core/trunk/impl/src/test/resources/resources/import.css 2010-05-12 17:42:44 UTC
(rev 17005)
@@ -0,0 +1,5 @@
+body2 {
+ padding: 10px !important;
+ border: 1px solid green;
+ background-image: url(image.png);
+}
\ No newline at end of file
Added: root/core/trunk/impl/src/test/resources/resources/import.ecss
===================================================================
--- root/core/trunk/impl/src/test/resources/resources/import.ecss
(rev 0)
+++ root/core/trunk/impl/src/test/resources/resources/import.ecss 2010-05-12 17:42:44 UTC
(rev 17005)
@@ -0,0 +1 @@
+@import url('selector.ecss');
\ No newline at end of file
Added: root/core/trunk/impl/src/test/resources/resources/importedEL.css
===================================================================
--- root/core/trunk/impl/src/test/resources/resources/importedEL.css
(rev 0)
+++ root/core/trunk/impl/src/test/resources/resources/importedEL.css 2010-05-12 17:42:44
UTC (rev 17005)
@@ -0,0 +1,26 @@
+@charset "iso-8859-1";
+body2 {
+ padding: 10px !important;
+ border: 1px solid green;
+ background-image: url(image.png);
+}
+
+@font-face {
+ font-family: Scarborough Light;
+ src: url(http://www.font.site/s/scarbo-lt);
+}
+@page :right {
+ margin-left: 3cm;
+ margin-right: 4cm;
+}
+@media screen, print {
+body {
+ line-height: 3;
+}
+}
+body {
+ padding: 10px !important;
+ border: 1px solid green;
+ background-image: url(image.png);
+ background: red
url(/rfRes/org.richfaces.renderkit.html.images.ButtonBackgroundImage/DATB/eAF79urt!-Pnr!xn4mZgYAAAREsHMw__.jsf);
+}
\ No newline at end of file
Added: root/core/trunk/impl/src/test/resources/resources/importedEL.ecss
===================================================================
--- root/core/trunk/impl/src/test/resources/resources/importedEL.ecss
(rev 0)
+++ root/core/trunk/impl/src/test/resources/resources/importedEL.ecss 2010-05-12 17:42:44
UTC (rev 17005)
@@ -0,0 +1 @@
+@import url("#{resource['full.ecss']}");
Added: root/core/trunk/impl/src/test/resources/resources/media.css
===================================================================
--- root/core/trunk/impl/src/test/resources/resources/media.css
(rev 0)
+++ root/core/trunk/impl/src/test/resources/resources/media.css 2010-05-12 17:42:44 UTC
(rev 17005)
@@ -0,0 +1,5 @@
+@media screen, print {
+body {
+ line-height: 3;
+}
+}
\ No newline at end of file
Added: root/core/trunk/impl/src/test/resources/resources/media.ecss
===================================================================
--- root/core/trunk/impl/src/test/resources/resources/media.ecss
(rev 0)
+++ root/core/trunk/impl/src/test/resources/resources/media.ecss 2010-05-12 17:42:44 UTC
(rev 17005)
@@ -0,0 +1,5 @@
+@media screen, print {
+ body {
+ line-height: 3
+ }
+}
\ No newline at end of file
Added: root/core/trunk/impl/src/test/resources/resources/page.css
===================================================================
--- root/core/trunk/impl/src/test/resources/resources/page.css
(rev 0)
+++ root/core/trunk/impl/src/test/resources/resources/page.css 2010-05-12 17:42:44 UTC
(rev 17005)
@@ -0,0 +1,4 @@
+@page :right {
+ margin-left: 3cm;
+ margin-right: 4cm;
+}
\ No newline at end of file
Added: root/core/trunk/impl/src/test/resources/resources/page.ecss
===================================================================
--- root/core/trunk/impl/src/test/resources/resources/page.ecss
(rev 0)
+++ root/core/trunk/impl/src/test/resources/resources/page.ecss 2010-05-12 17:42:44 UTC
(rev 17005)
@@ -0,0 +1,4 @@
+@page :right {
+ margin-left: 3cm;
+ margin-right: 4cm;
+}
\ No newline at end of file
Added: root/core/trunk/impl/src/test/resources/resources/resource.css
===================================================================
--- root/core/trunk/impl/src/test/resources/resources/resource.css
(rev 0)
+++ root/core/trunk/impl/src/test/resources/resources/resource.css 2010-05-12 17:42:44 UTC
(rev 17005)
@@ -0,0 +1,3 @@
+body {
+ background: red
url(/rfRes/org.richfaces.renderkit.html.images.ButtonBackgroundImage/DATB/eAF79urt!-Pnr!xn4mZgYAAAREsHMw__.jsf);
+}
\ No newline at end of file
Added: root/core/trunk/impl/src/test/resources/resources/resource.ecss
===================================================================
--- root/core/trunk/impl/src/test/resources/resources/resource.ecss
(rev 0)
+++ root/core/trunk/impl/src/test/resources/resources/resource.ecss 2010-05-12 17:42:44
UTC (rev 17005)
@@ -0,0 +1,3 @@
+body {
+ background: 'red
url(#{resource["org.richfaces.renderkit.html.images.ButtonBackgroundImage"]})';
+}
\ No newline at end of file
Added: root/core/trunk/impl/src/test/resources/resources/selector.css
===================================================================
--- root/core/trunk/impl/src/test/resources/resources/selector.css
(rev 0)
+++ root/core/trunk/impl/src/test/resources/resources/selector.css 2010-05-12 17:42:44 UTC
(rev 17005)
@@ -0,0 +1,5 @@
+body2 {
+ padding: 10px !important;
+ border: 1px solid green;
+ background-image: url(image.png);
+}
\ No newline at end of file
Added: root/core/trunk/impl/src/test/resources/resources/selector.ecss
===================================================================
--- root/core/trunk/impl/src/test/resources/resources/selector.ecss
(rev 0)
+++ root/core/trunk/impl/src/test/resources/resources/selector.ecss 2010-05-12 17:42:44
UTC (rev 17005)
@@ -0,0 +1,5 @@
+body2 {
+ padding: 10px !important;
+ border: 1px solid green;
+ background-image: url(image.png);
+}
\ No newline at end of file
Added: root/core/trunk/impl/src/test/resources/resources/skin.css
===================================================================
--- root/core/trunk/impl/src/test/resources/resources/skin.css
(rev 0)
+++ root/core/trunk/impl/src/test/resources/resources/skin.css 2010-05-12 17:42:44 UTC
(rev 17005)
@@ -0,0 +1,6 @@
+body {
+ padding: 10px !important;
+ border: 1px solid green;
+ background-image: url(image.png);
+ color: #0078D0;
+}
\ No newline at end of file
Added: root/core/trunk/impl/src/test/resources/resources/skin.ecss
===================================================================
--- root/core/trunk/impl/src/test/resources/resources/skin.ecss
(rev 0)
+++ root/core/trunk/impl/src/test/resources/resources/skin.ecss 2010-05-12 17:42:44 UTC
(rev 17005)
@@ -0,0 +1,6 @@
+body {
+ padding: 10px !important;
+ border: 1px solid green;
+ background-image: url(image.png);
+ color: "#{richSkin.generalLinkColor}"
+}
\ No newline at end of file
Modified:
root/ui/core/trunk/api/src/main/java/org/richfaces/component/AbstractAttachQueue.java
===================================================================
---
root/ui/core/trunk/api/src/main/java/org/richfaces/component/AbstractAttachQueue.java 2010-05-12
14:25:10 UTC (rev 17004)
+++
root/ui/core/trunk/api/src/main/java/org/richfaces/component/AbstractAttachQueue.java 2010-05-12
17:42:44 UTC (rev 17005)
@@ -35,6 +35,7 @@
import org.ajax4jsf.component.behavior.AjaxBehavior;
import org.richfaces.cdk.annotations.Attribute;
import org.richfaces.cdk.annotations.JsfComponent;
+import org.richfaces.cdk.annotations.JsfRenderer;
import org.richfaces.cdk.annotations.Tag;
import org.richfaces.cdk.annotations.TagType;
@@ -42,9 +43,10 @@
* @author Nick Belaevski
*
*/
-@JsfComponent(
+@JsfComponent(renderer=(a)JsfRenderer(type="org.richfaces.AttachQueueRenderer"),
tag = @Tag(name = "attachQueue",
handler = "org.richfaces.view.facelets.html.AttachQueueHandler",
+
generate = false, type = TagType.Facelets)
)
@ListenerFor(systemEventClass = PostAddToViewEvent.class)
@@ -59,7 +61,7 @@
private transient List<AjaxBehavior> behaviorsToAssociate;
@Attribute
- public abstract String getRequestSimilarityId();
+ public abstract String getRequestGroupingId();
@Attribute
public abstract int getRequestDelay();
@@ -75,6 +77,9 @@
@Attribute
public abstract String getOnrequestdequeue();
+
+ @Attribute
+ public abstract String getQueueId();
@Override
public String getFamily() {
Modified: root/ui/core/trunk/api/src/main/java/org/richfaces/component/AbstractQueue.java
===================================================================
---
root/ui/core/trunk/api/src/main/java/org/richfaces/component/AbstractQueue.java 2010-05-12
14:25:10 UTC (rev 17004)
+++
root/ui/core/trunk/api/src/main/java/org/richfaces/component/AbstractQueue.java 2010-05-12
17:42:44 UTC (rev 17005)
@@ -24,6 +24,7 @@
import org.richfaces.cdk.annotations.JsfComponent;
import org.richfaces.cdk.annotations.Attribute;
import org.richfaces.cdk.annotations.Tag;
+import org.richfaces.cdk.annotations.TagType;
import javax.faces.component.UIComponentBase;
@@ -31,7 +32,8 @@
* @author Nick Belaevski
*
*/
-@JsfComponent
+@JsfComponent(tag = @Tag(name = "queue",
+ generate = false, type = TagType.Facelets))
public abstract class AbstractQueue extends UIComponentBase {
public static final String GLOBAL_QUEUE_NAME =
"org.richfaces.queue.global";
@@ -66,4 +68,10 @@
@Attribute
public abstract String getOnrequestdequeue();
+
+ @Attribute
+ public abstract int getTimeout();
+
+ @Attribute
+ public abstract boolean isIgnoreDupResponses();
}
Added:
root/ui/core/trunk/api/src/main/java/org/richfaces/renderkit/html/AttachQueueRenderer.java
===================================================================
---
root/ui/core/trunk/api/src/main/java/org/richfaces/renderkit/html/AttachQueueRenderer.java
(rev 0)
+++
root/ui/core/trunk/api/src/main/java/org/richfaces/renderkit/html/AttachQueueRenderer.java 2010-05-12
17:42:44 UTC (rev 17005)
@@ -0,0 +1,59 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2009, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.renderkit.html;
+
+import javax.faces.component.UIComponent;
+
+import org.richfaces.cdk.annotations.JsfRenderer;
+
+/**
+ * @author Nick Belaevski Renderer for attachedQueue component
+ */
+(a)JsfRenderer(type="org.richfaces.AttachQueueRenderer",
family="org.richfaces.AttachQueue")
+public class AttachQueueRenderer extends QueueRendererBase {
+
+ @Override
+ protected String getQueueName(UIComponent comp) {
+ return comp.getClientId();
+ }
+
+ @Override
+ protected String findAndSetQueueName(UIComponent comp) {
+ String name = null;
+ if (comp.getAttributes().get(NAME_ATTRIBBUTE) != null) {
+ name = comp.getAttributes().get(NAME_ATTRIBBUTE).toString();
+ comp.getAttributes().put(QUEUE_ID_ATTRIBBUTE, name);
+ name = getQueueName(comp);
+ } else {
+ String foundedQueueId = findParentQueueId(comp);
+ if (foundedQueueId != null) {
+ comp.getAttributes().put(QUEUE_ID_ATTRIBBUTE, foundedQueueId);
+ name = getQueueName(comp);
+ } else {
+ LOGGER
+ .warn("Global and form queue for this a4j:attach component can
not be found" + getQueueName(comp));
+ return null;
+ }
+ }
+ return name;
+ }
+}
\ No newline at end of file
Modified:
root/ui/core/trunk/api/src/main/java/org/richfaces/renderkit/html/QueueRenderer.java
===================================================================
---
root/ui/core/trunk/api/src/main/java/org/richfaces/renderkit/html/QueueRenderer.java 2010-05-12
14:25:10 UTC (rev 17004)
+++
root/ui/core/trunk/api/src/main/java/org/richfaces/renderkit/html/QueueRenderer.java 2010-05-12
17:42:44 UTC (rev 17005)
@@ -21,28 +21,43 @@
*/
package org.richfaces.renderkit.html;
-import javax.faces.application.ResourceDependencies;
-import javax.faces.application.ResourceDependency;
-import javax.faces.event.AbortProcessingException;
-import javax.faces.event.ComponentSystemEvent;
-import javax.faces.event.ComponentSystemEventListener;
-import javax.faces.event.ListenerFor;
-import javax.faces.event.PostAddToViewEvent;
-import javax.faces.render.Renderer;
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import org.ajax4jsf.context.ContextInitParameters;
+import org.richfaces.cdk.annotations.JsfRenderer;
+import org.richfaces.component.AbstractQueue;
+
/**
- * @author Nick Belaevski
- *
+ * @author Nick Belaevski Renderer for queue component
*/
-//@JsfRenderer
-@ResourceDependencies( { @ResourceDependency(library = "javax.faces", name =
"jsf.js"),
- @ResourceDependency(name = "jquery.js"), @ResourceDependency(name =
"richfaces.js"),
- @ResourceDependency(name = "richfaces-queue.js")
- })
-@ListenerFor(systemEventClass = PostAddToViewEvent.class)
-public class QueueRenderer extends Renderer implements ComponentSystemEventListener {
+ @JsfRenderer(type="org.richfaces.QueueRenderer",
family="org.richfaces.Queue")
+public class QueueRenderer extends QueueRendererBase {
- public void processEvent(ComponentSystemEvent event) throws AbortProcessingException
{
- //TODO encode queue settings
+ @Override
+ protected String findAndSetQueueName(UIComponent comp) {
+ String name = null;
+ if (comp.getAttributes().get(NAME_ATTRIBBUTE) != null) {
+ name = comp.getAttributes().get(NAME_ATTRIBBUTE).toString();
+ } else {
+ UIComponent parentForm = findParentForm(comp);
+ if (parentForm != null) {
+ name = parentForm.getClientId();
+ } else {
+ name = AbstractQueue.GLOBAL_QUEUE_NAME;
+ if
(!ContextInitParameters.isGlobalQueueEnabled(FacesContext.getCurrentInstance())) {
+ LOGGER
+ .warn("Global queue is disabled by you are using unnamed
queue, so new global queue will be created with defined parameters");
+ }
+ }
+ comp.getAttributes().put(NAME_ATTRIBBUTE, name);
+ }
+ return name;
}
-}
+
+ @Override
+ protected String getQueueName(UIComponent comp) {
+ // TODO Auto-generated method stub
+ return comp.getAttributes().get(NAME_ATTRIBBUTE).toString();
+ }
+}
\ No newline at end of file
Added:
root/ui/core/trunk/api/src/main/java/org/richfaces/renderkit/html/QueueRendererBase.java
===================================================================
---
root/ui/core/trunk/api/src/main/java/org/richfaces/renderkit/html/QueueRendererBase.java
(rev 0)
+++
root/ui/core/trunk/api/src/main/java/org/richfaces/renderkit/html/QueueRendererBase.java 2010-05-12
17:42:44 UTC (rev 17005)
@@ -0,0 +1,98 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2009, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.renderkit.html;
+
+import javax.faces.application.ResourceDependencies;
+import javax.faces.application.ResourceDependency;
+import javax.faces.component.UIComponent;
+import javax.faces.component.UIForm;
+import javax.faces.context.FacesContext;
+import javax.faces.event.AbortProcessingException;
+import javax.faces.event.ComponentSystemEvent;
+import javax.faces.event.ComponentSystemEventListener;
+import javax.faces.event.ListenerFor;
+import javax.faces.event.ListenersFor;
+import javax.faces.event.PostAddToViewEvent;
+import javax.faces.event.PreRemoveFromViewEvent;
+import javax.faces.render.Renderer;
+
+import org.ajax4jsf.component.QueueRegistry;
+import org.ajax4jsf.context.ContextInitParameters;
+import org.richfaces.component.AbstractQueue;
+import org.richfaces.log.RichfacesLogger;
+import org.slf4j.Logger;
+
+/**
+ * @author Nick Belaevski Base class for rendering Queue
+ */
+// @JsfRenderer
+@ResourceDependencies( { @ResourceDependency(library = "javax.faces", name =
"jsf.js"),
+ @ResourceDependency(name = "jquery.js"), @ResourceDependency(name =
"richfaces.js"),
+ @ResourceDependency(name = "richfaces-queue.js") })
+@ListenersFor( { @ListenerFor(systemEventClass = PostAddToViewEvent.class),
+ @ListenerFor(systemEventClass = PreRemoveFromViewEvent.class) })
+public abstract class QueueRendererBase extends Renderer implements
ComponentSystemEventListener {
+
+ public void processEvent(ComponentSystemEvent event) throws AbortProcessingException
{
+ UIComponent comp = event.getComponent();
+ FacesContext context = FacesContext.getCurrentInstance();
+
+ if (event instanceof PostAddToViewEvent) {
+ String name = findAndSetQueueName(comp);
+ if (name != null) {
+ QueueRegistry.getInstance(context).registerQueue(context, name, comp);
+ }
+ } else if (event instanceof PreRemoveFromViewEvent) {
+ QueueRegistry.getInstance(context).removeQueue(context, getQueueName(comp));
+ }
+ }
+
+ protected abstract String findAndSetQueueName(UIComponent comp);
+
+ protected abstract String getQueueName(UIComponent comp);
+
+ protected static final String QUEUE_ID_ATTRIBBUTE = "queueId";
+ protected static final String NAME_ATTRIBBUTE = "name";
+ protected static final Logger LOGGER = RichfacesLogger.COMPONENTS.getLogger();
+
+ protected String findParentQueueId(UIComponent comp) {
+ UIComponent parentForm = findParentForm(comp);
+ for (UIComponent c : parentForm.getChildren()) {
+ if (c instanceof AbstractQueue) {
+ return parentForm.getClientId();
+ }
+ }
+ if
(ContextInitParameters.isGlobalQueueEnabled(FacesContext.getCurrentInstance())) {
+ return AbstractQueue.GLOBAL_QUEUE_NAME;
+ }
+ return null;
+ }
+
+ protected UIComponent findParentForm(UIComponent comp) {
+ UIComponent component = comp.getParent();
+ while (component != null && !(component instanceof UIForm)) {
+ component = component.getParent();
+ }
+
+ return component;
+ }
+}
\ No newline at end of file
Added:
root/ui/core/trunk/api/src/test/java/org/richfaces/component/QueueRendererTest.java
===================================================================
--- root/ui/core/trunk/api/src/test/java/org/richfaces/component/QueueRendererTest.java
(rev 0)
+++
root/ui/core/trunk/api/src/test/java/org/richfaces/component/QueueRendererTest.java 2010-05-12
17:42:44 UTC (rev 17005)
@@ -0,0 +1,124 @@
+/**
+ * License Agreement.
+ *
+ * JBoss RichFaces - Ajax4jsf Component Library
+ *
+ * Copyright (C) 2007 Exadel, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+
+package org.richfaces.component;
+
+import org.jboss.test.faces.ApplicationServer;
+import org.jboss.test.faces.htmlunit.HtmlUnitEnvironment;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import com.gargoylesoftware.htmlunit.html.HtmlPage;
+
+/**
+ * @author amarkhel
+ * @since 3.3.0
+ */
+public class QueueRendererTest{
+
+ private static final String EXPECTED_QUEUE_SCRIPT =
"'first':{requestDelay:'400',timeout:'100',ignoreDupResponses:'true'},'form':{requestDelay:'400'},'form:firstAttach':{timeout:'300',queueId:'form',requestGroupingId:'request'},'second':{requestDelay:'400',timeout:'100',ignoreDupResponses:'true'},'form:linkAttach':{timeout:'500',queueId:'second'},'form:secondAttach':{queueId:'form'}";
+
+ private static final String QUEUE_SCRIPT_MUST_BE_NOT_NULL = "Queue script must be
not null";
+
+ private static final String QUEUE_SCRIPT_MUST_BE_NULL = "Queue script must be
null";
+
+ private static final String SCRIPT = "</script>";
+
+ private static final String RICH_FACES_QUEUE_SET_QUEUE_OPTIONS =
"RichFaces.queue.setQueueOptions(";
+
+ protected HtmlPage page;
+
+ protected HtmlUnitEnvironment facesEnvironment;
+
+
+ @Before
+ public void setUp() throws Exception {
+ facesEnvironment = new HtmlUnitEnvironment();
+
+ ApplicationServer facesServer = facesEnvironment.getServer();
+ facesServer.addResource("/queue.xhtml",
"org/ajax4jsf/component/queue.xhtml");
+ facesServer.addResource("/nonQueue.xhtml",
"org/ajax4jsf/component/nonQueue.xhtml");
+
+ facesEnvironment.start();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ this.page = null;
+ this.facesEnvironment.release();
+ this.facesEnvironment = null;
+ }
+
+
+ @Test
+ public void testQueue() throws Exception {
+ page = renderView("/queue.jsf");
+ String responseString = page.getWebResponse().getContentAsString();
+ String queueScript = extractQueueScript(responseString);
+ assertNotNull(queueScript, QUEUE_SCRIPT_MUST_BE_NOT_NULL);
+ assertEquals(queueScript, EXPECTED_QUEUE_SCRIPT);
+ /*String[] queueArray = queueScript.split("},");
+ //String[] queueNames = new String[queueArray.length];
+ //String[] queueOptions = new String[queueArray.length];
+ for(int i = 0; i < queueArray.length - 1; i++){
+ queueArray[i] = queueArray[i] + "}";
+ }
+ String expectedArray = getQueuesByView("queue.jsf");
+ for(int i = 0; i < queueArray.length; i++){
+ String[] queues = queueArray[i].split(":");
+ queueNames[i] = queues[0];
+ queueOptions[i] = queues[1];
+ }*/
+
+ }
+
+ @Test
+ public void testPageWithoutQueue() throws Exception {
+ page = renderView("/nonQueue.jsf");
+ String responseString = page.getWebResponse().getContentAsString();
+ String queueScript = extractQueueScript(responseString);
+ assertNull(QUEUE_SCRIPT_MUST_BE_NULL, queueScript);
+
+ }
+
+ private String extractQueueScript(String responseString) {
+ String queueScript = null;
+ if(responseString.lastIndexOf(RICH_FACES_QUEUE_SET_QUEUE_OPTIONS) != -1){
+ queueScript =
responseString.substring(responseString.lastIndexOf(RICH_FACES_QUEUE_SET_QUEUE_OPTIONS) +
RICH_FACES_QUEUE_SET_QUEUE_OPTIONS.length() +1);
+ if(queueScript.indexOf(SCRIPT) != -1){
+ queueScript = queueScript.substring(0, queueScript.indexOf(SCRIPT) -3);
+ }else{
+ return null;
+ }
+ }
+ return queueScript;
+ }
+
+ protected HtmlPage renderView(String url) throws Exception {
+ page = facesEnvironment.getPage(url);
+ return page;
+ }
+}
\ No newline at end of file
Added: root/ui/core/trunk/api/src/test/resources/org/ajax4jsf/component/nonQueue.xhtml
===================================================================
--- root/ui/core/trunk/api/src/test/resources/org/ajax4jsf/component/nonQueue.xhtml
(rev 0)
+++
root/ui/core/trunk/api/src/test/resources/org/ajax4jsf/component/nonQueue.xhtml 2010-05-12
17:42:44 UTC (rev 17005)
@@ -0,0 +1,35 @@
+<html
xmlns:h="http://java.sun.com/jsf/html"
+
xmlns:f="http://java.sun.com/jsf/core"
+
xmlns:a4j="http://richfaces.org/a4j"
+
xmlns:ui="http://java.sun.com/jsf/facelets">
+
+ <h:head>
+ <title>Test queue page</title>
+
+ <h:outputScript name="jsf.js" library="javax.faces" />
+ <h:outputScript name="jquery.js" />
+ <h:outputScript name="richfaces.js" />
+ <h:outputScript name="richfaces-queue.js" />
+
+ </h:head>
+ <h:body>
+ <h:form id="form">
+ <a4j:ajax>
+ <h:inputText />
+
+ </a4j:ajax>
+ <a4j:ajax event="valueChange">
+ <h:panelGroup>
+ <a4j:ajax event="valueChange">
+ <h:inputText />
+
+ <a4j:commandLink value="Link"/>
+
+ </a4j:ajax>
+ </h:panelGroup>
+ </a4j:ajax>
+ <h:commandButton value="G"/>
+ </h:form>
+
+ </h:body>
+</html>
\ No newline at end of file
Added: root/ui/core/trunk/api/src/test/resources/org/ajax4jsf/component/queue.xhtml
===================================================================
--- root/ui/core/trunk/api/src/test/resources/org/ajax4jsf/component/queue.xhtml
(rev 0)
+++
root/ui/core/trunk/api/src/test/resources/org/ajax4jsf/component/queue.xhtml 2010-05-12
17:42:44 UTC (rev 17005)
@@ -0,0 +1,42 @@
+<html
xmlns:h="http://java.sun.com/jsf/html"
+
xmlns:f="http://java.sun.com/jsf/core"
+
xmlns:a4j="http://richfaces.org/a4j"
+
xmlns:ui="http://java.sun.com/jsf/facelets">
+
+ <h:head>
+ <title>Test queue page</title>
+
+ <h:outputScript name="jsf.js" library="javax.faces" />
+ <h:outputScript name="jquery.js" />
+ <h:outputScript name="richfaces.js" />
+ <h:outputScript name="richfaces-queue.js" />
+
+ </h:head>
+ <h:body>
+ <a4j:queue name="first" ignoreDupResponses="true"
timeout="100" requestDelay="400"/>
+ <h:form id="form">
+ <a4j:queue ignoreDupResponses="false" requestDelay="400"/>
+ <a4j:ajax>
+ <h:inputText />
+
+ <a4j:attachQueue requestGroupingId="request" timeout="300"
id="firstAttach" />
+ </a4j:ajax>
+ <a4j:queue name="second" ignoreDupResponses="true"
timeout="100" requestDelay="400"/>
+ <a4j:ajax event="valueChange">
+ <h:panelGroup>
+ <a4j:ajax event="valueChange">
+ <h:inputText />
+
+ <a4j:commandLink value="Link">
+ <a4j:attachQueue name="second" timeout="500"
id="linkAttach" />
+ </a4j:commandLink>
+
+ <a4j:attachQueue id="secondAttach" />
+ </a4j:ajax>
+ </h:panelGroup>
+ </a4j:ajax>
+ <h:commandButton value="G"/>
+ </h:form>
+
+ </h:body>
+</html>
\ No newline at end of file