var BUILD_DATE = "20080905092037";
var utils;
function load(){
var isSupported = utils.isSupportedBrowser();
if (!isSupported) {
var messageDiv = document.getElementById("incompatibleBrowserMessage");
var msg = 'For optimal Wetpaint performance we recommend the latest versions of Internet Explorer or Firefox. For Mac users, we recommend Firefox instead of Safari.';
messageDiv.innerHTML = msg;
messageDiv.style.display = 'block';
}
}
window.baseInit = window.init;
if( window.baseInit == null ) window.baseInit = function(){}
init = function( fcn ){
if( ! window.initFunctions )
window.initFunctions = new Array();
if( typeof(fcn) == "string")
window.initFunctions[ window.initFunctions.length ] = fcn;
else{
baseInit();
for( var i=0; i 0) ? document.documentElement.scrollLeft : document.getElementById("allcontent").scrollLeft;
pos.top = (window.scrollY) ? window.scrollY : (document.documentElement.scrollTop > 0) ? document.documentElement.scrollTop : document.getElementById("allcontent").scrollTop;
return pos;
}
/**
* Returns an object with two parameters indicating the window dimensions in pixels.
* Note that this method fakes an understanding of a vertical scrollbar (presumes 18px).
* @return Object with x and y coordinates of window dimensions.
* @type Object
*/
utils.getWindowDimensions = function() {
var dim = {x:null,y:null};
if (self.innerHeight){
// all except Explorer
dim.x = self.innerWidth - 18;
dim.y = self.innerHeight;
} else if (document.documentElement && document.documentElement.clientHeight){
// Explorer 7 and 6 Strict Mode
if (this.isMSIE7) {
dim.x = document.documentElement.clientWidth;
}else{
dim.x = document.documentElement.clientWidth - 18;
}
dim.y = document.documentElement.clientHeight;
} else if (document.body){
// other Explorers
dim.x = document.body.clientWidth - 18;
dim.y = document.body.clientHeight;
}
return dim;
};
/**
* Returns a node referencing the first element in the ancestry matching the starting node.
* Will find instances of specific class names within space-seperated className list.
* @param {node} node Starting DOM element node.
* @param {String} names List of node names to be matched, comma separated.
* @param {String} attrib_name (optional) Name of attribute required in matching node.
* @param {String} attrib_name (optional) If attrib_name is specified, value of attribute required in matching node.
* @param {node} stop_node (optional) Node that, if encountered, we stop looking for additional nodes.
* @return Element referencing parent node.
* @type Element
*/
utils.getParentElement = function(node, names, attrib_name, attrib_value, stop_node) {
if (this.isMSIE && attrib_name == 'class') attrib_name = 'className';
if (node == null) return null; //return null, as no node is defined.
if (typeof(names) == "undefined" || names == null) {
if (node.nodeType == 1) return node;
while ((node = node.parentNode) != null && node.nodeType != 1) ; // Find parent node that is a element
return node; //return any node, as names is not defined.
}
var namesAr = names.split(',');
do {
for (var i=0; i';
if (testStartElement == testEndElement) return testStartElement;
} while (testEndElement = testEndElement.parentNode);
testEndElement = endElement;
} while (testStartElement = testStartElement.parentNode);
}
} else {
if (range.item) return range.item(0);
if (range.parentElement().tagName.toLowerCase() == 'tbody') return range.parentElement().offsetParent;
return range.parentElement();
}
}
//no common container found.
return null;
};
/**
* This method replaces range.compareNode(), which was deprecated in Gecko 1.9 (i.e: Firefox 3).
*
* @param range The range for the comparison.
* @param node The node to compare.
*
* @return one of the following constant integer values:
*
*
0. The node occurs before the specified range.
*
1. The node occurs after the specified range.
*
2. The specified range occurs within the node.
*
3. The node occurs within the specified range.
*
*/
utils.rangeCompareNode = function( range, node ) {
if( range.compareNode ) return range.compareNode(node);
if( !node ) return 3;
var nodeRange = node.ownerDocument.createRange();
try { nodeRange.selectNode(node); } catch(e) { nodeRange.selectNodeContents(node); }
var nodeIsBefore = range.compareBoundaryPoints( Range.START_TO_START, nodeRange ) == 1;
var nodeIsAfter = range.compareBoundaryPoints( Range.END_TO_END, nodeRange ) == -1;
if( nodeIsBefore && !nodeIsAfter ) return 0; // Range.NODE_BEFORE
if( !nodeIsBefore && nodeIsAfter ) return 1; // Range.NODE_AFTER
if( nodeIsBefore && nodeIsAfter ) return 2; // Range.NODE_BEFORE_AND_AFTER
return 3; // Range.NODE_INSIDE
};
/**
* Returns a reference to a document tree node that contains the start point of a Range or TextRange.
* This method ignores empty Text elements at the start of the selection and accounts for selected images.
* @param {Range} range A W3C DOM Range object, or an IE TextRange object.
* @return Element referencing node containing the start of the range.
* @type Element
*/
utils.getStartContainer = function(range) {
if (range) {
if (range.cloneContents) {
//Trim leading empty text node if exists.
var docFragment = range.cloneContents();
if (docFragment.childNodes.length > 1 && docFragment.childNodes[0].nodeType == 3 && docFragment.childNodes[0].length == 0) {
return this.getTextElement(range.startContainer.nextSibling);
} else if (docFragment.childNodes.length == 1 && docFragment.childNodes[0].nodeName.toLowerCase() == 'img') {
var fragSrc = utils.regexpReplace(docFragment.childNodes[0].src,'^http://(.*?)/','','i')
var imageMatches = this.getElementsByAttributeValue(range.startContainer,'img','src',fragSrc)
for (var i=0;i 1 && docFragment.childNodes[docFragment.childNodes.length-1].nodeType == 3 && docFragment.childNodes[docFragment.childNodes.length-1].length == 0) {
return this.getTextElement(range.endContainer.previousSibling);
} else if (docFragment.childNodes.length == 1 && docFragment.childNodes[docFragment.childNodes.length-1].nodeName.toLowerCase() == 'img') {
var fragSrc = utils.regexpReplace(docFragment.childNodes[docFragment.childNodes.length-1].src,'^http://(.*?)/','','i')
var imageMatches = this.getElementsByAttributeValue(range.endContainer,'img','src',fragSrc)
for (var i=0;i=0){
if(warnHTML){
messageNode.innerHTML = messageNode.innerHTML = warnHTML.replace('[REMCHARS]',remaining);
} else{
messageNode.innerHTML = "Note: You can enter up to "+remaining+" additional characters.";
}
return true;
}else{
if(limitHTML){
messageNode.innerHTML = limitHTML.replace('[CURCHARS]',currLength).replace('[MAXCHARS]', maxchars);
} else {
messageNode.innerHTML = "You have entered "+currLength+" characters. The limit is "+maxchars+".";
}
return false;
}
}
/**
* A class to parse color values
* @author Stoyan Stefanov
* @link http://www.phpied.com/rgb-color-parser-in-javascript/
* @license Use it if you like it
*/
function RGBColor(color_string){
this.ok = false;
// strip any leading #
if (color_string.charAt(0) == '#') { // remove # if any
color_string = color_string.substr(1,6);
}
color_string = color_string.replace(/ /g,'');
color_string = color_string.toLowerCase();
// array of color definition objects
var color_defs = [
{
re: new RegExp("^rgb\\((\\d{1,3}),\\s*(\\d{1,3}),\\s*(\\d{1,3})\\)$"),
example: ['rgb(123, 234, 45)', 'rgb(255,234,245)'],
process: function (bits){
return [
parseInt(bits[1]),
parseInt(bits[2]),
parseInt(bits[3])
];
}
},
{
re: new RegExp("^(\\w{2})(\\w{2})(\\w{2})$"),
example: ['#00ff00', '336699'],
process: function (bits){
return [
parseInt(bits[1], 16),
parseInt(bits[2], 16),
parseInt(bits[3], 16)
];
}
},
{
re: new RegExp("^(\\w{1})(\\w{1})(\\w{1})$"),
example: ['#fb0', 'f0f'],
process: function (bits){
return [
parseInt(bits[1] + bits[1], 16),
parseInt(bits[2] + bits[2], 16),
parseInt(bits[3] + bits[3], 16)
];
}
}
];
// search through the definitions to find a match
for (var i = 0; i < color_defs.length; i++) {
var re = color_defs[i].re;
var processor = color_defs[i].process;
var bits = re.exec(color_string);
if (bits) {
channels = processor(bits);
this.r = channels[0];
this.g = channels[1];
this.b = channels[2];
this.ok = true;
}
}
// validate/cleanup values
this.r = (this.r < 0 || isNaN(this.r)) ? 0 : ((this.r > 255) ? 255 : this.r);
this.g = (this.g < 0 || isNaN(this.g)) ? 0 : ((this.g > 255) ? 255 : this.g);
this.b = (this.b < 0 || isNaN(this.b)) ? 0 : ((this.b > 255) ? 255 : this.b);
// some getters
this.toRGB = function () {
return 'rgb(' + this.r + ', ' + this.g + ', ' + this.b + ')';
}
this.toHex = function () {
var r = this.r.toString(16);
var g = this.g.toString(16);
var b = this.b.toString(16);
if (r.length == 1) r = '0' + r;
if (g.length == 1) g = '0' + g;
if (b.length == 1) b = '0' + b;
return '#' + r + g + b;
}
this.colorDistance = function (r2, g2, b2) {
var a = r2 - this.r;
var b = g2 - this.g;
var c = b2 - this.b;
return Math.sqrt (a*a + b*b + c*c);
}
this.dToWhite = this.colorDistance(255, 255, 255);
this.dToBlack = this.colorDistance(0 ,0 ,0);
this.isDark = function() {
return this.dToBlack < this.dToWhite;
}
this.blackOrWhiteOrGray = function(){
// try to return Gray unless current color is near gray
// if so, return black or white, whichever is farther from current
dToGray = this.colorDistance(151, 151, 151);
if((dToGray - this.dToBlack) > (dToGray - this.dToWhite) ){
return (dToGray > this.dToBlack) ? 'Gray' : 'White' ;
} else {
return (dToGray > this.dToWhite) ? 'Gray' : 'Black' ;
}
}
}
function HSVColor(initial_color_string){
this.ok = false;
// array of color definition objects
this.color_defs = [
{
re: new RegExp("^hsv\\((\\d{1,3}),\\s*(\\d{1,3}),\\s*(\\d{1,3})\\)$"),
example: ['hsv(360, 100, 100)', 'hsv(243,67,60)'],
process: function (bits){
return [
parseInt(bits[1]),
parseInt(bits[2]),
parseInt(bits[3])
];
}
}, {
re: new RegExp("^(\\w{2})(\\w{2})(\\w{2})$"),
example: ['#00ff00', '336699'],
process: function (bits){
//HSV calculation
var hsvR = Math.round(parseInt(bits[1],16)/.255)/1000;
var hsvG = Math.round(parseInt(bits[2],16)/.255)/1000;
var hsvB = Math.round(parseInt(bits[3],16)/.255)/1000;
var max = Math.max(Math.max(hsvR, hsvG), hsvB);
var min = Math.min(Math.min(hsvR, hsvG), hsvB);
var hue = 0;
var saturation = 0;
var brightness = Math.round(max*100)/100;
var delta = Math.round((max - min)*1000)/1000;
if (max != 0) {
saturation = Math.round((delta / max)*100)/100;
} else {
saturation = 0;
hue = -1;
}
if (hsvR == max) {
hue = (Math.round((hsvG - hsvB)*100)/100) / delta;
} else if(hsvG == max) {
hue = 2 + (Math.round((hsvB - hsvR)*100)/100) / delta;
} else {
hue = 4 + (Math.round((hsvR - hsvG)*100)/100) / delta;
}
hue *= 60;
if (hue < 0) hue += 360;
//window.status = bits[1] + '-' + bits[2] + '-' + bits[3] + ' ... ' + hsvR + '-' + hsvG + '-' + hsvB + ' ... ' + max + '-' + min + '-' + delta + ' ... ' + Math.round(hue) + '-' + parseInt(saturation*100) + '-' + parseInt(brightness*100)
return [
Math.round(hue),
parseInt(saturation*100),
parseInt(brightness*100)
];
}
}
];
//setter
this.setValues = function (color_string) {
// strip any leading #
if (color_string.charAt(0) == '#') { // remove # if any
color_string = color_string.substr(1,6);
}
color_string = color_string.replace(/ /g,'');
color_string = color_string.toLowerCase();
// search through the definitions to find a match
for (var i = 0; i < this.color_defs.length; i++) {
var re = this.color_defs[i].re;
var processor = this.color_defs[i].process;
var bits = re.exec(color_string);
if (bits) {
channels = processor(bits);
this.hue = channels[0];
this.saturation = channels[1];
this.brightness = channels[2];
this.ok = true;
}
}
// validate/cleanup values
this.hue = (this.hue < 0 || isNaN(this.hue)) ? 0 : ((this.hue > 360) ? 360 : this.hue);
this.saturation = (this.saturation < 0 || isNaN(this.saturation)) ? 0 : ((this.saturation > 100) ? 100 : this.saturation);
this.brightness = (this.brightness < 0 || isNaN(this.brightness)) ? 0 : ((this.brightness > 100) ? 100 : this.brightness);
}
// some getters
this.toHex = function () {
var red;
var green;
var blue;
var hue = this.hue;
var saturation = this.saturation/100;
var brightness = this.brightness/100;
var i, f, p, q, t;
if (saturation == 0) {
red = green = blue = brightness;
}
hue /= 60; // sector 0 to 5
i = Math.floor( hue );
f = hue - i;
p = brightness * ( 1 - saturation );
q = brightness * ( 1 - saturation * f );
t = brightness * ( 1 - saturation * ( 1 - f ) );
switch( i ) {
case 0: red = brightness; green = t; blue = p; break;
case 1: red = q; green = brightness; blue = p; break;
case 2: red = p; green = brightness; blue = t; break;
case 3: red = p; green = q; blue = brightness; break;
case 4: red = t; green = p; blue = brightness; break;
default: red = brightness; green = p; blue = q; break;
}
//window.status = this.hue + ' ... ' + hue + '-' + saturation + '-' + brightness + ' ... ' + Math.round(red*255) + '-' + Math.round(green*255) + '-' + Math.round(blue*255) + ' ... ' + i + '-' + f + '-' + p + '-' + q + '-' + t;
red = Math.round(red*255).toString(16);
green = Math.round(green*255).toString(16);
blue = Math.round(blue*255).toString(16);
if (red.length == 1) red = '0' + red;
if (green.length == 1) green = '0' + green;
if (blue.length == 1) blue = '0' + blue;
return '#' + red + green + blue;
}
this.toHSV = function () {
return 'hsv(' + this.hue + ', ' + this.saturation + ', ' + this.brightness + ')';
}
//load from initialization.
if (initial_color_string) this.setValues(initial_color_string);
return this;
}
utils.toggleMinMax = function(who, which){
if(typeof(who) == 'object'){
if(who.className.substring(0,6) == "toggle"){
switch(which){
case "min": who.className = "toggleMin";
break;
case "max": who.className = "toggleMax";
break;
default: who.className = (who.className == "toggleMin")? "toggleMax" : "toggleMin";
}
}else{
this.toggleMinMax(who.offsetParent, which);
}
}else{
// throw error
}
}
utils.getSortUri = function(sort) {
var params = location.search.getObjectFromQuerystring();
var sortParam = "sort=" + sort;
var uri = location.href;
if (params["sort"]) {
uri = location.href.replace(new RegExp("\\bsort=[^\\&]*\\b"), sortParam);
} else {
uri += (location.search.length > 0) ? "&" + sortParam : "?" + sortParam;
}
var offsetRE = new RegExp("\\boffset=[^\\&]*\\b");
if (offsetRE.test(uri)) uri = uri.replace(offsetRE, "offset=0");
return uri;
}
/**
* Tracking
* omniture
*/
utils.logMacroEvent = function( eventName, eventCode ){
if(typeof(s_gi)!='undefined'){
try{
s_w=s_gi(s_account);
s_w.pageName= s_w.prop1 + ' - UIEvents - ' + eventName;
s_w.prop7=eventName; //ui event name
s_w.eVar8=eventName; //ui action
s_w.events='';
if(eventCode){s_w_addEvent(eventCode);}
s_w_addEvent('event8');
s_w_addEvent('event1');
s_w.t(); //increments page views
} catch(s_w){ return; }
}
}
utils.logMicroEvent = function( eventName, eventCode ){
if(typeof(s_gi)!='undefined'){
try{
s_w=s_gi(s_account);
if(eventName.indexOf('error')!=-1){s_w.pageType='errorPage';}
s_w.pageName= s_w.prop1 + ' - UIEvents - ' + eventName;
s_w.prop7=eventName; //ui event name
s_w.eVar8=eventName; //ui action
s_w.events='';
if(eventCode){s_w_addEvent(eventCode);}
s_w_addEvent('event8');
s_w.tl(); //doesn't increment page views
} catch(s_w){ return; }
}
}
/**
* Generic
*/
function $() {
var results = [], element;
for (var i = 0; i < arguments.length; i++) {
element = arguments[i];
if (typeof element == 'string' && element!='')
element = document.getElementById(element);
results.push( ( (typeof(Element)!='undefined') && Element && Element.extend) ? Element.extend(element) : element );
}
return results.length < 2 ? results[0] : results;
}
function isFunction(a) {
return typeof a == 'function';
}
// Breaks javascript event to dom references in IE - preventing memory leaks
// Use whenever removing an item from the dom or setting innerHTML
function purge(d) {
var a = d.attributes, i, l, n;
if (a) {
l = a.length;
for (i = 0; i < l; i += 1) {
n = a[i].name;
if (typeof d[n] === 'function') {
d[n] = null;
}
}
}
a = d.childNodes;
if (a) {
l = a.length;
for (i = 0; i < l; i += 1) {
purge(d.childNodes[i]);
}
}
}
/**
* Dates
*/
//Load the dates returned from the XML server into a JS Date object, using ISO8601 date formatting standard.
var DEFAULT_TIME_ZONE = -4;
var DEFAULT_TIME_STRING = 'EDT';
Date.prototype.setISO8601 = function(string) {
var expression = new RegExp( "(\\d{4})-(\\d{1,2})-(\\d{1,2})T(\\d{1,2}):(\\d{1,2}):(\\d{1,2})(-|\\+)(\\d{1,2}):(\\d{1,2})" );
var standard = string.replace( expression, "$2/$3/$1 $4:$5:$6 GMT$7$8$9" );
var date = new Date( standard );
this.setTime( date.getTime() );
};
//Return the millisecond format of the date as of midnight this morning.
Date.prototype.getMidnightTime = function() {
return this.getTime() - (this.getHours() * 3600000) - (this.getMinutes() * 60000) - (this.getSeconds() * 1000) - this.getMilliseconds();
};
Date.prototype.getWikiTime = function(noTimeZone) {
var adjustForTimezoneOffset = function(date) { return new Date( date.getTime() + ( 1000 * 60 * ( date.getTimezoneOffset() - ( DEFAULT_TIME_ZONE * -60 ) ) ) ); };
var z = function(x) { return (0<=x&&x<=9?'0':'')+x; };
var adjusted = adjustForTimezoneOffset(this);
var now = adjustForTimezoneOffset(new Date());
var arrDaysOfWeek = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ];
var arrMonths = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ];
var formattedDate = arrMonths[adjusted.getMonth()] + " " + adjusted.getDate() + " " + adjusted.getFullYear();
if( adjusted.getTime() > now.getMidnightTime() ) formattedDate = "Today";
else if( adjusted.getTime() > now.getMidnightTime() - 86000000 ) formattedDate = "Yesterday";
else if( adjusted.getTime() > now.getMidnightTime() - ( 86000000 * 7 ) ) formattedDate = arrDaysOfWeek[adjusted.getDay()];
formattedDate += ", ";
formattedDate += adjusted.getHours() <= 12 ? adjusted.getHours() == 0 ? 12 : adjusted.getHours() : adjusted.getHours() - 12;
formattedDate += ":" + z( adjusted.getMinutes() ) + ' ' + ( adjusted.getHours() < 12 ? "am" : "pm" );
return formattedDate + ( !noTimeZone ? " " + DEFAULT_TIME_STRING : "" );
};
Date.prototype.getStaticTime = function(noTimeZone) {
var arrMonths = new Array("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec");
var formattedDate = arrMonths[this.getMonth()] + " " + this.getDate() + " " + this.getFullYear();
formattedDate += ", ";
formattedDate += (this.getHours() <= 12) ? (this.getHours() == 0) ? '12' : this.getHours() : (this.getHours() - 12);
formattedDate += ":";
formattedDate += (this.getMinutes() < 10) ? "0" + this.getMinutes() : this.getMinutes();
formattedDate += (this.getHours() < 12) ? " am" : " pm";
var timeZone = (noTimeZone) ? '' : DEFAULT_TIME_STRING;
return formattedDate + " " + timeZone;
};
/**
* Strings
*/
String.prototype.newlinesToHTML = function() {
// remove \rs that IE SO helpfully adds
var cleanedText = this.replace(/\r/gi, "");
return cleanedText.replace(/\n/gi, " ");
}
String.prototype.newlinesToUnicode = function() {
return this.replace(/ /gi, "\n");
}
String.prototype.capitalize = function() {
var charRE = /^[a-z]/;
if (!charRE.test(this)) return this;
// older versions of safari do not support passing a function to String.replace
try {
return this.replace(charRE, function(c) { return c.toUpperCase(); });
} catch (e) {
var capChar = charRE.exec(this)[0].toUpperCase();
return this.replace(charRE, capChar);
}
}
String.prototype.trim = function(in_str) {
in_str = this != window ? this : in_str;
return in_str.replace(/^\s+/g, '').replace(/\s+$/g, '');
};
String.prototype.encodeCDATA = function() {
return this.replace(/]]>/g, "]]>");
};
String.prototype.encodeHTML = function() {
return this.replace(/&/g, "&").replace(//g, ">").replace(/"/g,""").replace(/'/g,"'");
};
String.prototype.decodeHTML = function() {
return this.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g,'"').replace(/"/g,'"').replace(/'/g,"'").replace(/'/g,"'");
};
String.prototype.getObjectFromQuerystring = function() {
var map = {};
var str = this.replace(/^\?/, "");
var pairs = str.split("&");
for (var i=0; i 1) ? decodeURIComponent(utils.regexpReplace(keyValue[1],"\\+"," ","gi")) : null;
value = (value == "true") ? true : ((value == "false") ? false : value);
if (map[keyValue[0]] && (map[keyValue[0]] instanceof Array)) map[keyValue[0]].push(value);
else map[keyValue[0]] = value;
}
return map;
};
utils.getQueryStringFromObject = function( obj, prefix ) {
var queryString = "";
for( var key in obj ) {
var value = obj[key];
if( prefix ) key = key;
switch( typeof(value) ) {
case "undefined":
case "function":
break;
case "string":
case "number":
case "boolean":
queryString += encodeURIComponent( ( prefix ? prefix + '.' : '' ) + key ) + "=" + encodeURIComponent(value) + "&";
break;
case "object":
if( value instanceof Array ) {
for( var i = 0; i < value.length; i++ ) {
var parseObject = {}; parseObject[key] = value[i];
var parsed = utils.getQueryStringFromObject( parseObject, prefix );
if( parsed ) queryString += parsed + '&';
}
} else {
var parsed = utils.getQueryStringFromObject( value, ( prefix ? prefix + "." : "" ) + key );
if( parsed ) queryString += parsed + '&';
}
break;
}
}
return queryString.replace( new RegExp("&$",'g'), "" );
};
/**
* Numbers
* required by addWidget and addImage
*/
Number.prototype.format = function(decpoint, sep) {
// check for missing parameters and use defaults if so
if (arguments.length == 1) {
sep = ",";
}
if (arguments.length == 0) {
sep = ",";
decpoint = ".";
}
// need a string for operations
var num = this.toString();
// separate the whole number and the fraction if possible
a = num.split(decpoint);
x = a[0]; // decimal
y = a[1]; // fraction
z = "";
if (typeof(x) != "undefined") {
// reverse the digits. regexp works from left to right.
for (i=x.length-1;i>=0;i--)
z += x.charAt(i);
// add seperators. but undo the trailing one, if there
z = z.replace(/(\d{3})/g, "$1" + sep);
if (z.slice(-sep.length) == sep)
z = z.slice(0, -sep.length);
x = "";
// reverse again to get back the number
for (i=z.length-1;i>=0;i--)
x += z.charAt(i);
// add the fraction back in, if it was there
if (typeof(y) != "undefined" && y.length > 0)
x += decpoint + y;
}
return x;
}
/**
* public class ClassLoader
*
* Handles asynchronous requests for JavaScript classes.
*
* @depends Request
* @depends BUILD_DATE
*/
window.ClassLoader = {
dependencies: {
"CYOAutoLookup" : [ "AutoLookup" ],
"TagAutoLookup" : [ "AutoLookup" ],
"Editor": [ "Area", "Toolbar" ],
"Toolbar": [ "ToolbarInput" ]
},
/**
* public static void load()
*
* Asynchronously loads the specified JavaScript class. After the class has been
* successfully loaded, the specified callback method, if any, is run.
*
* @param String classId The name of the class to be loaded.
* @param Function callback (optional) The method to run after the class has loaded.
* @param Boolean loaded (internal) Marks the class as loaded and runs the callback.
*
* @depends Request to asynchronously request the class.
* @depends BUILD_DATE to build the URL from which to load the class.
*/
load: function( classId, callback, loaded ) {
var loadable = true;
// First, check to see if the class is already loaded...
if( loaded ) { if( typeof(callback) === "function" ) callback(); }
else {
// Load dependencies...
var dependencies = this.dependencies[classId];
for( var i = 0; dependencies && i < dependencies.length; i++ )
loadable = this.load( dependencies[i], ClassLoader.generateDependencyCallback( dependencies[i], classId, callback ) ) && loadable;
// If all dependencies are loaded, then load the class...
if( loadable ) {
var request = this.getRequest( classId );
if( request ) {
if( request.validateResponse() ) setTimeout( function() { ClassLoader.load( classId, callback, true ); }, 0 );
else {
loadable = false;
// TODO: Attach this callback to the existing loader. We already have an open request for this class, so let's not interrupt it.
}
} else {
loadable = false;
request = this.getRequest( classId, true );
request.setListener( function() { if( request.validateResponse() ) { try {
eval( request.getObjectFromXML()["script"]["text"] );
setTimeout( function() { ClassLoader.load( classId, callback, true ); }, 0 );
} catch (ex) {} } } );
request.send( "/classloader/" + classId + "/" + BUILD_DATE );
}
}
}
return loadable;
},
/**
* private static Request getRequest()
*
* This method allows the ClassLoader to interact with requests it has made.
*
* @param String classId The name of the class corresponding to this request.
* @param boolean force If true, creates a new request if one does not already exist.
*
* @return Request corresponding to the provided classId.
*/
getRequest: function( classId, force ) {
var requestId = "class:" + classId;
var request = application.requests[requestId];
if( force && !request ) request = application.initRequest(requestId);
return request;
},
/**
* public static void cancel()
*
* This method will cancel any open requests the ClassLoader has made for the given classId,
* including any dependencies. Classes which have already been loaded are not affected.
*
* @param String classId The name of the class for which requests should be cancelled.
*/
cancel: function( classId ) {
var dependencies = this.dependencies[classId];
for( var i = 0; dependencies && i < dependencies.length; i++ ) this.cancel(dependencies[i]);
var request = this.getRequest(classId);
if( request ) request.invalidate();
},
/**
* private static Function generateDependencyCallback()
*
* This method generates a callback method for the loading of a class dependency.
* The generated method will remove the dependency from its parent's dependency chain,
* and if the parent has no further dependencies, will attempt to load the parent.
*
* @param String dependency The name of the class dependency.
* @param String parentClassId The name of the class which depends on dependency. This is
* the parent class in the dependency chain -- not in the object hierarchy.
* @param Function callback The callback to execute after all dependencies have loaded.
*
* @return A function which will enforce loading of parent classes in the dependency chain.
*/
generateDependencyCallback: function( dependency, parentClassId, callback ) {
return function() {
var dependencies = ClassLoader.dependencies[parentClassId];
for( var i = 0; i < dependencies.length; i++ ) {
if( dependencies[i] == dependency ) {
dependencies.splice(i,1);
ClassLoader.dependencies[parentClassId] = dependencies;
break;
}
}
if( dependencies.length == 0 ) ClassLoader.load( parentClassId, callback );
};
}
};
/**
* Construct a new Tooltip object.
* @class for teh shits
* @constructor
*/
var tooltip = null;
function Tooltip(referenceElement, xhtml, xOffset, yOffset, pitch, className) {
if (!arguments.length) return;
this.referenceElement = referenceElement;
this.referencePosition = utils.getAbsolutePosition(referenceElement);
this.pitch = (typeof(pitch) != 'undefined' && pitch.toLowerCase() == 'left') ? 'Left' : 'Right';
this.tooltipDiv = document.createElement("div");
this.tooltipDiv.id = "tooltipDiv";
this.tooltipDiv.className = (typeof(className) != 'undefined') ? className : '';
Element.extend(this.tooltipDiv);
this.ttTopDiv = document.createElement("div");
this.ttTopDiv.id = "ttTopDiv";
this.ttTopDiv.className = "ttTop" + this.pitch;
this.ttMidDiv = document.createElement("div");
this.ttMidDiv.id = "ttMidDiv";
this.ttBotDiv = document.createElement("div");
this.ttBotDiv.id = "ttBotDiv";
this.ttCloseDiv = document.createElement("div");
this.ttCloseDiv.id = "ttCloseDiv";
this.ttCloseDiv.className = "ttClose" + this.pitch;
this.ttContentDiv = document.createElement("div");
this.ttContentDiv.id = "ttContentDiv";
this.ttTopDiv.appendChild(this.ttCloseDiv);
this.tooltipDiv.appendChild(this.ttTopDiv);
this.ttMidDiv.appendChild(this.ttContentDiv);
this.tooltipDiv.appendChild(this.ttMidDiv);
this.tooltipDiv.appendChild(this.ttBotDiv);
this.tooltipDiv.style.visibility = 'hidden';
document.body.appendChild(this.tooltipDiv);
this.tooltipDiv.style.top = this.referencePosition.absTop + 'px';
this.tooltipDiv.style.left = this.referencePosition.absLeft + 'px';
this.ttContentDiv.innerHTML = xhtml;
//position the tooltip.
this.xOffset = (typeof(xOffset) != 'undefined') ? parseInt(xOffset) : 0;
this.yOffset = (typeof(yOffset) != 'undefined') ? parseInt(yOffset) : 0;
if (this.pitch == 'Left') this.xOffset = this.xOffset - parseInt(this.tooltipDiv.scrollWidth);
this.tooltipDiv.style.marginLeft = this.xOffset + 'px';
this.tooltipDiv.style.marginTop = this.yOffset + 'px';
//close existing tooltip
if (tooltip){
tooltip.close(true)
};
tooltip = this;
//prep the close event handler.
utils.addEvent( this.ttCloseDiv, "click", function (e) { if (window.tooltip) tooltip.close(); } );
this.open();
}
Tooltip.prototype.setContent = function(xhtml) {
this.xhtml = xhtml;
this.ttContentDiv.innerHTML = this.xhtml;
};
Tooltip.prototype.getContent = function() {
return this.xhtml;
};
Tooltip.prototype.close = function(opening) {
//fade it out
var tooltipToClose = tooltip;
if(!opening) tooltip = null;
new Effect.Fade(this.tooltipDiv, {duration:.3,
afterFinish : function(){
document.body.removeChild(tooltipToClose.tooltipDiv);
}
});
return false;
};
Tooltip.prototype.open = function() {
//fade it in
this.tooltipDiv.style.display='none';
this.tooltipDiv.style.visibility='visible';
new Effect.Appear(this.tooltipDiv, {duration:.3,
afterFinish : function(){
}
});
return false;
};/**
* Construct a new Request object.
* @class Simple XMLHTTPRequest management class.
* @constructor
*/
function Request(requestReference) {
if (window.XMLHttpRequest) {
this.req = new XMLHttpRequest();
} else if (window.ActiveXObject) {
this.req = new ActiveXObject("Microsoft.XMLHTTP");
}
this.reference = requestReference;
this.url = null;
this.method = null;
this.xml = null;
this.objFromXml = null;
this.timeout = null;
this.timeoutDelay = 0; //set this to allow a stream of requests to not conflict.
this.isStatusComplete = false;
this.isInvalidated = false;
this.onResponseError = null; //function handler for all errors
this.contentType = "text/xml";
}
/**
* Assigns the onReadyStateChange handler to a function.
* @param {function} fn Event handler function that listens for the response of this request object.
*/
Request.prototype.setListener = function(fn) {
this.listener = fn;
}
/**
* Assigns a custom handler function to be called on response error.
* @param {function} fn Handler function that deals with a response.
*/
Request.prototype.setErrorHandler = function(fn) {
this.onResponseError = fn;
}
/** Invalidate this request. Provides a hook for listeners to tell whether or not to execute. */
Request.prototype.invalidate = function() {
this.isInvalidated = true;
}
/**
* Clears any pending requests and attempts to send a new request.
* @param {String} url URL to which the request is to be sent. Note that the domain MUST be same-origin as this JS file.
* @param {String} method GET, POST, PUT, DELETE, or HEAD.
* @param {String} xml Body of the request, in standard XML format. Used with POST and PUT methods only.
*/
Request.prototype.send = function(url, method, xml) {
if (this.req) {
this.url = url;
if (this.url.indexOf('.txt') == this.url.length - 4) this.url += '/'
this.method = method || "GET";
this.xml = xml;
this.timeoutSend = setTimeout('application.requests["' + this.reference + '"].asynchSend()',this.timeoutDelay);
}
}
/**
* Opens a connection to the specified URL and sends the request. This is called asynchronously from this.send().
*/
Request.prototype.asynchSend = function() {
if (utils.isSafari) {
//overwrite the PUT or DELETE methods, to keep Safari from punting on them completely.
if (this.method == 'PUT') {
this.method = 'POST';
this.url = this.url + '?method=PUT';
}
if (this.method == 'DELETE') {
this.method = 'POST';
this.url = this.url + '?method=DELETE';
}
}
this.objFromXml = null;
this.req.open(this.method, this.url, true);
try { this.req.setRequestHeader( 'Content-Type', this.contentType );
} catch(e) { try { this.req.setContentType( this.contentType );
} catch(e) { try { this.req.contentType = this.contentType;
} catch(e) {} } }
var request = this;
this.req.onreadystatechange = function(e) {
//if( this.readyState == 4 ) utils.log( "<-", request.method, request.url, this.status, request.contentType, this.responseText );
if( request.listener ) request.listener.call( this, e );
};
//utils.log( "->", this.method, this.url, this.contentType, this.xml );
this.req.send(this.xml);
}
/**
* Transforms a string for URL submission. Escapes the string. This used to do more (underscore, space thing).
* @param {String} element_name Unescaped string.
* @return Escaped string.
* @type String
*/
Request.prototype.wikiEscape = function(element_name) {
return encodeURIComponent(element_name);
}
/**
* Transforms a string escaped for URL submission. Unescapes the string. This used to replace underscores with spaces.
* @param {String} element_name Unescaped string.
* @return Escaped string.
* @type String
*/
Request.prototype.wikiUnescape = function(element_name) {
return decodeURIComponent(element_name);
}
/**
* @param {request} req Request object to examine the response of.
* @return The documentElement of the XML in the response.
* @type element
*/
Request.prototype.validateResponse = function(req, errorHandler) {
if (typeof(req) == "undefined") req = this.req;
if ( !this.isStatusComplete && !this.timeout ) {
this.timeout = setTimeout("application.requests['" + this.reference + "'].showNoResponse();", 60000);
return false;
}
if (this.isInvalidated) return false;
if (req.readyState == 4) {
clearTimeout(this.timeout);
this.timeout = null;
var returnStatus = 0;
var returnText = "";
try {
returnStatus = req.status;
returnText = req.statusText;
} catch (e) {
returnStatus = 0;
returnText = "";
}
if (returnStatus == 200) {
if (this.method == 'HEAD') return true;
element = req.responseXML.documentElement;
if (!element) return this.handleError(returnStatus, errorCode, 'We are sorry, a processing occurred. If this problem persists, please reload the page and try again.');
if (element.nodeName.toLowerCase() != "error") {
this.isStatusComplete = true;
return true;
} else {
//TODO improve error mapping
var errorCode = parseInt(element.getAttribute("status"));
switch (errorCode) {
case 1: //UserCreateException
case 6: //NoSuchPageException
case 9: //PageOutOfDateException
case 10: //UserNotFoundException
case 17: //NoSuchFavoriteException
case 18: //NoSuchAccountException
case 23: //duplicate tag
case 26: //general search error
case 27: //search server is down
case 29: //FieldValidationException - bad input
case 32: //content page has been deleted
case 40: //FavoriteAlreadyExistsException
case 42: //Template doesn't exist
case 1001: //RSS feed invalid
case 34561: //Friendship already exists
//return to listener for error handling.
return true;
break;
case 401: //unauthorized
return this.handleError(returnStatus, errorCode, 'It appears you are no longer signed-in or are unauthorized to use this feature.');
break;
default:
return this.handleError(returnStatus, errorCode, 'We are sorry, an error occurred. If this problem persists, please reload the page and try again.');
break;
}
utils.logMicroEvent('Response 200 exception - status='+element.getAttribute("status")+',statusText=' + returnText);
return false;
}
} else if (returnStatus == 405){
//readonly
return this.handleError(returnStatus, null, 'We are sorry, this feature has been temporarily disabled. Please reload the page and try again.');
} else if (returnStatus == 0) {
//request aborted by script
} else {
utils.logMicroEvent('Response ' + returnStatus + ' exception - statusText=' + returnText);
return this.handleError(returnStatus, null, "We are sorry, a server error occurred. \nIf this problem persists, please reload the page and try again.");
}
}
return false;
}
Request.prototype.handleError = function(returnStatus, errorCode, errorText) {
if (this.onResponseError) {
this.onResponseError(returnStatus, errorCode, errorText)
} else {
if (errorText) alert(errorText);
}
return false;
}
Request.prototype.showNoResponse = function() {
if (this.req.readyState != 4) {
this.handleError(null, null, "We are sorry, this web site is not responding. If this problem persists, please reload the page and try again.");
}
}
/**
* Unmarshalls an XML element (and its children) into JS objects. If the XML element has same-named children,
* they are placed into an Array().
* @param {element} xmlElement XML element to be unmarshalled.
* @return Unmarshalled object containing data from the XML element.
* @type Object
*/
Request.prototype.getObjectFromXML = function(xmlElement) {
if (!this.objFromXml) this.objFromXml = this.parseXmlToObject(xmlElement);
return this.objFromXml;
}
Request.prototype.parseXmlToObject = function(xmlElement) {
if (typeof(xmlElement) == "undefined") xmlElement = this.req.responseXML.documentElement;
if (!xmlElement) return null;
var obj = new Object();
//nodeTest = '<' + xmlElement.nodeName;
//for (var j=0;j (' + xmlElement.childNodes.length + ' children)');
if (xmlElement.attributes){
for (var j=0;j= 0) {
return (childNode.nodeValue) ? childNode.nodeValue : childNode.text;
} else {
var childObj = this.parseXmlToObject(childNode);
if (typeof obj[childNodeName] == "undefined") {
try{
obj[childNodeName] = childObj;
if (typeof obj[childNodeName] == "undefined") { //FF empty CDATA returns undefined.
obj[childNodeName] = '';
} else {
obj[childNodeName].length = 1;
obj[childNodeName][0] = obj[childNodeName];
}
} catch( e ){
alert( e );
}
} else {
if (obj[childNodeName].length == 1) {
tmp = obj[childNodeName];
//obj[childNodeName].length = null;
obj[childNodeName] = new Array();
obj[childNodeName][obj[childNodeName].length] = tmp;
}
obj[childNodeName][obj[childNodeName].length] = childObj;
}
}
}
}
return obj;
}
//Constants & Globals
var logoImageLoaded = false;
//DOM Element Event Handler Assignments
//Each event handler that the CYO deals with may be assigned to an element, if it exists.
function initEvents() {
if ($("logo_text")) {
utils.addEvent($("logo_text"),"keydown",function(e) { setTimeout("customLogo.updateHeaderText()",0); });
utils.addEvent($("logo_text"),"change",function(e) { setTimeout("customLogo.updateHeaderText()",0); });
utils.addEvent($("logo_text"),"mouseup",function(e) { setTimeout("customLogo.updateHeaderText()",0); });
utils.addEvent($("logoOption_text_removeImage"),"click",function(e) { customLogo.removeImage(); });
utils.addEvent($("logoOption_text_removeImage2"),"click",function(e) { customLogo.removeImage(); });
utils.addEvent($("logoOption_image_openForm"),"click",function(e) { customLogo.setImageForm('open'); });
utils.addEvent($("logoOption_image_reopenForm"),"click",function(e) { customLogo.setImageForm('open'); });
}
if ($("wikiUrl")) {
var lookup;
// Load the lookup classes
initAutoComplete = function() {
if( !( window.AutoLookupConfig && window.CYOAutoLookup ) ) return;
var url = "/wikisearch?maxResults=MAXRESULTS&offset=OFFSET&name=";
var lookupConfig = new AutoLookupConfig($("nameSuggestMsg").innerHTML);
lookupConfig.setDataCollectionName("wiki");
lookupConfig.setDataValueNames(["name", "wikiDomain"]);
lookupConfig.removeUpKeys(lookupConfig.upKeys);
lookupConfig.removeDownKeys(lookupConfig.downKeys);
lookupConfig.setSelectListener(null);
lookup = new CYOAutoLookup(lookupConfig, $("wikiUrl"), "getWikiNames", url);
if ($("wikiUrl").value) lookup.keyUp(null);
}
ClassLoader.load("CYOAutoLookup", initAutoComplete);
ClassLoader.load("AutoLookupConfig", initAutoComplete);
}
//cyo handlers.
if($("containerCyo")){
utils.addEvent($("cyo_description_trigger"),"click",function(e) {
tooltip = new Tooltip($("cyo_description_trigger"), $("cyo_description_trigger").getElementsByTagName("span")[0].innerHTML, -200, 20, 'right', 'largeWrapperToolTip' );
return false;
});
utils.addEvent($("cyo_contributors_trigger"),"click",function(e) {
tooltip = new Tooltip($("cyo_contributors_trigger"), $("cyo_contributors_trigger").getElementsByTagName("span")[0].innerHTML, 0, 20, 'left' );
return false;
});
utils.addEvent($("cyo_tags_trigger"),"click",function(e) {
tooltip = new Tooltip($("cyo_tags_trigger"), $("cyo_tags_trigger").getElementsByTagName("span")[0].innerHTML, 0, 20 );
return false;
});
utils.addEvent($("cyo_anon_trigger"),"click",function(e) {
tooltip = new Tooltip($("cyo_anon_trigger"), $("cyo_anon_trigger").getElementsByTagName("span")[0].innerHTML, 0, 20 );
return false;
});
utils.addEvent($("cyo_reg_trigger"),"click",function(e) {
tooltip = new Tooltip($("cyo_reg_trigger"), $("cyo_reg_trigger").getElementsByTagName("span")[0].innerHTML, 0, 20 );
return false;
});
utils.addEvent($("cyo_publicinvite_trigger"),"click",function(e) {
if (utils.isMSIE) {
var xOffset = document.getElementById('cyo_publicinvite_trigger').offsetWidth;
}else{
var xOffset = document.getElementById('cyo_publicinvite_trigger').firstChild.offsetWidth;
}
tooltip = new Tooltip($("cyo_publicinvite_trigger"), $("cyo_publicinvite_trigger").getElementsByTagName("span")[0].innerHTML, xOffset, 20, 'left' );
return false;
});
utils.addEvent($("cyo_privateinvite_trigger"),"click",function(e) {
if (utils.isMSIE) {
var xOffset = document.getElementById('cyo_privateinvite_trigger').offsetWidth;
}else{
var xOffset = document.getElementById('cyo_privateinvite_trigger').firstChild.offsetWidth;
}
tooltip = new Tooltip($("cyo_privateinvite_trigger"), $("cyo_privateinvite_trigger").getElementsByTagName("span")[0].innerHTML, xOffset, 20, 'left' );
return false;
});
utils.addEvent($("role_trigger"),"click",function(e) {
if (tooltip) {
tooltip.close();
return null;
} else {
if (utils.isMSIE) {
var xOffset = document.getElementById('role_trigger').offsetWidth;
}else{
var xOffset = document.getElementById('role_trigger').firstChild.offsetWidth;
}
tooltip = new Tooltip($("role_trigger"), $("role_trigger").getElementsByTagName("span")[0].innerHTML, xOffset, 20 );
return false;
}
});
}
}
init('setTimeout("initEvents();",0)');
/*checkWikiName = new function(){
this.nameList=[];
this.referenceName = 'checkWikiName';
this.charThreshold = 3;
this.maxListLength = 10;
this.firstThree = '';
this.createVisibleList = function(){
this.introText=''+$('nameSuggestMsg').innerHTML+' ';
if (!this.nameListHolder){
this.nameListHolder=document.createElement('SPAN');
this.nameListHolder.className='suggestList';
this.formInputElement.parentNode.insertBefore(this.nameListHolder, this.formInputElement.nextSibling);
}
this.nameListHolder.innerHTML = '';
var count = 0;
for(var i=0; i' + this.nameList[i].name + ' ';
count++;
}
}
if(this.nameListHolder.innerHTML==''){
this.destroyVisibleList();
} else {
this.nameListHolder.innerHTML = this.introText + this.nameListHolder.innerHTML;
utils.addEvent($(this.referenceName), 'click',
function(e) {checkWikiName.destroyVisibleList()}
);
}
}
this.destroyVisibleList = function(){
if(this.nameListHolder){
this.formInputElement.parentNode.removeChild(this.nameListHolder)
this.nameListHolder=null;
}
}
this.checkName = function(formInputElement){
this.formInputElement = formInputElement;
//regExp removes whitespace (does trim)
this.wikiName = formInputElement.value.trim();
//not enought letters do nothing
if (this.wikiName.length < this.charThreshold) {
this.destroyVisibleList();
return false;
}
this.uri = '/wikisearch?name='+this.wikiName;
//ajax call if enough letters, or first three have changed
if ( this.wikiName.length >= this.charThreshold
&& this.wikiName.substring(0,3)!=this.firstThree
){
var requestObj = application.initRequest(this.referenceName);
requestObj.setListener(
function(e) {
if (requestObj.validateResponse()) {
checkWikiName.nameList=[];
utils.stopThrobber(formInputElement);
var xmlResults = requestObj.getObjectFromXML();
if (parseInt(xmlResults['results']) > 0){
for(var i=0; i0) {
this.createVisibleList();
}
return false;
}
} */
application = new function(){
this.requests = new Object;
this.initRequest = function(requestReference) {
if (this.requests[requestReference]) {
if (this.requests[requestReference].req.readyState != 0) this.requests[requestReference].req.abort();
if (this.requests[requestReference].timeoutSend) clearTimeout(this.requests[requestReference].timeoutSend);
} else {
this.requests[requestReference] = new Request(requestReference);
}
return this.requests[requestReference];
};
this.attachedEvents = new Array();
this.detachEvents = function( ) {
for (var i=application.attachedEvents.length-1; i>=0; i--) {
if (application.attachedEvents[i]["elem"].removeEventListener) {
application.attachedEvents[i]["elem"].removeEventListener(application.attachedEvents[i]["evtName"], application.attachedEvents[i]["handler"], false);
} else if(application.attachedEvents[i]["elem"].detachEvent){
application.attachedEvents[i]["elem"].detachEvent("on" + application.attachedEvents[i]["evtName"],application.attachedEvents[i]["handler"]);
}
application.attachedEvents.length = i;
}
}
init('setTimeout("utils.addEvent(window, \'unload\', application.detachEvents)" , 0)');
}
var skinSlider = {
slider : {},
paginator : {},
leftControl : {},
rightControl : {},
skins : [],
thumbSizeX : 210,
thumbSizeY : 204,
groupSize : 8,
getSlideIncrement : function(){ return this.thumbSizeX*this.groupSize/2 },
pages : [],
pageTabs : [],
currentPage : 0,
currentPreviewImg : null,
currentSelection : null,
zoomImages : [],
initialSkin : '',
init : function() {
this.formInput = $('skin');
this.slider = $('slider');
this.paginator = $('paginator');
this.leftControl = $('moveLeft');
this.rightControl = $('moveRight');
this.previewScreen = $('previewScreen');
this.skins = $( 'skinData' ).getElementsByTagName('li');
var topRow='';
var bottomRow='';
var flipRow=false;
var paginatorhtml='';
var zoomhtml = '';
var skinName = '';
var thumb = '';
var radio= '';
var bigZoom = '';
var zoomLink = '';
Event.observe(this.leftControl, 'click', function(){ return skinSlider.slideSlider(-1) } );
Event.observe(this.rightControl, 'click', function(){ return skinSlider.slideSlider(1) } );
//set the initial skin
if (this.formInput.value==''){
this.initialSkin = this.skins[0].id.replace('data_','');
this.formInput.value = this.initialSkin;
} else {
this.initialSkin = this.formInput.value;
}
init('skinSlider.setSelection($("skin_a_"+skinSlider.initialSkin))');
for (var i=0; i ';
zoomLink = ''+
'zoom'
radio = ''+
''+
' '
cell = '