Over the weekend I decided to give the blog a facelift, and though I had been changing the old banner's colors every month, as well as the colors of the associated style sheet, I wanted more significant changes: center the content in the browser window, and randomize the style sheet with a banner to match.
Here's what I did to get the random style sheets working properly...
Randomizing the style sheets was really no problem at all. A simple little JavaScript function takes care of that each time one of the blog's pages is rendered by a browser:
function GetRandomCSS() { var cssList = new Array( 'styles-site1.css', 'styles-site2.css', 'styles-site3.css', 'styles-site4.css', 'styles-site5.css'); var randnum = Math.floor(cssList.length * Math.random()); return cssList[randnum]; }
What this does is sets up a JavaScript array with the filenames of my style sheets as its values. A random number computation makes sure the random number generated is in the range [0..4] since JavaScript arrays begin at index zero (0). Using the random number as an index to the array, the style sheet at that index is then returned to the calling function:
function changeCSS() { document.getElementById('cssHolder').setAttribute( 'href', GetRandomCSS()); }
This function tells the browser to locate the current element on the page identified by the name "cssHolder" and set its href attribute to what is returned from the function GetRandomCSS(), which will be a random style sheet filename as described above. But for this to work properly, there needs to be an element on the page named "cssHolder":
<link rel="stylesheet" href="styles-site.css" type="text/css" id="cssHolder">
An element's href attribute is just an HTML link, and by setting the href attribute to a different style sheet filename the effect will be a change of style sheet associated with the page.
All of the pieces are together, all that's left is to make the function call to change the style sheet when the page is being rendered. This is done in the HTML body tag:
<body onload="changeCSS();">
This tells the browser to call the JavaScript function "changeCSS()" any time it begins to load the page. And while that produces the desired result and the style sheets are now randomized, I really don't want the style sheet to change every time a page is loaded. Instead, I'd like for a style sheet to be chosen at random only once, and use it for the duration of the visitor's browser session. The easiest way this can be done in JavaScript is by using a Cookie.
Getting cookies to work was by no means easy, though how I finally decided to implement them is relatively straightforward, and I'll try to explain the easiest method.
A Cookie is simply a name/value pair. You decide on a name for your cookie, give it a value, and then tell the browser to remember it for later. Sounds simple, doesn't it? Well, working with JavaScript can be very frustrating since it's difficult to see what is happening in the code. I wind up adding lots of alert statements, sometimes one after every line, just to see where the code is failing. And working through this cookie code was no exception. Here's how I finally got cookies to work, albeit in their simple default behavior:
function SetACookie(name,value) { var theCookie = name + "="; theCookie = theCookie + escape(value); document.cookie = theCookie; }
The SetACookie function sets a cookie with the name of the contents of the first parameter to the value of the contents of the second. It does so by setting the cookie property of the current document object. Easy enough. But sometimes what isn't obvious is what JavaScript is doing under-the-hood: the cookie property isn't really being set, it's being added to. By virtue of setting the property you are telling JavaScript to add your cookie and its value to the list of cookies it's maintaining for this document object.
Also worth noting: cookie values may not contain any semicolons, commas or whitespace, and so the value is encoded with the JavaScript function escape prior to storing. Doing so requires the use of unescape when retrieving the cookie, as we'll see in the next section.
I use SetACookie to set the value of a cookie named "jayis" to the filename of the randomly chosen style sheet found in the first part of this discussion. That way, when a visitor goes to another page on the site, I check the cookie to see if anything has been stored there: if so, then I use that style sheet instead of generating another random style sheet and the appearance of the site remains consistent. This is a good thing.
To check the cookie for a value:
(document.cookie.indexOf("jayis")!=-1)? cookieEnabled=true:cookieEnabled=false; if(cookieEnabled) { alert("The cookie exists");
If the JavaScript indexOf() method returns -1, that means the search string "jayis" was not found in document.cookie. Remember that document.cookie may contain many cookies, so the test is to see if it exists somewhere within the contents of document.cookie.
So, now that I'm able to set a cookie and test to see if one exists, all I need to be able to do now is fetch the value of a stored cookie and wrap all this up into some usable code. Let's start with a function that fetches the value of a stored cookie. Since cookies are strings and can be stored with other cookies, the function which retrieves a cookie's value must do some string parsing to isolate the value from the other cookies and values:
function GetCookieVal(offset) { var endstr = document.cookie.indexOf (";",offset); if (endstr == -1) { endstr = document.cookie.length; } return unescape(document.cookie.substring( offset,endstr)); } function GetACookie(name) { var arg = name + "="; var alen = arg.length; var clen = document.cookie.length; var i = 0; while(i < clen) { var j = i + alen; if (document.cookie.substring(i,j) == arg) { return GetCookieVal(j); } i = document.cookie.indexOf(" ", i) + 1; if(i == 0) break; } return null; }
The first function, GetCookieVal, simply returns the value portion of a cookie string given the offset into the string where the value begins. Obviously, the hard work has already been done here, all that is needed is to calculate where the value ends, since it might end with a semicolon indicating the beginning of another cookie, or no semicolon if it's the last cookie in the string.
The second function, GetACookie, parses through the document object's cookie string until it finds the requested cookie, or doesn't. If it finds it, it calls on the first function to return the value; otherwise null is returned.
Finally, I can wrap up my project by replacing the GetRandomCSS function with additional code that firsts checks to see if a style sheet already exists by checking for the existence of my cookie 'jayis'. If so, it returns the value which is the style sheet filename; if not, it generates a random style sheet filename and saves it in a cookie:
function GetRandomCSS() { (document.cookie.indexOf("jayis")!=-1)? cookieEnabled=true:cookieEnabled=false; if(cookieEnabled) { return GetACookie('jayis'); } else { var cssList = new Array( 'styles-site1.css', 'styles-site2.css', 'styles-site3.css', 'styles-site4.css', 'styles-site5.css'); var randnum = Math.floor(cssList.length * Math.random()); SetACookie('jayis',cssList[randnum]); return cssList[randnum]; } }
Thanks go out to RIT Professor Dan Bogaard who provided me with some of the above code, and to Dave Morgan who was a big help with debugging. The code that appears in this posting is an amalgamation from many sources. In particular, the code Prof. Bogaard gave me was derived from code by Bill Dortch at http://www.hidaho.com/cookies/cookie.txt
This solution is by no means the best since there are other attributes that cookies support to allow them to persist across browser sessions. The above code will create a cookie that will disappear when the user quits their browser. It serves the purpose I required, however, and since I spent many hours getting just the default cookie behavior implemented, I wanted to share it with anyone else who is trying to do the same thing.
Comments and questions welcome.
There is another way to use PHP dirty few lines:
Before HTML tag enter the php following:
<?
if (!isset($_COOKIE['jayis'])) {
$rand = mt_rand(1, 5);
setcookie('jayis', $rand, time()+3600, '/', '', 0);
}
$stylesheet = ">link rel='stylesheet' href='style-site" . $_COOKIE['jayis'] . ".css' type='text/css'>";
?>
Inside the header tag, do the following:
<?= $stylesheet ?>
The number 3600 is equalivent to seconds.
I am typing this code in comment, I am sure it should work..
but I haven't learned PHP yet. :-/
Thanks for the code and suggestion, David, and I'm sure there are better and/or easier ways to do it. I'm looking forward to learning about PHP in the fall in one of my graduate classes.
thanks for the tip! =)
I needed a component to export community builder users database in excel format to be downloaded by the administrator. After going through many forums i found a component SQL2Excel which could be used to export user data from joomla to excel. I downloaded and installed the same (with some help from http://www.ebook-search-queen.com ). Now the SQL2Excel is showing up under Components menu in Administrator but on clicking it , i am taken to the home page of Joomla Administrator. It is not working. I checked the installed components and modules and both are showing SQL 2 Excel as installed but i am not able to figure out why its not working properly. On click of it in components menu nothing happens just taken to home page control panel of joomla administrator. Can anyone help me out with this?
Update