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

Reply via email to