Blog

Some ramblings and write-ups about tech, music, travelling and other topics.

Bashamichi Taproom

The Taproom, Bashamichi

  • Beers

I went to the opening of the Baird Bashamichi Taproom.

AJAX CSS Switching with jQuery UI and PHP

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:
$('

Git Proxy Switching

So here's a little instruction on how to set up git proxy switching to swtich between accessing your home git repos from work, where you have to go through SOCKS proxy for external access, and git repos on internal network. Setting the environment variable GIT_PROXY_COMMAND overrides whatever proxy configuration already exists - this is all we need to get git:// repositories to work. To get Git-over-SSH connections to work, which you probably want for push operations, you’ll also need to set up GIT_SSH.

~/.gitconfig-work

First of all, save the .gitconfig you use at work as ~/home/.gitconfig-work. It might look something like this:
[user]
	name = Takeshi Kanemoto
	email = [email protected]
[color]
    ui = auto
[core]
    attributesfile = ~/.gitattributes

~/.gitconfig-home

Next, we set up a .gitconfig used to access your home git repos, located on host bashmygash.com. The following example assumes that you are using gerrit to manage your git repositories, hence the port 29418.
[user]
	name = Takeshi Kanemoto
	email = [email protected]
[color]
    ui = auto
[url "ssh://[email protected]:29418/"]
    insteadOf = git://tak.atso-net.jp/
    pushInsteadOf = git://tak.atso-net.jp/
[core]
    attributesfile = ~/.gitattributes

~/.gitconfig-local

This is a .gitconfig you would use at home, pulling your local git repositories using git:// for faster access.
[user]
	name = Takeshi Kanemoto
	email = [email protected]
[color]
    ui = auto

[url "ssh://tak.kanemoto@localhost:29418/"]
    pushInsteadOf = git://tak.atso-net.jp/
[core]
    attributesfile = ~/.gitattributes

~/bin/git-switch

#!/bin/sh
# Filename: ~/bin/git-switch
# This script switches between work, home, and local
# It MUST be sourced.

echo "I: setting up for $1..."

[ -e ~/.gitconfig ] && rm -v ~/.gitconfig

case $1 in
    home)
        export GIT_SSH="${HOME}/bin/socks-ssh"
        export GIT_PROXY_COMMAND="${HOME}/bin/socks-gw"
        ln -v -s .gitconfig-home ~/.gitconfig
        ;;
    local)
        unset GIT_SSH
        unset GIT_PROXY_COMMAND
        ln -v -s .gitconfig-local ~/.gitconfig
        ;;
    work|*)
        unset GIT_SSH
        unset GIT_PROXY_COMMAND
        ln -v -s .gitconfig-work ~/.gitconfig
esac

echo "I: GIT_SSH=$GIT_SSH"
echo "I: GIT_PROXY_COMMAND=$GIT_PROXY_COMMAND"

echo "I: done!"

~/bin/socks-gw

#!/bin/sh
# Filename: ~/bin/socks-gw
# This script connects to a SOCKS proxy using connect.c
$HOME/bin/connect -H proxy.bashmygash.net:8080 $@
You will need to have a built binary from connect.c in ~/bin/connect

~/bin/socks-ssh

#!/bin/sh
# Filename: ~/bin/socks-ssh
# This script opens an SSH connection through a SOCKS server
ssh -o ProxyCommand="${HOME}/bin/socks-gw %h %p" $@

Usage

Now, all you need to do is:
. ~/bin/git-switch {work|home|local}
Or even better, you can add the following to ~/.bashrc:
alias gits='. ${HOME}/bin/git-switch'
and all you have to do is
gits {work|home|local}

References

http://threebytesfull.com/2008/04/git-with-and-without-proxy/

'\r' in bash

Sometimes in Bash, you want to display some text in the console and sometimes you may also want to have the ability to overwrite the line that you have just displayed with a new string. For example, a bash script could display a text “Working..” on the console and then, instead of display “Finished!” to the next line, you want the line that first display “Working…” be cleared and replace with the “Finished!” string. Here is a little piece of code that could do this:

#!/bin/bash
tput sc
echo -n “Working…”
for i in `seq 1 5000`;
do
echo $i > \dev\null
done
tput el1
tput rc
echo “Finished!”
Update There's actually a simpler way:
for i in `seq 1 5000`; do
    echo $i > /dev/null               # do some processing
    echo -n -e "working $i\x0d"
done