Post Reply 
Author Prefix URLs in CSS Templates Specification
fbernardo
AT core team member

Find all posts by this user
Quote this message in a reply
Default  29 January 2014 18:27
Requirements
The goal of this development is to introduce the possibility to add images, and media in general, inside CSS Templates without knowing where static files will be finally deployed. In other words, giving the possibility to the users to easily add media without useless worries about paths.This option should call an external class in charge of doing the url mapping for images and replace the image urls inside the CSS templates with the result of the mapping.

Use cases
A user responsible for the customization of an Aria Templates application needs to customize the application adding images through the CSS property background. He is not responsible of the deploy of the application, so he doesn't know anything about where the static files will be finally deployed. Instead of writing wrong urls, he just defines a short path and leaves the task of adding the final path to the guy responsible of deploying the application.

The customizer will write something like this:

.myimage {
     background: url(images/myImage.png);
}

and the final result will be something like this:

.myimage {
     background: url([prefix]images/myImage.png);
}

Technical Solution
The solution proposes to add a configuration property to the app environment, where the user can specify the method to call in order to do the url mapping for the images.
The property will be imgUrlMapping. So inside aria/templates/environment will be added a bean to describe this property:

$type: "json:FunctionRef"
$default: null
$description: "Method to map image urls inside css templates."

Inside aria/templates/CSSCtxt.js, inside _getOutput method, will be added a method that searches the urls inside the CSS template, calls the method of the external class and updates the urls. So the idea to parse the CSS templates is to use a regexp in order to match the pattern url() and url(" ") and return the content of the brackets. Then the method calls the external class method, passing the result of the parsing action and the CSS template classpath and wait for the whole path to put inside the CSS rule. The internal method will look only for urls inside background properties, it won't identify any urls related to inline style or image elements.


History
31/01/2014 Update of the technical solution - F. Bernardo
29/01/2014 Creation of the specification - F. Bernardo
(This post was last modified: 6 February 2014 09:57 by fbernardo.)
Marc Laval
AT core team member

Find all posts by this user
Quote this message in a reply
30 January 2014 10:11
Looks fine to me!
jakub-g
AT core team member

Find all posts by this user
Quote this message in a reply
Default  30 January 2014 11:17
I think this might be more complex than it looks at the first glance (though I might be wrong).

I don't like overengineering simple things, but there are a number of edge cases here, we should either investigate it and support them, or tell explicitly we don't support them.

A) There are many properties that can accept URL as a value:

background-image (hence also background), some exotic ones like cursor, list-style-image (hence list-style too) and probably more

https://developer.mozilla.org/en-US/docs...cursor/url
https://developer.mozilla.org/en-US/docs...tyle-image
http://www.w3.org/TR/CSS2/syndata.html#uri

So IMO we should just look for url() and maybe preceding : and not necessarily for hardcoded property list

B) remember about special case for data URIs which naturally shouldn't be prefixed

We've already had some issues with data URIs in the past:
https://github.com/ariatemplates/ariatem...issues/721

C) value inside URL can be quoted with " or ' but does not have to be

[1] http://stackoverflow.com/questions/21688...tes-needed

D) the URLs can contain parentheses () [2], semicolons ; [3] and what not.

[2] http://stackoverflow.com/questions/11780...85#1178285
[3] http://www.ietf.org/rfc/rfc1738.txt

Quote: Thus, only alphanumerics, the special characters "$-_.+!*'(),", and
reserved characters used for their reserved purposes may be used
unencoded within a URL.

Especially, the URL can contain a parenthesis and a semicolon after it Smile
I guess we can ignore colon : even though it's valid in URLs because no one sane would use it (especially since filenames in Windows can't contain it)

Hence I guess this should be valid CSS (haven't tested)

background-image:url(foo(1);IAmAnnoying.png);
another-prop:url(folder/url(2).png);
yet-another-prop:url ( "foo(3).png" )

To be investigated, if those kinds of things work cross-browser, the implementation should be aware of it.

If we assume : can't be in the URL, we can probably search for:

:\s*url\(\s*\"
:\s*url\(\s*\'
:\s*url\(\s*


and just push the prefix after the match, unless what follows is data:


Edit:

http://www.w3.org/TR/CSS2/syndata.html#uri

Quote:Some characters appearing in an unquoted URI, such as parentheses, white space characters, single quotes (') and double quotes ("), must be escaped with a backslash so that the resulting URI value is a URI token: '\(', '\)'.

So this is invalid due to unescaped parentheses

background-image:url(foo(1);IAmAnnoying.png);
but this should be ok
background-image:url("foo(1);IAmAnnoying.png");

http://jakub-g.github.io/
(This post was last modified: 30 January 2014 11:29 by jakub-g.)
divdavem
AT core team member

Find all posts by this user
Quote this message in a reply
Default  30 January 2014 13:42
I would prefer not to add a new feature which relies on classpaths, especially as we are in the process of getting rid of them.

And if we have a classpath in the environment, we need to load the corresponding class, and the correct time to do it is not so obvious. Doing it in the CSSClassLoader, as you suggest, may seem to be a nice idea because this is when there is an asynchronous operation related to CSS templates. However, we should also be able to change the mapping class in the environment after all the CSS template classes have been loaded... so, do we need to load the class at several places? This is adding extra complexity.
I know we already accept classpaths for other things in the app environment (URL service, request handler...). But then for each new classpath configuration parameter added to the environment, we are adding some new code in a different place to load the corresponding class. There should perhaps be a unified and clear way to load all those classes defined in the environment.

I would prefer having in the environment a direct reference to the class instance, or to just have a reference to the function which does the mapping (we already accept functions in the environment for some parameters like for date and type formats).
@all: What do you think?

Another remark: I think it would be good to clarify in the spec what happens with the CSS templates of the skin (for AriaLib widgets). There is a parameter in the skin allowing to specify the root of images (general.imagesRoot). I suppose it is then the role of the mapping class to just ignore CSS templates of the AriaLib.
Note that in the CSS templates of the skin, the url does not immediately follow the colon, we use something like this (cf aria.widgets.AriaSkinInterface.backgroundMacro):

var rule = ["background: ", color, " ", fullUrl, otherparams, ";"];
if (gifUrl) {
    rule.push("_background-image: url(", gifUrl, ") !important;");
}
fbernardo
AT core team member

Find all posts by this user
Quote this message in a reply
Default  30 January 2014 13:47
As I said the goal is
Quote: to give the possibility to the users to easily add media without useless worries about paths.

Who, in the world, is using an URL like this:
background-image:url(foo(1);IAmAnnoying.png);
to add a background image through CSS?
flongo
AT core team member

Find all posts by this user
Quote this message in a reply
30 January 2014 14:04
1) I guess we don't actually care about the css property, we will just look for "url(...)", wherever it is, and pass whatever we find inside the parentheses to the correct method.

2) skin interaction: It is up to the function that maps urls to distinguish between skin images or other images. It is possible to access the imagesRoot property of the skin, so it's easy to perform a check.

3) I agree with David about the easiness of just receiving the function that does the mapping. My only concern is that functions are not serializable, whereas strings are... I like the idea of having serializable app environment configuration.

4) What if that environment variable changes? We don't care. It is not in the requirements to update all CSS Templates. What we could do, is to raise a warning to inform the user that a change of that variable won't trigger the refresh of the css templates that have already been processed.
jakub-g
AT core team member

Find all posts by this user
Quote this message in a reply
30 January 2014 14:18
(30 January 2014 13:47)fbernardo Wrote:  As I said the goal is
Quote: to give the possibility to the users to easily add media without useless worries about paths.

Who, in the world, is using an URL like this:
background-image:url(foo(1);IAmAnnoying.png);
to add a background image through CSS?

You never who the customizers are Smile
BTW who the hell uses unquoted data URIs? Seems that @melthuamy does https://github.com/ariatemplates/ariatem...issues/721 and probably a number of users.
I'm just pointing out a potential issue to be taken care of, not to have PTRs in the future.

(30 January 2014 14:04)flongo Wrote:  1) I guess we don't actually care about the css property, we will just look for "url(...)", wherever it is, and pass whatever we find inside the parentheses to the correct method.

Yep, but as I mentioned, there could be parentheses inside the URL so some care is needed

(30 January 2014 14:04)flongo Wrote:  3) I agree with David about the easiness of just receiving the function that does the mapping. My only concern is that functions are not serializable, whereas strings are... I like the idea of having serializable app environment configuration.

Direct function as suggested by David is a very good and easy solution, @Francesco, is there some special usage why you prefer serializable environment?

http://jakub-g.github.io/
fbernardo
AT core team member

Find all posts by this user
Quote this message in a reply
Default  30 January 2014 14:18
Quote:I would prefer having in the environment a direct reference to the class instance, or to just have a reference to the function which does the mapping (we already accept functions in the environment for some parameters like for date and type formats).
@all: What do you think?

I like the idea to accept a method as input, it will simplify and reduce the impact on framework side.


About the URL, I'd prefer to reduce the possibility and only search for something like:

url(...)

and that's it. If your css rule doesn't match, you should change your css rule.
(This post was last modified: 30 January 2014 14:33 by fbernardo.)
flongo
AT core team member

Find all posts by this user
Quote this message in a reply
Default  30 January 2014 14:36
@jakub. Yes, there is a usecase: you might want to save the environment configuration somewhere to reuse it.

But since we already allow other functions, I guess we just don't care.


As far as the url content is concerned, if there is a parenthesis inside there could be issues. We should see how browsers interprest them and define the proper regular expression.
benoit.charbonnier
AT core team member

Find all posts by this user
Quote this message in a reply
Default  30 January 2014 14:42
I might be stupid, but I ask myself a small question.

In the scope of customization, if the guy need to add a new image as a css background, it means to me a few basic things:

1/ He is going to use an already existing image (in the scope of the application he is customizing) so he should basically already know the full url of the resource.

or

2/ It is an external image, same conclusion, he should know the full url of the image.

or

3/ It is a complete new image, that goes along with its customization, so the image should be part of the customized component (in APP a component is a kind of folder where all you static files (tpls, controllers, csstpls) are located). Which means that the image should be available with a dynamic replacement at APP level (see an attempt of explanations just below...)

So for me there is nothing to do !!

Explanations, today in APP, they don't specify any classpaths in there templates (I would neither in their css templates). They are automagically handled by APP layers.
So we might just need an API to specify to APP that this resource define inside the css is part of the component itself, and so it should be processed by an APP Layer before the template content is being sent back to the client...

---------------------------------------------------------------------

EDIT So they have real classpaths ! Smile So i don't even see what we should have to do.. They could use this.$package.replace(".", "/") combined with rootFolderPath to have a path back to the folder where is the tplcss
(This post was last modified: 30 January 2014 16:38 by benoit.charbonnier.)
Post Reply