Forum OpenACS Development: OpenACS skinning

Collapse
Posted by Malte Sussdorff on
For one of our customer sites (not .LRN !) we would like to have user based look and feel. The user should be able to see the site in different CSS formated ways, depending on the style he choosed. As we do not have the time to clean up the OpenACS myriads of CSS files, here is the approach we have been thinking and maybe someone has comments on it or says, hey, this can be achieved much easier.

We would create a skinning package, which would probably just reuse the "skin" package. This (future) package contains a www/resources directory with a subdirectory for each skin. Within each subdirectory all the CSS files that are needed to display the changed skin are present. What do I mean by that: The usual OpenACS installation has a "lists.css" "forms.css" "site-master.css" "blank-master.css" loaded by default (and some others as well). If for your skin "cognovis" you only need to change the look of lists, the directory /skin/www/resources/cognovis/ would only contain a lists.css.

To identify the skin a user would like to have, we are using a cookie, which is set upon login to the site, based on the user preferences (in an extension of the users table or some other table). This approach allows us to even set cookies for not logged in users, making the site look different depending on your entry point (aka: place where we set the cookie). Obviously a user can change the default skin if he chooses to.

[skin::get_css_url -css_type "lists.css"] would then retrieve the value of the cookie (if set, otherwise use default) and see if there is a file "lists.css" in the directory of the skin name specified in the cookie. If yes, return the URL "/resources/skin/cognovis/lists.css". If not, return the default URL, which is "/resources/skin/default/lists.css". To make this work, the procedure would then have to be entered in all the places where the default css is called (e.g. site-master.adp / blank-master.adp / ....). And obviously all the spread out css files will have to be unified in one place (which I will do for the time being in our installation of the skin package).

As you will plainly see this has a performance penalty of a magnitude I don't have a clue yet, but as we are not hitting the database, we should be fairly fine. Additionally we will be using util_memoize to cache the result with two additional procedures:

[skin::get_css_url_for_user -css_type -user_id], which will return the value if the user is logged in (or nothing if no special skinned css is available). Again no clue how much this hurts the memory, but if I am not mistaken util_memoize is using memory across all threads and we are facing 400 bytes per user logged in since the last flush, which should be fine for most sites.

[skin::get_css_url_for_skin -css_type -skin] which will prevent us going to the harddisk all the time to check if there actually is a file or not. Though this means we have to flush the cache if we are adding new skins or new css files to the skin, we should still be pretty save.

One additional benefit of this approach is that I can open a specific skins directory using NFS / SMB / WebDAV / ..., so a designer could play around with it as much as he likes, without having to send me the CSS file and me going to install the CSS file in the file system, because I don't want to give him SSH access to the server.

Do you see any problems with this approach? Is there an easier way of achiving user based looks of the site?

P.S.: Once this method has proven to work, we might actually make it standard in OpenACS, having the default directory /skin/www/resources/default/ with all the skins that are usually called by default (instead of having them spread out across all the packages). Upon installation of a package, each package could then copy their css file(s) into the skin default directory.

P.P.S.: I deliberatly only went for CSS files and not the whole templating, because we needed something nice and fast without too many consequences.

P.P.P.S.: Does it make sense to put in a seperate package or should I go straight for acs-templating? As this is optional ( no need to implement it in the adp pages of your site) it would not require a TIP, would it ?

Collapse
2: Re: OpenACS skinning (response to 1)
Posted by Harish Krishnan on
Hi Malte,
We implemented a similar scheme including having master templates for http://interlink.azri.biz . Although it is not per user, it will not be a significant challenge to do it that way. Along with it we added a theme upload functionality that took a zipped file which contained the complete directory that a designer would produce. The zip file also consists of a XML manifest file (which contains the mapping between the directory structure and the theme name css folder/images/adp file for the theme) that allows the uploading action to register the theme which is then available to the admin to change. I know there are better ways of doing it but it works quite well for us.

The general directory structure we use is the following:
skin/
master/ - for adp files
www/resources/theme1 - sample theme directory which contains all the image and css files and folders.

I am not sure where to upload this on the openacs site, so in case you are interested I can upload the code somewhere.

Collapse
3: Re: OpenACS skinning (response to 2)
Posted by Malte Sussdorff on
Harish, please send it to my inbox or alternative upload it to the file storage area at OpenACS. Please add a demo skin (or two) if possible, so I could take a look how you did this exactly. This is really appreciated. If you upload, please do so at:

https://openacs.org/storage/index?folder%5fid=493034

Collapse
8: Re: OpenACS skinning (response to 3)
Posted by Harish Krishnan on
Collapse
9: Re: OpenACS skinning (response to 8)
Posted by Malte Sussdorff on
Hi Harish, I looked at the code and it seems to be missing the SQL directory. Additionally it would be great if you had one or two demo skins in the package or one of the skin uploads, which it seems to be doing.
Collapse
4: Re: OpenACS skinning (response to 1)
Posted by Dave Bauer on
Malte why not store the skin name in a client property then just have someting like this
link href="/resources/skins/@mailto:skin_name@/lists.css";
link href="/resources/skins/@mailto:skin_name@/forms.css";

You only have to load the client property frm the database if its out of memory and its only a couple of bytes for the name of the skin.

To make it work you just have to grep for CSS and fix the few files that point to a css file. Doesn't seem too hard.

Collapse
6: Re: OpenACS skinning (response to 4)
Posted by Malte Sussdorff on
Loading the client property works for logged in users, but how would this work for not logged in people? This is why I came up with the cookies.

With regards to one single CSS. Yes, absolutely, but this sadly isn't how OpenACS is structured. And I'm not sure to get rid of the myriads of CSS files yet :). But for sure I could do this, generate one large CSS file, and commit this to head, getting rid of all the seperate CSS files.

But maybe there was a reason behind splitting them up (like: Do not lead such a large CSS file all the time?).

Collapse
7: Re: OpenACS skinning (response to 4)
Posted by Malte Sussdorff on
Additionally we have been thinking about providing CSS styles per dotfolio_user. This should be pretty straightforward, just changing the location of storage :). But in this case I could probably just mimik the behaviour of the community based templates in .LRN ?
Collapse
5: Re: OpenACS skinning (response to 1)
Posted by Dave Bauer on
Even better forget all that!

Have ONE css file for each skin that includes the other css files.