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 ?