Mathieu Brunot

Home

Theme changer

Published May 21, 2012

Alternative themes

Alternate themes are a (non-standard?) way to manage multiple themes for your website. The principle consists in assigning a title via the title attribute of the <link> tag to identify a theme. A theme can be made up of several CSS files and there is no limit to the number of themes that can be created.

Warning

It is still necessary to avoid having too many themes in a page! At a minimum, 1 theme is equivalent to a CSS file and, even if only one theme is applied at a time, all CSS files are still loaded and parsed by the browser (significant increase in the loading time of the page).

The problem is that this functionality is only managed by Firefox (display, style of the page), and it is not even persistent (as soon as we change the page, we go back to the theme by fault). I therefore propose here to implement JavaScript code to manage alternative themes regardless of the browser (as long as JavaScript is activated), plus a concrete application for the use of cookies for persistence of choice.

Presentation of the HTML code

A main style can be declared as follows (requires title attribute):

<link href="main.css" title="Main" rel="stylesheet" type="text/css"/>

An alternate style can be declared as follows (requires title attribute and rel attribute with alternate value):

<link href="alternative.css" title="Alternate" rel="alternate stylesheet" type="text/css"/>`

A permanent style (affecting whatever the current theme) can be declared as follows:

<link href="permanent.css" rel="stylesheet" type="text/css"/>

Management of alternative themes in JavaScript

Here is a function/class in JavaScript to manage alternative themes (functionality present under Firefox). The function/class allows to retrieve the list of themes of the page, check that a theme is present and change the current theme. The class calls the cookies manipulation functions seen in a here.

/**
 * @brief Function to create a easy-to-use theme changer.
 * 
 * Pseudo class for handling theme changes through Javascript cookies.
 * 
 * @author madmath03
 */
function themeChanger() {
	// Theme Cookie Parameters
	this.themeCookieName = "theme";
	this.themeCookieDaysDuration = 30;
	
	this.listThemes = new Array();
	/**
	 * @brief Function to get the list of themes available in the page
	 * @return array of themes (DOM 'link' Objects)
	 */
	this.getListThemes = function() {
		this.listThemes = new Array();
		var listLinks = document.getElementsByTagName("link");
		
		for (var i = 0, n = listLinks.length ; i < n ; i++) {
			if (listLinks[i].rel && (listLinks[i].rel.indexOf("style") !== -1) && listLinks[i].title) {
				this.listThemes.push(listLinks[i]);
			}
		}
		
		return this.listThemes;
	};
	
	/**
	 * @brief Function to check if a given theme exists
	 * @param themeName name of the theme
	 * @returns true if present in the list of theme, false otherwise
	 */
	this.check = function(themeName) {
		if (themeName == null || themeName.length <= 0)
			return false;
		
		var themeExists = false;
		for (var i = 0, n = this.listThemes.length ; i < n && !themeExists ; i++) {
			if (this.listThemes[i].title) {
				if (this.listThemes[i].title === themeName)
					themeExists = true;
			}
		}
		return themeExists;
	};
	
	/**
	 * @brief Function to switch to a given theme
	 * @param themeName name of the theme
	 */
	this.change = function(themeName) {
		this.getListThemes();
		// if the theme is not set or does not exist
		if (!this.check(themeName)) {
			unsetCookie(this.themeCookieName);
			return;
		}
		
		// loop through the themes
		for (var i = 0, n = this.listThemes.length ; i < n ; i++) {
			if (this.listThemes[i].title) {
				// disable all themes
				this.listThemes[i].disabled = true;
				// enable the proper one
				if (this.listThemes[i].title === themeName)
					this.listThemes[i].disabled = false;
			}
		}
		var path = getUrlPath().split('/');
		setCookie(this.themeCookieName, themeName, this.themeCookieDaysDuration, null, '/'+path[0]+'/');
	};
	
	/**
	 * @brief Function to retrieve and switch to the current theme
	 * @returns the name of the current theme
	 */
	this.getCurrentTheme = function() {
		var themeCookie = getCookie(this.themeCookieName);
		this.change(themeCookie);
		return themeCookie;
	};
	
	// Init
	this.getCurrentTheme();
}

Managing alternate themes with jQuery

Here is the equivalent function/class in jQuery:

/**
 * Function/class to create a easy-to-use theme changer.
 * 
 * Pseudo class for handling theme changes through JavaScript cookies.
 * 
 * This advanced theme changer uses jQuery.
 * @see https://jquery.com/
 * 
 * @author madmath03
 * 
 * @param $ jQuery instance
 */
function $themeChanger($) {
	// Theme Cookie Parameters
	this.themeCookieName = "theme";
	this.themeCookieDaysDuration = 30;
	
	/**
	 * @brief Function to get the list of themes available in the page
	 * @return jQuery array of themes
	 */
	this.getListThemes = function() {
		return $('html head link[rel*="style"][title]');
	};
	
	/**
	 * @brief Function to check if a given theme exists
	 * @param themeName name of the theme
	 * @returns true if present in the list of theme, false otherwise
	 */
	this.check = function(themeName) {
		if (themeName == null || !(themeName.length > 0))
			return false;
		
		return ($('html head link[rel*="style"][title="'+themeName+'"]').length > 0);
	};

	/**
	 * @brief Function to switch to a given theme
	 * @param themeName name of the theme
	 */
	this.change = function(themeName) {
		// if the theme is set and exists
		if (this.check(themeName)) {
			// for each theme CSS
			this.getListThemes().each(function() {
				this.disabled = true;
				if (this.title === themeName)
					this.disabled = false;
			});
			var path = getUrlPath().split('/');
			setCookie(this.themeCookieName, themeName, this.themeCookieDaysDuration, null, '/'+path[0]+'/');
		}
		else
			unsetCookie(this.themeCookieName);
	};

	/**
	 * @brief Function to retrieve and switch to the current theme
	 * @returns the name of the current theme
	 */
	this.getCurrentTheme = function() {
		var themeCookie = getCookie(this.themeCookieName);
		this.change(themeCookie);
		return themeCookie;
	};
	
	// Init
	this.getCurrentTheme();
}