...

Stylesheet Switcher

liorean
02-11-2003, 12:58 AM
Ok, this is an objectified, slightly revised version of my old Theme Switcher script.

Even though this script is fully functional in all situations I've tried it in (given the basic JS, DOM, CSS compliance demands are fulfilled and cookies accepted), I still want your comments and suggestions on it, including criticism and pointing out weak points.

It's broken down in three scripts (alternatively one larger file for the entire thing), separation based on functionality of the object enclosed alone.

(Check out the cookie handler, it might be useful on it's own in other scripts.)

~~~~<cookie.js>~~~~

var cookie={ // The Cookie Handler main object
Get:function(n){ // Function for getting cookies
var re=new RegExp(n+'=([^;]*);?','gi'); // Create regex for cookies fetching
var r=re.exec(document.cookie)||[]; // Fetch cookie using regex
return unescape(r.length>1?r[1]:null) // Return unescaped cookie
},
Set:function(n,v,e,p,d,s){ // Function for setting cookies
var t=new Date; // Get current time and date
if(e) // If days to expiry is set
t.setTime(t.getTime()+(e*8.64e7)); // calculate expiry date
document.cookie=n+'='+escape(v)+'; '+(!e?'':'; expires='+t.toUTCString())+(!p?'':'; path='+p)+(!d?'':'; domain='+d)+(!s?'':'; secure') // Set cookie
},
Del:function(n,p,d){ // Function for deleting cookies
var t=cookie.Get(n); // Get cookie
document.cookie=n+'='+(!p?'':'; path='+p)+(!d?'':'; domain='+d)+'; expires=Thu, 01-Jan-70 00:00:01 GMT'; // Delete cookie
return t // Return the deleted cookie
},
Sup:function(){ // Function for detecting cookies support
cookie.Set('c',true); // Set dummy cookie
return cookie.Del('c'); // Return whether dummy was written
}
};



~~~~<event.js>~~~~

var event={ // The Event Handler main object
Add:function(f){ // Function for adding onload handlers
event.col[event.col.length]=f; // Add event handler to collection
if(typeof window.addEventListener!='undefined') // If W3C compliant
window.addEventListener('load',f,false); // Apply event handler
else if(!event.ieSet) // Otherwise, unless already set
if(typeof document.onreadystatechange!='undefined') // If supported
document.onreadystatechange=event.onload; // Add In event handler handler
event.ieSet=true; // Specify that event handler already is set
return(typeof window.addEventListener!='undefined') // Return whether W3C compliant
},
onload:function(){ // Function for handling multiple onload handlers in IE
var m=/mac/i.test(navigator.platform); // Detect whether mac
if(typeof document.readyState!='undefined') // If supported
if(m?document.readyState!='interactive':document.readyState!='complete') // And not already finished
return; // Exit
for(var i=0,f;(f=(i<event.col.length)?event.col[i]:null);i++) // For all event handlers
f(); // Run event handler
return // Exit
},
ieSet:false, // Variable to say whether event handler is set or not
col:[] // Collection for event handlers
};


~~~~<themeswitch.js>~~~~

var style={ // Theme Switcher main object
Set:function(t){ // Function for setting active theme
for(var i in this.col) // For each existing title
for(var j=0,f;(f=(j<this.col[i].length)?this.col[i][j]:null);j++) // And all stylesheets of that title
f.disabled=i!=t?true:false; // Set to enabled or disabled depending on whether title matches user input
},
Get:function(){ // Function for determining active theme
for(var i in this.col) // For each existing title
if(!this.col[i][0].disabled) // Unless disabled
return i; // Return title
return this.Pref() // Otherwise try to determine preferred title
},
Pref:function(){ // Function to determine preferred title
for(var i in this.col) // For each existing title
if(!this.col[i][0].disabled) // Unless disabled
return i; // Return title
return null // Otherwise return null
},
sum:function(){ // Function to collect existing titles into a collection
var s=document.styleSheets,i=0; // Set needed variables
for(var f;(f=(i<s.length)?s[i]:null);i++) // For each existing stylesheet
switch(f.title){ // Read title
case '': // If none or blank
break; // Exit
default: // Otherwise
switch(typeof this.col[f.title]){ // Read title
case 'object': // If exists in collection
this.col[f.title][this.col[f.title].length]=f; // Add stylesheet to that title in the collection
break; // Exit
default: // Otherwise
this.col[f.title]=[f] // Add new titla to collection and add stylesheet to that title
}
}
},
onload:function(){ // Function to send to onload handler
style.sum(); // Collect titles
if(cookie.Sup()){ // If cookies support exists
var c=cookie.Get('style'); // Get preferred theme from cookie
style.Set(c||style.Pref()) // Otherwise use the author specified
}
},
onunload:function(){ // Function to send to onunload handler
if(cookie.Sup()){ // If cookies support exists
var s=style.Get(); // Get active theme
cookie.Set('style',s,356,'/') // Write active theme to cookie
}
},
col:{} // Collection for titles
};

event.Add(style.onload); // Add onload handler
window.onunload=style.onunload; // Add onunload handler


~~~~<HTML Inclusion>~~~~

<!-- Example Containment -->
<link rel="stylesheet" type="text/css" href="standard.css" />
<link rel="stylesheet" type="text/css" href="default.css" title="Default" />
<link rel="alternate stylesheet" type="text/css" href="strange.css" title="Strange" />
/ - - - /

<a href="#" title="none" onclick="window.style.Set(this.title);return false;">Turn off themes</a><br />
<a href="#" title="Default" onclick="window.style.Set(this.title);return false;">Change to default theme</a><br />
<a href="#" title="Strange" onclick="window.style.Set(this.title);return false;">Change to strange theme</a><br />

<img src="none.png" title="Turn off themes" onclick="window.style.Set('none');return false;" /><br />
<img src="default.gif" title="Change to Default theme" onclick="window.style.Set('Default');return false;" /><br />
<img src="strange.jpeg" title="Change to Strange theme" onclick="window.style.Set('Strange');return false;" /><br />


The tutorial and full sources for it are available from <http://members.evolt.org/liorean/scripts/themeswitch-t.html>.
There are also text files explaining how to use each of the scripts in it inside the zipfile with tutorial and full sources.

// liorean

Skyzyx
02-18-2003, 09:18 AM
Looks good... I came across this a few months ago...


/*****************************
STYLESWAP
Original "StyleSwitcher" code by Paul Sowden, http://www.idontsmoke.co.uk/ss/
Modified by Aaron Jones on October 10, 2002
Modified even more by Skyzyx Genesis...
*****************************/
function setSS(zStyleSheet)
{
for(i=0; (a=document.getElementsByTagName("link")[i]); i++)
{
if(a.getAttribute("rel").indexOf("style") != -1 && a.getAttribute("title"))
{
a.disabled = true;
if(a.getAttribute("title") == zStyleSheet)
{
a.disabled = false;
new cookie('zPresetStyle', zStyleSheet, 365, '/').set();
}
}
}
}

function keepSS()
{
if (new cookie('zPresetStyle').read()) activeSS(new cookie('zPresetStyle').read());
else activeSS('');
}



Here's my cookie code, although it could definitely be slimmed down if it's only used for this...

/*****************************
COOKIE FUNCTIONALITY
Based on "Night of the Living Cookie" by Bill Dortch (Released to Public Domain)
(c) 2003, Skyzyx Technologies
*****************************/
function cookie(name, value, expires, path, domain, secure)
{
// Passed Values
this.name=name;
this.value=value;
this.expires=expires;
this.path=path;
this.domain=domain;
this.secure=secure;

// Read cookie
this.read=function()
{
var arg = this.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)
{
var endstr = document.cookie.indexOf (";", j);
if (endstr == -1) endstr = document.cookie.length;
return unescape(document.cookie.substring(j, endstr));
}
i = document.cookie.indexOf(" ", i) + 1;
if (i == 0) break;
}
return null;
}

// Set cookie
this.set=function()
{
// Store initial value of "this.expires" for re-initialization.
expStore=this.expires;

// Set time to absolute zero.
exp = new Date();
base = new Date(0);
skew = base.getTime();
if (skew > 0) exp.setTime (exp.getTime() - skew);
exp.setTime(exp.getTime() + (this.expires*24*60*60*1000));
this.expires=exp;

document.cookie = this.name + "=" + escape (this.value) +
((this.expires) ? "; expires=" + this.expires.toGMTString() : "") +
((this.path) ? "; path=" + this.path : "") +
((this.domain) ? "; domain=" + this.domain : "") +
((this.secure) ? "; secure" : "");

// Re-initialize
this.expires=expStore;
}

// Kill cookie
this.kill=function()
{
document.cookie = this.name + "=" +
((this.path) ? "; path=" + this.path : "") +
((this.domain) ? "; domain=" + this.domain : "") +
"; expires=Thu, 01-Jan-70 00:00:01 GMT";
}

// Change cookie settings.
this.changeVal=function(chVal) { this.kill(); this.value=chVal; this.set(); }
this.changeExp=function(chExp) { this.kill(); this.expires=chExp; this.set(); }
this.changePath=function(chPath) { this.kill(); this.path=chPath; this.set(); }
this.changeDomain=function(chDom) { this.kill(); this.domain=chDom; this.set(); }
this.changeSecurity=function(chSec) { this.kill(); this.secure=chSec; this.set(); }
}



The CSS <link> tags must have the TITLE attribute...
<link rel="stylesheet" href="default.css" title="Default" />

You'd add it to the HTML page like this...

<!-- Inside the HEAD tags... -->
<script language="javascript" type="text/javascript">
<!--
keepSS();
//-->
</script>

<!-- Inside the BODY somewhere... -->
<a href="#" onclick="activeSS('Default');">New Stylesheet</a>

liorean
02-18-2003, 03:21 PM
Oh, I know of Paul's style switcher (presented in an article on ALA quite some time ago) I had just written a mechanism that was much less potent when I read his article - and I decided that I would rework my code to be a full switcher. Later, I reworked it again and allowed it to use stylesheets no matter how they are defined, instead of just taking link tags into account.

Throw in my cookie handler and it was pretty much finished.

Now, my switcher has some points that Paul's hasn't - it's objectbound, shorter (If you erase all that unnecessary commenting, anyway), and can handle all stylesheets instead of only link tags.

Skyzyx
02-18-2003, 04:27 PM
Cool!

DooM_MonkeY
06-17-2004, 02:42 AM
Why not just a simple



<script>

function swap-style(theHref) {

document.all.styleSheet.href=theHref;
}
</script>

<link rel="stylesheet" id="styleSheet" type="text/css">

<a href="javascript:void;" onclick="swap-style('style.css');">Swap Style 1</a>

glenngv
06-17-2004, 06:23 AM
...suggest a solution that will only work (if at all) in IE. :rolleyes:

joh6nn
06-17-2004, 01:03 PM
that method works just fine, actually ( aside from the point that he's using document.all ). i'm using it on my site.

jkd
06-17-2004, 06:38 PM
AFAIK, all others browsers implement UI for switching to alternate stylesheets. The point of using multiple <link/>'s is to provide all of the stylesheets to the browser through markup, then using Javascript for IE to hack a UI. And since you have all these <link/>'s in markup now, it doesn't really matter if you're changing href's or rel's. Probably better to change the rel's because if you're changing the href of a single <link/> element, you may end up with dubious semantics (two links to the same stylesheet, but one with rel="stylesheet" and another to rel="alternate stylesheet").

oldcrazylegs
06-17-2004, 07:20 PM
Style Sheet Switcher script here http://www.codelifter.com/main/javascript/changestyles.html

DooM_MonkeY
06-21-2004, 04:15 AM
that method works just fine, actually ( aside from the point that he's using document.all ). i'm using it on my site.

If not document.all, what should I use? Would I go

getElementById('Stylesheet').href=theStyle;

?

joh6nn
06-21-2004, 10:23 PM
Doom Monkey: that looks about right.

jkd: you're thinking in the context of alternate-styles provided by the author. i'm thinking in the context of web-site skins defined by the user.

it did occur to me though that i may have read somewhere that the href attribute isn't supposed to be read/write, but rather read-only. haven't had a chance to look that up and confirm it. the only reason i've been using that method anyway, is because the Dom replaceChild method was crashing Fire Fox. i'll have to check and see if that's fixed in 0.9

DooM_MonkeY
06-22-2004, 08:13 PM
Oops, sorry, thats javascript:void(0); on the href of the link, typed too fast i guess

so it should be change to



<script>

function swapStyle(theHref) {

document.getElementById('styleSheet').href=theHref;
}
</script>

<link rel="stylesheet" id="styleSheet" type="text/css">

<a href="javascript:void(0);" onclick="swapStyle('style1.css');">Swap Style 1</a>



?¿?

glenngv
06-23-2004, 02:48 AM
It's good that you provide an alternative to Javascript-disabled browsers.

function swapStyle(theHref) {
if (document.getElementById) document.getElementById('styleSheet').href=theHref;
else alert('Sorry, not supported.');
return false; //cancels link action
}

If you're using a server-side language:

<a href="page.php?s=style1.css" onclick="return swapStyle('style1.css');">Swap Style 1</a>

If none:

<a href="nojavascriptmsg.htm" onclick="return swapStyle('style1.css');">Swap Style 1</a>

or

<a href="#" onclick="return swapStyle('style1.css');">Swap Style 1</a>

DooM_MonkeY
06-23-2004, 03:50 AM
oh so thats what the "return true/false" does, which one does what though?

glenngv
06-23-2004, 04:31 AM
If you return false to an event handler, normally the event will be suppressed. Otherwise, it won't.

Try this:

<form action="javascript:alert('submitted')" onsubmit="alert('This is an unsubmittable page.');return false">

<a href="page.htm" onclick="return false;">Unclickable link</a>

<a href="page.htm" onclick="alert('hello');return true;">The alert will show but the browser will still go to the specified url in href</a>

<input type="submit" value="Submit" />
</form>

DooM_MonkeY
06-23-2004, 06:08 AM
Oh I get it now, so if it is return false, the link wont go anywhere, but if its return true, its just normal right?

glenngv
06-23-2004, 07:13 AM
Right. That is, of course, if javascript is enabled.



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum