Igor Vaynberg wrote:
> i guess it is not something that we support right now, but something
> that is cleary needed. we need to build a resource that can load a css
> file, parse for images, replace them, and then serve the altered content.
>
> i know almaw has been working on something like this but i dont know how
> far he got. a patch would be welcome, if not then i guess you will have
> to wait until one of the core devels has the time.
Sorry for the late reply - been on holiday. Please find attached
something that might be useful.
You'll need to change CssResource#getResourceStream() to understand how
to tell if your app is in debug mode or not (see discussion on the dev
list a week or two ago about that).
Best regards,
Al Maw
package foo.wicket.resources;
import wicket.Application;
import wicket.AttributeModifier;
import wicket.Component;
import wicket.ResourceReference;
import wicket.SharedResources;
import wicket.markup.ComponentTag;
import wicket.markup.html.WebMarkupContainer;
import wicket.model.IModel;
import wicket.model.Model;
import wicket.util.value.ValueMap;
/**
* Created on 03-May-2006.
* @author Alastair Maw
*/
public class CssReference extends WebMarkupContainer {
private static final long serialVersionUID = 1L;
/**
* Construct.
* @param id component id
* @param referer the class that is refering; is used as the relative
* root for gettting the resource
* @param file reference as a string
*/
public CssReference(final String id, final Class referer, final String file) {
this(id, referer, new Model(file));
}
public CssReference(final String id, final Class referer, final IModel file) {
super(id);
IModel srcReplacement = new Model() {
private static final long serialVersionUID = 1L;
public Object getObject(Component component) {
Object o = file.getObject(component);
if (o == null) {
throw new IllegalArgumentException("The model must provide a non-null object (component == " + component + ")");
}
if (!(o instanceof String)) {
throw new IllegalArgumentException("The model must provide an instance of String");
}
String f = (String)component.getConverter().convert(file.getObject(component), String.class);
final SharedResources sharedResources = Application.get().getSharedResources();
CssResource resource = (CssResource)sharedResources.get(referer, f, getLocale(), getStyle(), true);
if (resource == null) {
resource = new CssResource(getRequestCycle(), referer, file.getObject(component).toString());
sharedResources.add(referer, f, null, null, resource);
}
String url = getRequestCycle().urlFor(new ResourceReference(referer, f)).toString();
return url;
}
};
add(new AttributeModifier("href", true, srcReplacement));
}
/**
* @see wicket.Component#onComponentTag(wicket.markup.ComponentTag)
*/
protected void onComponentTag(ComponentTag tag) {
// Must be attached to a style tag
checkComponentTag(tag, "link");
ValueMap attributes = tag.getAttributes();
attributes.put("rel", "stylesheet");
attributes.put("type", "text/css");
}
}
package foo.wicket.resources;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import wicket.Application;
import wicket.RequestCycle;
import wicket.Resource;
import wicket.ResourceReference;
import wicket.WicketRuntimeException;
import wicket.markup.html.PackageResourceReference;
import wicket.markup.html.WebResource;
import wicket.util.lang.Packages;
import wicket.util.resource.IResourceStream;
import wicket.util.resource.ResourceStreamNotFoundException;
import wicket.util.resource.StringBufferResourceStream;
import wicket.util.resource.locator.IResourceStreamLocator;
import wicket.util.time.Time;
/**
* Created on 03-May-2006.
* @author Alastair Maw
*/
public class CssResource extends WebResource {
private static final long serialVersionUID = 1L;
private static Log log = LogFactory.getLog(CssResource.class);
/** CSS definition */
private StringBufferResourceStream css = new StringBufferResourceStream();
private Class scope;
private String path;
public CssResource(RequestCycle cycle, Class scope, String path) {
this.scope = scope;
this.path = path;
refreshResource(cycle);
}
private void refreshResource(RequestCycle cycle) {
String absolutePath = Packages.absolutePath(scope, path);
// Locate the resource
IResourceStreamLocator locator = Application.get().getResourceSettings().getResourceStreamLocator();
IResourceStream resourceStream = locator.locate(scope, absolutePath, null, null, null);
// Check that resource was found
if (resourceStream == null) {
throw new WicketRuntimeException("Unable to find package resource [path = " + absolutePath + "]");
}
try {
try {
css.clear();
BufferedReader in = new BufferedReader(new InputStreamReader(resourceStream.getInputStream()));
int lastSlash = path.lastIndexOf('/');
// We've requested a path/to/something/foo.css and now we want to
// strip off the foo.css from the end so we can construct relative
// links to url() resources, which we prefix things with.
// Note that if we don't have a slash, we'll do a substring(0, 0) == ""
String prefix = path.substring(0, lastSlash + 1);
// We assume that search and replace over the CSS is expensive, CSS isn't that big,
// and that memory is fairly cheap, so we make just throw it all into a StringBuffer.
String line;
while ((line = in.readLine()) != null) {
// Check to see if we have a "url(" token.
String[] tokens = line.split("url\\(", 2);
if (tokens.length == 2) {
// Create a new line with the bit before the "url(" token and the token itself.
String newLine = tokens[0] + "url(";
// Find the matching closing bracket of the "url(" token.
tokens = tokens[1].split("\\)", 2);
if (tokens.length == 2) {
// Find the href for the included resource.
String href = tokens[0];
/*
* The CSS 2 spec (http://www.w3.org/TR/REC-CSS2/syndata.html#uri) says:
*
* The format of a URI value is 'url(' followed by optional whitespace
* followed by an optional single quote (') or double quote (") character
* followed by the URI itself, followed by an optional single quote (')
* or double quote (") character followed by optional whitespace followed
* by ')'. The two quote characters must be the same.
*/
href = href.trim();
if (href.length() > 0) {
if ((href.charAt(0) == '\'' && href.charAt(href.length() - 1) == '\'') ||
href.charAt(0) == '"' && href.charAt(href.length() - 1) == '"') {
href = href.substring(1, href.length() - 1);
}
}
try {
String url;
final String resolvedParents = Packages.absolutePath("", prefix + href);
if (resolvedParents.startsWith("/")) {
url = cycle.urlFor(new ResourceReference(resolvedParents.substring(1)) {
@Override
protected Resource newResource() {
return ClassLoaderResource.get(resolvedParents);
}
}).toString();
}
else {
// Get a URL for packaged resource.
url = cycle.urlFor(new PackageResourceReference(scope, resolvedParents)).toString();
}
// Re-add the "url(" token's closing ")".
newLine += url;
newLine += ")";
newLine += tokens[1];
line = newLine;
}
catch (Exception e) {
log.info("Ignoring replacement for CSS resource: " + href + " - ");
e.printStackTrace();
}
}
}
// Add the line to the output, with a newline.
css.append(line);
css.append("\n");
css.setLastModified(Time.now());
}
}
finally {
resourceStream.close();
}
}
catch (ResourceStreamNotFoundException e) {
throw new WicketRuntimeException(e);
}
catch (IOException e) {
throw new WicketRuntimeException(e);
}
}
// @see wicket.Resource#getResourceStream()
public IResourceStream getResourceStream() {
// We try to refresh resources on every load if we're in development mode.
Application app = Application.get();
if (app instanceof MxWebApplication &&
((MxWebApplication)app).getAppMode().equals(Application.DEVELOPMENT)) {
RequestCycle cycle = RequestCycle.get();
// We need to check for null here, because Wicket gets the
// lastModified time without providing a RequestCycle threadlocal.
// We only refresh for the real requests.
if (cycle != null) {
log.info("Reloading CSS resource " + path);
refreshResource(cycle);
}
else {
String absolutePath = Packages.absolutePath(scope, path);
// Locate the resource
IResourceStreamLocator locator = Application.get().getResourceSettings().getResourceStreamLocator();
IResourceStream resourceStream = locator.locate(scope, absolutePath, null, null, null);
// Sort out the last modified time.
css.setLastModified(resourceStream.lastModifiedTime());
}
}
return css;
}
}
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Wicket-user mailing list
Wicket-user@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/wicket-user