If you are like me, who is just happy with non-crappy looking pages without going into a CSS frenzy, jQuery UI definitely is probably what you're looking for. In fact, pure jQuery UI pages do look pretty awesome - all it needs is a few js/css links and a couple of lines of javascript.

If you are placing all files from jQuery UI themes in the same place, so that the common files overlap, it's very easy to switch between themes -  just a matter of changing the theme name in the path to the theme specific css file:

<link id="tk-stylesheet" type="text/css" rel="stylesheet"
    href="/script/jquery-ui/css/dot-luv/jquery-ui-1.8.4.custom.css" />

into

<link id="tk-stylesheet" type="text/css" rel="stylesheet"
    href="/script/jquery-ui/css/redmond/jquery-ui-1.8.4.custom.css" />

I was already doing this theme selection RESTfully, parsing $_GET['skin'] in php. I was looking at the ThemeRoller on the jQuery UI site, which allows you to choose from the pre-set themes and build your own, when I realized how easy it is to switch themes using AJAX in jQuery UI. All you need to do is change the href attribute. However, just changing the theme ajaxly wasn't quite enough for me - I've recently developed a login framework with PHP/MySQL as the backend and jQuery UI as the front-end. This framework also stores user settings. What I really wanted was a way for users the switch between themes ajaxly whilst saving the theme setting so that when the user logs in the next time, the chosen theme will be selected by default. So for the rest of this article I will be talking about how to do all the above, assuming you have a page set up to use jQuery UI as the front-end already, and that you have some kind of mechanism to save user settings.

Demos

I've pretty much put this skin switcher to all of my webapps. Ones that are publicly available include:

The "Short" Version

For the impatient, here's the short version:

Stylesheet Link:

<link id="tk-stylesheet" type="text/css" rel="stylesheet"
    href="/script/jquery-ui/css/dot-luv/jquery-ui-1.8.4.custom.css" />

Javascript:

if (typeof TK == "undefined") var TK = {};
TK.getCssUrl = function(skin) {
    return "/script/css-proxy.php/script/jquery-ui/css/"
    + skin + "/jquery-ui-1.8.4.custom.css?css";
};
...
$('#tk-stylesheet').attr('href', TK.getCssUrl("redmond"));

CSS fetcher:

Prepare a DOCUMENT_ROOT/script/css-proxy.phpfile which returns

file_get_contents($_SERVER['DOCUMENT_ROOT'] . $_SERVER['PATH_INFO']);

Step 1. Download jQuery UI Themes

If you are not fussed about customizing the theme, you can simply download the themes from the Gallery section on the jQuery UI Theme Roller. Unzip all themes to the same folder, overwriting any duplicates.

Step 2. PHP

Now we will start the css-proxy.php to fetch the all the CSS that you need.

if (isset($_GET["css"])) {
    header("Content-Type: text/css");

    $s = "#dummy-element{width:2px;}";

    $s .= file_get_contents($_SERVER['DOCUMENT_ROOT'] . $_SERVER['PATH_INFO']);

    $patterns = array(
        "/(url\('*)/"
    );
    $replace  = array(
        "\\1" . dirname($_SERVER['PATH_INFO']) . "/",
    );

    $s = preg_replace($patterns, $replace, $s);

    echo $s;
}

Notice the #dummy-element that has been added. This is just a way to detect whether the css has been loaded in javascript, but we will come back to this later. Here we get the path to the css file using $_SERVER['PATH_INFO']; of course, you may choose to use $_GET variable instead. Since the page that we are serving is most likely not on the same directory as the jquery-ui theme css file, we need to replace the relative image paths with the absolute paths, hence the preg_replace(...).

Step 3. Javascript

Now for the fun part. We prepare a javascript file for switching stylesheet using AJAX. It kind of assumes you have a login framework that supports user specific settings. I have created my own framework to do this; perhaps I'll write it up in another post.

$(function(){
    TK.skinSwitcher.init();
});
if (typeof TK == "undefined") var TK = {};

/* this is where we specify the path to the css-proxy.php file we have prepared earlier */
TK.getCssUrl = function(skin) {
    return "/script/css-proxy.php/script/jquery-ui/css/"
        + skin
        + "/jquery-ui-1.8.4.custom.css?css";
};

/* returns another php css proxy file in the same directory as the page being served */
TK.getCssUrl.custom = function(skin) { return "styles.php?skin=" + skin; };

/* This points to the script that allows users to persist their settings
 * using GET or POST.
 */
TK.getSettingsUrl = function() { return "/script/your-login-settings.php"; }

/* A wrapper function to get the url for saving
 * the current user's skin selection
 * If sucsessful, it should return the same skin name as parsed.
 * Otherwise it should return the currently selected skin name
 * for the current user, or the default skin name or something.
 * If you don't have a login framework, you can create a php file with just
 * * and put the path to that file in getSettingsUrl()
 */
TK.getSettingsUrl.skin = function(skin) {
    return TK.getSettingsUrl() + "?skin=" + skin;
}

/* Main skinSwitcher object */
TK.skinSwitcher = {
    dialog : null,
    message : null,
    init: function(){
        $('
').appendTo('body');
    },
    check: function(callback) {
        /* This is why we inserted the #dummy-element to the CSS
         * returned by css-proxy.php
         */
        if ($('#dummy-element').width()==2) callback();
        else setTimeout(function(){TK.skinSwitcher.check(callback)}, 250);
    },
    load : function(skin) {
        TK.skinSwitcher.message = document.createElement("div");
        $(TK.skinSwitcher.message).html(
            "

Please wait while the skin '" + skin + "' is being loaded... "); $(TK.skinSwitcher.message).dialog({ modal: true, draggable : false, resizable : false, title : "Switching skin" }); /* When working with localhost, you can setTimeout(...) * to introduce fake network latency. Comment it out for Production */ //setTimeout(function() { $.get(TK.getSettingsUrl.skin(skin), function(data){ /* Here's the core of this script; * we simply change the href attribute of the stylesheet tag. */ $('#tk-stylesheet').attr('href', TK.getCssUrl(data)); $('#tk-stylesheet-custom').attr('href', TK.getCssUrl.custom(data)); /* We start off the checking "thread" parsing a callback function * to be executed when the css has been loaded */ TK.skinSwitcher.check(function(){ $(TK.skinSwitcher.message).dialog("close").remove(); }); }); //}, 200); }, showDialog : function() { $(TK.skinSwitcher.dialog).dialog({ resizable: true, height:400, width: 600, modal: false, title : "Select a skin", show : "drop", hide : "drop", buttons: { Close: function() { $(this).dialog('close'); } } }); } }

Now you can test it using something like the following html


...

Fancy Skin Selection Dialog

In addition to the above javascript, you can create a nice dialog box with thumbnails for users to be able to select the skin.

First, scan for all skins available using PHP.

$skinsdir = $_SERVER['DOCUMENT_ROOT'] . "/script/jquery-ui/css/";
if($dir = opendir($skinsdir)) {
    while($entry = readdir($dir)){
        if($entry[0] != '.' && is_dir($skinsdir.$entry)) {
            array_push($skins, $entry);
        }
    }
    closedir($dir);
}

Then in the TK.skinSwitcher.init() function, you can insert something like:

$('
On 22 November 2010

Comments