
var cxlEnv = new Object();
cxlEnv.sitePath = "http://www.arubarealestate.com/";
cxlEnv.server = "www.arubarealestate.com/";
cxlEnv.domain = cxlEnv.server.replace(/^[0-9a-zA-Z]+\./,"");
cxlEnv.domain = cxlEnv.domain.replace("/",'');
cxlEnv.subdomain = "";
cxlEnv.context = "WEB-INF/";
cxlEnv.protocol = "";
cxlEnv.bodyClass= "about-aruba";
cxlEnv.imageBase = "/images/";
cxlEnv.styleBase = "/styles/";
cxlEnv.scriptBase = "/scripts/";
cxlEnv.categories= "";
cxlEnv.mapsAPIkey = "error";
/*
Script: Core.js
MooTools - My Object Oriented JavaScript Tools.
License:
MIT-style license.
Copyright:
Copyright (c) 2006-2008 [Valerio Proietti](http://mad4milk.net/).
Code & Documentation:
[The MooTools production team](http://mootools.net/developers/).
Inspiration:
- Class implementation inspired by [Base.js](http://dean.edwards.name/weblog/2006/03/base/) Copyright (c) 2006 Dean Edwards, [GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)
- Some functionality inspired by [Prototype.js](http://prototypejs.org) Copyright (c) 2005-2007 Sam Stephenson, [MIT License](http://opensource.org/licenses/mit-license.php)
*/
var MooTools = {
'version': '1.2.3',
'build': '4980aa0fb74d2f6eb80bcd9f5b8e1fd6fbb8f607'
};
var Native = function(options){
options = options || {};
var name = options.name;
var legacy = options.legacy;
var protect = options.protect;
var methods = options.implement;
var generics = options.generics;
var initialize = options.initialize;
var afterImplement = options.afterImplement || function(){};
var object = initialize || legacy;
generics = generics !== false;
object.constructor = Native;
object.$family = {name: 'native'};
if (legacy && initialize) object.prototype = legacy.prototype;
object.prototype.constructor = object;
if (name){
var family = name.toLowerCase();
object.prototype.$family = {name: family};
Native.typize(object, family);
}
var add = function(obj, name, method, force){
if (!protect || force || !obj.prototype[name]) obj.prototype[name] = method;
if (generics) Native.genericize(obj, name, protect);
afterImplement.call(obj, name, method);
return obj;
};
object.alias = function(a1, a2, a3){
if (typeof a1 == 'string'){
var pa1 = this.prototype[a1];
if ((a1 = pa1)) return add(this, a2, a1, a3);
}
for (var a in a1) this.alias(a, a1[a], a2);
return this;
};
object.implement = function(a1, a2, a3){
if (typeof a1 == 'string') return add(this, a1, a2, a3);
for (var p in a1) add(this, p, a1[p], a2);
return this;
};
if (methods) object.implement(methods);
return object;
};
Native.genericize = function(object, property, check){
if ((!check || !object[property]) && typeof object.prototype[property] == 'function') object[property] = function(){
var args = Array.prototype.slice.call(arguments);
return object.prototype[property].apply(args.shift(), args);
};
};
Native.implement = function(objects, properties){
for (var i = 0, l = objects.length; i < l; i++) objects[i].implement(properties);
};
Native.typize = function(object, family){
if (!object.type) object.type = function(item){
return ($type(item) === family);
};
};
(function(){
var natives = {'Array': Array, 'Date': Date, 'Function': Function, 'Number': Number, 'RegExp': RegExp, 'String': String};
for (var n in natives) new Native({name: n, initialize: natives[n], protect: true});
var types = {'boolean': Boolean, 'native': Native, 'object': Object};
for (var t in types) Native.typize(types[t], t);
var generics = {
'Array': ["concat", "indexOf", "join", "lastIndexOf", "pop", "push", "reverse", "shift", "slice", "sort", "splice", "toString", "unshift", "valueOf"],
'String': ["charAt", "charCodeAt", "concat", "indexOf", "lastIndexOf", "match", "replace", "search", "slice", "split", "substr", "substring", "toLowerCase", "toUpperCase", "valueOf"]
};
for (var g in generics){
for (var i = generics[g].length; i--;) Native.genericize(natives[g], generics[g][i], true);
}
})();
var Hash = new Native({
name: 'Hash',
initialize: function(object){
if ($type(object) == 'hash') object = $unlink(object.getClean());
for (var key in object) this[key] = object[key];
return this;
}
});
Hash.implement({
forEach: function(fn, bind){
for (var key in this){
if (this.hasOwnProperty(key)) fn.call(bind, this[key], key, this);
}
},
getClean: function(){
var clean = {};
for (var key in this){
if (this.hasOwnProperty(key)) clean[key] = this[key];
}
return clean;
},
getLength: function(){
var length = 0;
for (var key in this){
if (this.hasOwnProperty(key)) length++;
}
return length;
}
});
Hash.alias('forEach', 'each');
Array.implement({
forEach: function(fn, bind){
for (var i = 0, l = this.length; i < l; i++) fn.call(bind, this[i], i, this);
}
});
Array.alias('forEach', 'each');
function $A(iterable){
if (iterable.item){
var l = iterable.length, array = new Array(l);
while (l--) array[l] = iterable[l];
return array;
}
return Array.prototype.slice.call(iterable);
};
function $arguments(i){
return function(){
return arguments[i];
};
};
function $chk(obj){
return !!(obj || obj === 0);
};
function $clear(timer){
clearTimeout(timer);
clearInterval(timer);
return null;
};
function $defined(obj){
return (obj != undefined);
};
function $each(iterable, fn, bind){
var type = $type(iterable);
((type == 'arguments' || type == 'collection' || type == 'array') ? Array : Hash).each(iterable, fn, bind);
};
function $empty(){};
function $extend(original, extended){
for (var key in (extended || {})) original[key] = extended[key];
return original;
};
function $H(object){
return new Hash(object);
};
function $lambda(value){
return ($type(value) == 'function') ? value : function(){
return value;
};
};
function $merge(){
var args = Array.slice(arguments);
args.unshift({});
return $mixin.apply(null, args);
};
function $mixin(mix){
for (var i = 1, l = arguments.length; i < l; i++){
var object = arguments[i];
if ($type(object) != 'object') continue;
for (var key in object){
var op = object[key], mp = mix[key];
mix[key] = (mp && $type(op) == 'object' && $type(mp) == 'object') ? $mixin(mp, op) : $unlink(op);
}
}
return mix;
};
function $pick(){
for (var i = 0, l = arguments.length; i < l; i++){
if (arguments[i] != undefined) return arguments[i];
}
return null;
};
function $random(min, max){
return Math.floor(Math.random() * (max - min + 1) + min);
};
function $splat(obj){
var type = $type(obj);
return (type) ? ((type != 'array' && type != 'arguments') ? [obj] : obj) : [];
};
var $time = Date.now || function(){
return +new Date;
};
function $try(){
for (var i = 0, l = arguments.length; i < l; i++){
try {
return arguments[i]();
} catch(e){}
}
return null;
};
function $type(obj){
if (obj == undefined) return false;
if (obj.$family) return (obj.$family.name == 'number' && !isFinite(obj)) ? false : obj.$family.name;
if (obj.nodeName){
switch (obj.nodeType){
case 1: return 'element';
case 3: return (/\S/).test(obj.nodeValue) ? 'textnode' : 'whitespace';
}
} else if (typeof obj.length == 'number'){
if (obj.callee) return 'arguments';
else if (obj.item) return 'collection';
}
return typeof obj;
};
function $unlink(object){
var unlinked;
switch ($type(object)){
case 'object':
unlinked = {};
for (var p in object) unlinked[p] = $unlink(object[p]);
break;
case 'hash':
unlinked = new Hash(object);
break;
case 'array':
unlinked = [];
for (var i = 0, l = object.length; i < l; i++) unlinked[i] = $unlink(object[i]);
break;
default: return object;
}
return unlinked;
};
/*
Script: Browser.js
The Browser Core. Contains Browser initialization, Window and Document, and the Browser Hash.
License:
MIT-style license.
*/
var Browser = $merge({
Engine: {name: 'unknown', version: 0},
Platform: {name: (window.orientation != undefined) ? 'ipod' : (navigator.platform.match(/mac|win|linux/i) || ['other'])[0].toLowerCase()},
Features: {xpath: !!(document.evaluate), air: !!(window.runtime), query: !!(document.querySelector)},
Plugins: {},
Engines: {
presto: function(){
return (!window.opera) ? false : ((arguments.callee.caller) ? 960 : ((document.getElementsByClassName) ? 950 : 925));
},
trident: function(){
return (!window.ActiveXObject) ? false : ((window.XMLHttpRequest) ? 5 : 4);
},
webkit: function(){
return (navigator.taintEnabled) ? false : ((Browser.Features.xpath) ? ((Browser.Features.query) ? 525 : 420) : 419);
},
gecko: function(){
return (document.getBoxObjectFor == undefined) ? false : ((document.getElementsByClassName) ? 19 : 18);
}
}
}, Browser || {});
Browser.Platform[Browser.Platform.name] = true;
Browser.detect = function(){
for (var engine in this.Engines){
var version = this.Engines[engine]();
if (version){
this.Engine = {name: engine, version: version};
this.Engine[engine] = this.Engine[engine + version] = true;
break;
}
}
return {name: engine, version: version};
};
Browser.detect();
Browser.Request = function(){
return $try(function(){
return new XMLHttpRequest();
}, function(){
return new ActiveXObject('MSXML2.XMLHTTP');
});
};
Browser.Features.xhr = !!(Browser.Request());
Browser.Plugins.Flash = (function(){
var version = ($try(function(){
return navigator.plugins['Shockwave Flash'].description;
}, function(){
return new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version');
}) || '0 r0').match(/\d+/g);
return {version: parseInt(version[0] || 0 + '.' + version[1], 10) || 0, build: parseInt(version[2], 10) || 0};
})();
function $exec(text){
if (!text) return text;
if (window.execScript){
window.execScript(text);
} else {
var script = document.createElement('script');
script.setAttribute('type', 'text/javascript');
script[(Browser.Engine.webkit && Browser.Engine.version < 420) ? 'innerText' : 'text'] = text;
document.head.appendChild(script);
document.head.removeChild(script);
}
return text;
};
Native.UID = 1;
var $uid = (Browser.Engine.trident) ? function(item){
return (item.uid || (item.uid = [Native.UID++]))[0];
} : function(item){
return item.uid || (item.uid = Native.UID++);
};
var Window = new Native({
name: 'Window',
legacy: (Browser.Engine.trident) ? null: window.Window,
initialize: function(win){
$uid(win);
if (!win.Element){
win.Element = $empty;
if (Browser.Engine.webkit) win.document.createElement("iframe"); //fixes safari 2
win.Element.prototype = (Browser.Engine.webkit) ? window["[[DOMElement.prototype]]"] : {};
}
win.document.window = win;
return $extend(win, Window.Prototype);
},
afterImplement: function(property, value){
window[property] = Window.Prototype[property] = value;
}
});
Window.Prototype = {$family: {name: 'window'}};
new Window(window);
var Document = new Native({
name: 'Document',
legacy: (Browser.Engine.trident) ? null: window.Document,
initialize: function(doc){
$uid(doc);
doc.head = doc.getElementsByTagName('head')[0];
doc.html = doc.getElementsByTagName('html')[0];
if (Browser.Engine.trident && Browser.Engine.version <= 4) $try(function(){
doc.execCommand("BackgroundImageCache", false, true);
});
if (Browser.Engine.trident) doc.window.attachEvent('onunload', function() {
doc.window.detachEvent('onunload', arguments.callee);
doc.head = doc.html = doc.window = null;
});
return $extend(doc, Document.Prototype);
},
afterImplement: function(property, value){
document[property] = Document.Prototype[property] = value;
}
});
Document.Prototype = {$family: {name: 'document'}};
new Document(document);
/*
Script: Array.js
Contains Array Prototypes like each, contains, and erase.
License:
MIT-style license.
*/
Array.implement({
every: function(fn, bind){
for (var i = 0, l = this.length; i < l; i++){
if (!fn.call(bind, this[i], i, this)) return false;
}
return true;
},
filter: function(fn, bind){
var results = [];
for (var i = 0, l = this.length; i < l; i++){
if (fn.call(bind, this[i], i, this)) results.push(this[i]);
}
return results;
},
clean: function() {
return this.filter($defined);
},
indexOf: function(item, from){
var len = this.length;
for (var i = (from < 0) ? Math.max(0, len + from) : from || 0; i < len; i++){
if (this[i] === item) return i;
}
return -1;
},
map: function(fn, bind){
var results = [];
for (var i = 0, l = this.length; i < l; i++) results[i] = fn.call(bind, this[i], i, this);
return results;
},
some: function(fn, bind){
for (var i = 0, l = this.length; i < l; i++){
if (fn.call(bind, this[i], i, this)) return true;
}
return false;
},
associate: function(keys){
var obj = {}, length = Math.min(this.length, keys.length);
for (var i = 0; i < length; i++) obj[keys[i]] = this[i];
return obj;
},
link: function(object){
var result = {};
for (var i = 0, l = this.length; i < l; i++){
for (var key in object){
if (object[key](this[i])){
result[key] = this[i];
delete object[key];
break;
}
}
}
return result;
},
contains: function(item, from){
return this.indexOf(item, from) != -1;
},
extend: function(array){
for (var i = 0, j = array.length; i < j; i++) this.push(array[i]);
return this;
},
getLast: function(){
return (this.length) ? this[this.length - 1] : null;
},
getRandom: function(){
return (this.length) ? this[$random(0, this.length - 1)] : null;
},
include: function(item){
if (!this.contains(item)) this.push(item);
return this;
},
combine: function(array){
for (var i = 0, l = array.length; i < l; i++) this.include(array[i]);
return this;
},
erase: function(item){
for (var i = this.length; i--; i){
if (this[i] === item) this.splice(i, 1);
}
return this;
},
empty: function(){
this.length = 0;
return this;
},
flatten: function(){
var array = [];
for (var i = 0, l = this.length; i < l; i++){
var type = $type(this[i]);
if (!type) continue;
array = array.concat((type == 'array' || type == 'collection' || type == 'arguments') ? Array.flatten(this[i]) : this[i]);
}
return array;
},
hexToRgb: function(array){
if (this.length != 3) return null;
var rgb = this.map(function(value){
if (value.length == 1) value += value;
return value.toInt(16);
});
return (array) ? rgb : 'rgb(' + rgb + ')';
},
rgbToHex: function(array){
if (this.length < 3) return null;
if (this.length == 4 && this[3] == 0 && !array) return 'transparent';
var hex = [];
for (var i = 0; i < 3; i++){
var bit = (this[i] - 0).toString(16);
hex.push((bit.length == 1) ? '0' + bit : bit);
}
return (array) ? hex : '#' + hex.join('');
}
});
/*
Script: Function.js
Contains Function Prototypes like create, bind, pass, and delay.
License:
MIT-style license.
*/
Function.implement({
extend: function(properties){
for (var property in properties) this[property] = properties[property];
return this;
},
create: function(options){
var self = this;
options = options || {};
return function(event){
var args = options.arguments;
args = (args != undefined) ? $splat(args) : Array.slice(arguments, (options.event) ? 1 : 0);
if (options.event) args = [event || window.event].extend(args);
var returns = function(){
return self.apply(options.bind || null, args);
};
if (options.delay) return setTimeout(returns, options.delay);
if (options.periodical) return setInterval(returns, options.periodical);
if (options.attempt) return $try(returns);
return returns();
};
},
run: function(args, bind){
return this.apply(bind, $splat(args));
},
pass: function(args, bind){
return this.create({bind: bind, arguments: args});
},
bind: function(bind, args){
return this.create({bind: bind, arguments: args});
},
bindWithEvent: function(bind, args){
return this.create({bind: bind, arguments: args, event: true});
},
attempt: function(args, bind){
return this.create({bind: bind, arguments: args, attempt: true})();
},
delay: function(delay, bind, args){
return this.create({bind: bind, arguments: args, delay: delay})();
},
periodical: function(periodical, bind, args){
return this.create({bind: bind, arguments: args, periodical: periodical})();
}
});
/*
Script: Number.js
Contains Number Prototypes like limit, round, times, and ceil.
License:
MIT-style license.
*/
Number.implement({
limit: function(min, max){
return Math.min(max, Math.max(min, this));
},
round: function(precision){
precision = Math.pow(10, precision || 0);
return Math.round(this * precision) / precision;
},
times: function(fn, bind){
for (var i = 0; i < this; i++) fn.call(bind, i, this);
},
toFloat: function(){
return parseFloat(this);
},
toInt: function(base){
return parseInt(this, base || 10);
}
});
Number.alias('times', 'each');
(function(math){
var methods = {};
math.each(function(name){
if (!Number[name]) methods[name] = function(){
return Math[name].apply(null, [this].concat($A(arguments)));
};
});
Number.implement(methods);
})(['abs', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'exp', 'floor', 'log', 'max', 'min', 'pow', 'sin', 'sqrt', 'tan']);
/*
Script: String.js
Contains String Prototypes like camelCase, capitalize, test, and toInt.
License:
MIT-style license.
*/
String.implement({
test: function(regex, params){
return ((typeof regex == 'string') ? new RegExp(regex, params) : regex).test(this);
},
contains: function(string, separator){
return (separator) ? (separator + this + separator).indexOf(separator + string + separator) > -1 : this.indexOf(string) > -1;
},
trim: function(){
return this.replace(/^\s+|\s+$/g, '');
},
clean: function(){
return this.replace(/\s+/g, ' ').trim();
},
camelCase: function(){
return this.replace(/-\D/g, function(match){
return match.charAt(1).toUpperCase();
});
},
hyphenate: function(){
return this.replace(/[A-Z]/g, function(match){
return ('-' + match.charAt(0).toLowerCase());
});
},
capitalize: function(){
return this.replace(/\b[a-z]/g, function(match){
return match.toUpperCase();
});
},
escapeRegExp: function(){
return this.replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1');
},
toInt: function(base){
return parseInt(this, base || 10);
},
toFloat: function(){
return parseFloat(this);
},
hexToRgb: function(array){
var hex = this.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);
return (hex) ? hex.slice(1).hexToRgb(array) : null;
},
rgbToHex: function(array){
var rgb = this.match(/\d{1,3}/g);
return (rgb) ? rgb.rgbToHex(array) : null;
},
stripScripts: function(option){
var scripts = '';
var text = this.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi, function(){
scripts += arguments[1] + '\n';
return '';
});
if (option === true) $exec(scripts);
else if ($type(option) == 'function') option(scripts, text);
return text;
},
substitute: function(object, regexp){
return this.replace(regexp || (/\\?\{([^{}]+)\}/g), function(match, name){
if (match.charAt(0) == '\\') return match.slice(1);
return (object[name] != undefined) ? object[name] : '';
});
}
});
/*
Script: Hash.js
Contains Hash Prototypes. Provides a means for overcoming the JavaScript practical impossibility of extending native Objects.
License:
MIT-style license.
*/
Hash.implement({
has: Object.prototype.hasOwnProperty,
keyOf: function(value){
for (var key in this){
if (this.hasOwnProperty(key) && this[key] === value) return key;
}
return null;
},
hasValue: function(value){
return (Hash.keyOf(this, value) !== null);
},
extend: function(properties){
Hash.each(properties || {}, function(value, key){
Hash.set(this, key, value);
}, this);
return this;
},
combine: function(properties){
Hash.each(properties || {}, function(value, key){
Hash.include(this, key, value);
}, this);
return this;
},
erase: function(key){
if (this.hasOwnProperty(key)) delete this[key];
return this;
},
get: function(key){
return (this.hasOwnProperty(key)) ? this[key] : null;
},
set: function(key, value){
if (!this[key] || this.hasOwnProperty(key)) this[key] = value;
return this;
},
empty: function(){
Hash.each(this, function(value, key){
delete this[key];
}, this);
return this;
},
include: function(key, value){
if (this[key] == undefined) this[key] = value;
return this;
},
map: function(fn, bind){
var results = new Hash;
Hash.each(this, function(value, key){
results.set(key, fn.call(bind, value, key, this));
}, this);
return results;
},
filter: function(fn, bind){
var results = new Hash;
Hash.each(this, function(value, key){
if (fn.call(bind, value, key, this)) results.set(key, value);
}, this);
return results;
},
every: function(fn, bind){
for (var key in this){
if (this.hasOwnProperty(key) && !fn.call(bind, this[key], key)) return false;
}
return true;
},
some: function(fn, bind){
for (var key in this){
if (this.hasOwnProperty(key) && fn.call(bind, this[key], key)) return true;
}
return false;
},
getKeys: function(){
var keys = [];
Hash.each(this, function(value, key){
keys.push(key);
});
return keys;
},
getValues: function(){
var values = [];
Hash.each(this, function(value){
values.push(value);
});
return values;
},
toQueryString: function(base){
var queryString = [];
Hash.each(this, function(value, key){
if (base) key = base + '[' + key + ']';
var result;
switch ($type(value)){
case 'object': result = Hash.toQueryString(value, key); break;
case 'array':
var qs = {};
value.each(function(val, i){
qs[i] = val;
});
result = Hash.toQueryString(qs, key);
break;
default: result = key + '=' + encodeURIComponent(value);
}
if (value != undefined) queryString.push(result);
});
return queryString.join('&');
}
});
Hash.alias({keyOf: 'indexOf', hasValue: 'contains'});
/*
Script: Event.js
Contains the Event Native, to make the event object completely crossbrowser.
License:
MIT-style license.
*/
var Event = new Native({
name: 'Event',
initialize: function(event, win){
win = win || window;
var doc = win.document;
event = event || win.event;
if (event.$extended) return event;
this.$extended = true;
var type = event.type;
var target = event.target || event.srcElement;
while (target && target.nodeType == 3) target = target.parentNode;
if (type.test(/key/)){
var code = event.which || event.keyCode;
var key = Event.Keys.keyOf(code);
if (type == 'keydown'){
var fKey = code - 111;
if (fKey > 0 && fKey < 13) key = 'f' + fKey;
}
key = key || String.fromCharCode(code).toLowerCase();
} else if (type.match(/(click|mouse|menu)/i)){
doc = (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body;
var page = {
x: event.pageX || event.clientX + doc.scrollLeft,
y: event.pageY || event.clientY + doc.scrollTop
};
var client = {
x: (event.pageX) ? event.pageX - win.pageXOffset : event.clientX,
y: (event.pageY) ? event.pageY - win.pageYOffset : event.clientY
};
if (type.match(/DOMMouseScroll|mousewheel/)){
var wheel = (event.wheelDelta) ? event.wheelDelta / 120 : -(event.detail || 0) / 3;
}
var rightClick = (event.which == 3) || (event.button == 2);
var related = null;
if (type.match(/over|out/)){
switch (type){
case 'mouseover': related = event.relatedTarget || event.fromElement; break;
case 'mouseout': related = event.relatedTarget || event.toElement;
}
if (!(function(){
while (related && related.nodeType == 3) related = related.parentNode;
return true;
}).create({attempt: Browser.Engine.gecko})()) related = false;
}
}
return $extend(this, {
event: event,
type: type,
page: page,
client: client,
rightClick: rightClick,
wheel: wheel,
relatedTarget: related,
target: target,
code: code,
key: key,
shift: event.shiftKey,
control: event.ctrlKey,
alt: event.altKey,
meta: event.metaKey
});
}
});
Event.Keys = new Hash({
'enter': 13,
'up': 38,
'down': 40,
'left': 37,
'right': 39,
'esc': 27,
'space': 32,
'backspace': 8,
'tab': 9,
'delete': 46
});
Event.implement({
stop: function(){
return this.stopPropagation().preventDefault();
},
stopPropagation: function(){
if (this.event.stopPropagation) this.event.stopPropagation();
else this.event.cancelBubble = true;
return this;
},
preventDefault: function(){
if (this.event.preventDefault) this.event.preventDefault();
else this.event.returnValue = false;
return this;
}
});
/*
Script: Class.js
Contains the Class Function for easily creating, extending, and implementing reusable Classes.
License:
MIT-style license.
*/
function Class(params){
if (params instanceof Function) params = {initialize: params};
var newClass = function(){
Object.reset(this);
if (newClass._prototyping) return this;
this._current = $empty;
var value = (this.initialize) ? this.initialize.apply(this, arguments) : this;
delete this._current; delete this.caller;
return value;
}.extend(this);
newClass.implement(params);
newClass.constructor = Class;
newClass.prototype.constructor = newClass;
return newClass;
};
Function.prototype.protect = function(){
this._protected = true;
return this;
};
Object.reset = function(object, key){
if (key == null){
for (var p in object) Object.reset(object, p);
return object;
}
delete object[key];
switch ($type(object[key])){
case 'object':
var F = function(){};
F.prototype = object[key];
var i = new F;
object[key] = Object.reset(i);
break;
case 'array': object[key] = $unlink(object[key]); break;
}
return object;
};
new Native({name: 'Class', initialize: Class}).extend({
instantiate: function(F){
F._prototyping = true;
var proto = new F;
delete F._prototyping;
return proto;
},
wrap: function(self, key, method){
if (method._origin) method = method._origin;
return function(){
if (method._protected && this._current == null) throw new Error('The method "' + key + '" cannot be called.');
var caller = this.caller, current = this._current;
this.caller = current; this._current = arguments.callee;
var result = method.apply(this, arguments);
this._current = current; this.caller = caller;
return result;
}.extend({_owner: self, _origin: method, _name: key});
}
});
Class.implement({
implement: function(key, value){
if ($type(key) == 'object'){
for (var p in key) this.implement(p, key[p]);
return this;
}
var mutator = Class.Mutators[key];
if (mutator){
value = mutator.call(this, value);
if (value == null) return this;
}
var proto = this.prototype;
switch ($type(value)){
case 'function':
if (value._hidden) return this;
proto[key] = Class.wrap(this, key, value);
break;
case 'object':
var previous = proto[key];
if ($type(previous) == 'object') $mixin(previous, value);
else proto[key] = $unlink(value);
break;
case 'array':
proto[key] = $unlink(value);
break;
default: proto[key] = value;
}
return this;
}
});
Class.Mutators = {
Extends: function(parent){
this.parent = parent;
this.prototype = Class.instantiate(parent);
this.implement('parent', function(){
var name = this.caller._name, previous = this.caller._owner.parent.prototype[name];
if (!previous) throw new Error('The method "' + name + '" has no parent.');
return previous.apply(this, arguments);
}.protect());
},
Implements: function(items){
$splat(items).each(function(item){
if (item instanceof Function) item = Class.instantiate(item);
this.implement(item);
}, this);
}
};
/*
Script: Class.Extras.js
Contains Utility Classes that can be implemented into your own Classes to ease the execution of many common tasks.
License:
MIT-style license.
*/
var Chain = new Class({
$chain: [],
chain: function(){
this.$chain.extend(Array.flatten(arguments));
return this;
},
callChain: function(){
return (this.$chain.length) ? this.$chain.shift().apply(this, arguments) : false;
},
clearChain: function(){
this.$chain.empty();
return this;
}
});
var Events = new Class({
$events: {},
addEvent: function(type, fn, internal){
type = Events.removeOn(type);
if (fn != $empty){
this.$events[type] = this.$events[type] || [];
this.$events[type].include(fn);
if (internal) fn.internal = true;
}
return this;
},
addEvents: function(events){
for (var type in events) this.addEvent(type, events[type]);
return this;
},
fireEvent: function(type, args, delay){
type = Events.removeOn(type);
if (!this.$events || !this.$events[type]) return this;
this.$events[type].each(function(fn){
fn.create({'bind': this, 'delay': delay, 'arguments': args})();
}, this);
return this;
},
removeEvent: function(type, fn){
type = Events.removeOn(type);
if (!this.$events[type]) return this;
if (!fn.internal) this.$events[type].erase(fn);
return this;
},
removeEvents: function(events){
var type;
if ($type(events) == 'object'){
for (type in events) this.removeEvent(type, events[type]);
return this;
}
if (events) events = Events.removeOn(events);
for (type in this.$events){
if (events && events != type) continue;
var fns = this.$events[type];
for (var i = fns.length; i--; i) this.removeEvent(type, fns[i]);
}
return this;
}
});
Events.removeOn = function(string){
return string.replace(/^on([A-Z])/, function(full, first) {
return first.toLowerCase();
});
};
var Options = new Class({
setOptions: function(){
this.options = $merge.run([this.options].extend(arguments));
if (!this.addEvent) return this;
for (var option in this.options){
if ($type(this.options[option]) != 'function' || !(/^on[A-Z]/).test(option)) continue;
this.addEvent(option, this.options[option]);
delete this.options[option];
}
return this;
}
});
/*
Script: Element.js
One of the most important items in MooTools. Contains the dollar function, the dollars function, and an handful of cross-browser,
time-saver methods to let you easily work with HTML Elements.
License:
MIT-style license.
*/
var Element = new Native({
name: 'Element',
legacy: window.Element,
initialize: function(tag, props){
var konstructor = Element.Constructors.get(tag);
if (konstructor) return konstructor(props);
if (typeof tag == 'string') return document.newElement(tag, props);
return document.id(tag).set(props);
},
afterImplement: function(key, value){
Element.Prototype[key] = value;
if (Array[key]) return;
Elements.implement(key, function(){
var items = [], elements = true;
for (var i = 0, j = this.length; i < j; i++){
var returns = this[i][key].apply(this[i], arguments);
items.push(returns);
if (elements) elements = ($type(returns) == 'element');
}
return (elements) ? new Elements(items) : items;
});
}
});
Element.Prototype = {$family: {name: 'element'}};
Element.Constructors = new Hash;
var IFrame = new Native({
name: 'IFrame',
generics: false,
initialize: function(){
var params = Array.link(arguments, {properties: Object.type, iframe: $defined});
var props = params.properties || {};
var iframe = document.id(params.iframe);
var onload = props.onload || $empty;
delete props.onload;
props.id = props.name = $pick(props.id, props.name, iframe ? (iframe.id || iframe.name) : 'IFrame_' + $time());
iframe = new Element(iframe || 'iframe', props);
var onFrameLoad = function(){
var host = $try(function(){
return iframe.contentWindow.location.host;
});
if (!host || host == window.location.host){
var win = new Window(iframe.contentWindow);
new Document(iframe.contentWindow.document);
$extend(win.Element.prototype, Element.Prototype);
}
onload.call(iframe.contentWindow, iframe.contentWindow.document);
};
var contentWindow = $try(function(){
return iframe.contentWindow;
});
((contentWindow && contentWindow.document.body) || window.frames[props.id]) ? onFrameLoad() : iframe.addListener('load', onFrameLoad);
return iframe;
}
});
var Elements = new Native({
initialize: function(elements, options){
options = $extend({ddup: true, cash: true}, options);
elements = elements || [];
if (options.ddup || options.cash){
var uniques = {}, returned = [];
for (var i = 0, l = elements.length; i < l; i++){
var el = document.id(elements[i], !options.cash);
if (options.ddup){
if (uniques[el.uid]) continue;
uniques[el.uid] = true;
}
returned.push(el);
}
elements = returned;
}
return (options.cash) ? $extend(elements, this) : elements;
}
});
Elements.implement({
filter: function(filter, bind){
if (!filter) return this;
return new Elements(Array.filter(this, (typeof filter == 'string') ? function(item){
return item.match(filter);
} : filter, bind));
}
});
Document.implement({
newElement: function(tag, props){
if (Browser.Engine.trident && props){
['name', 'type', 'checked'].each(function(attribute){
if (!props[attribute]) return;
tag += ' ' + attribute + '="' + props[attribute] + '"';
if (attribute != 'checked') delete props[attribute];
});
tag = '<' + tag + '>';
}
return document.id(this.createElement(tag)).set(props);
},
newTextNode: function(text){
return this.createTextNode(text);
},
getDocument: function(){
return this;
},
getWindow: function(){
return this.window;
},
id: (function(){
var types = {
string: function(id, nocash, doc){
id = doc.getElementById(id);
return (id) ? types.element(id, nocash) : null;
},
element: function(el, nocash){
$uid(el);
if (!nocash && !el.$family && !(/^object|embed$/i).test(el.tagName)){
var proto = Element.Prototype;
for (var p in proto) el[p] = proto[p];
};
return el;
},
object: function(obj, nocash, doc){
if (obj.toElement) return types.element(obj.toElement(doc), nocash);
return null;
}
};
types.textnode = types.whitespace = types.window = types.document = $arguments(0);
return function(el, nocash, doc){
if (el && el.$family && el.uid) return el;
var type = $type(el);
return (types[type]) ? types[type](el, nocash, doc || document) : null;
};
})()
});
if (window.$ == null) Window.implement({
$: function(el, nc){
return document.id(el, nc, this.document);
}
});
Window.implement({
$$: function(selector){
if (arguments.length == 1 && typeof selector == 'string') return this.document.getElements(selector);
var elements = [];
var args = Array.flatten(arguments);
for (var i = 0, l = args.length; i < l; i++){
var item = args[i];
switch ($type(item)){
case 'element': elements.push(item); break;
case 'string': elements.extend(this.document.getElements(item, true));
}
}
return new Elements(elements);
},
getDocument: function(){
return this.document;
},
getWindow: function(){
return this;
}
});
Native.implement([Element, Document], {
getElement: function(selector, nocash){
return document.id(this.getElements(selector, true)[0] || null, nocash);
},
getElements: function(tags, nocash){
tags = tags.split(',');
var elements = [];
var ddup = (tags.length > 1);
tags.each(function(tag){
var partial = this.getElementsByTagName(tag.trim());
(ddup) ? elements.extend(partial) : elements = partial;
}, this);
return new Elements(elements, {ddup: ddup, cash: !nocash});
}
});
(function(){
var collected = {}, storage = {};
var props = {input: 'checked', option: 'selected', textarea: (Browser.Engine.webkit && Browser.Engine.version < 420) ? 'innerHTML' : 'value'};
var get = function(uid){
return (storage[uid] || (storage[uid] = {}));
};
var clean = function(item, retain){
if (!item) return;
var uid = item.uid;
if (Browser.Engine.trident){
if (item.clearAttributes){
var clone = retain && item.cloneNode(false);
item.clearAttributes();
if (clone) item.mergeAttributes(clone);
} else if (item.removeEvents){
item.removeEvents();
}
if ((/object/i).test(item.tagName)){
for (var p in item){
if (typeof item[p] == 'function') item[p] = $empty;
}
Element.dispose(item);
}
}	
if (!uid) return;
collected[uid] = storage[uid] = null;
};
var purge = function(){
Hash.each(collected, clean);
if (Browser.Engine.trident) $A(document.getElementsByTagName('object')).each(clean);
if (window.CollectGarbage) CollectGarbage();
collected = storage = null;
};
var walk = function(element, walk, start, match, all, nocash){
var el = element[start || walk];
var elements = [];
while (el){
if (el.nodeType == 1 && (!match || Element.match(el, match))){
if (!all) return document.id(el, nocash);
elements.push(el);
}
el = el[walk];
}
return (all) ? new Elements(elements, {ddup: false, cash: !nocash}) : null;
};
var attributes = {
'html': 'innerHTML',
'class': 'className',
'for': 'htmlFor',
'defaultValue': 'defaultValue',
'text': (Browser.Engine.trident || (Browser.Engine.webkit && Browser.Engine.version < 420)) ? 'innerText' : 'textContent'
};
var bools = ['compact', 'nowrap', 'ismap', 'declare', 'noshade', 'checked', 'disabled', 'readonly', 'multiple', 'selected', 'noresize', 'defer'];
var camels = ['value', 'type', 'defaultValue', 'accessKey', 'cellPadding', 'cellSpacing', 'colSpan', 'frameBorder', 'maxLength', 'readOnly', 'rowSpan', 'tabIndex', 'useMap'];
bools = bools.associate(bools);
Hash.extend(attributes, bools);
Hash.extend(attributes, camels.associate(camels.map(String.toLowerCase)));
var inserters = {
before: function(context, element){
if (element.parentNode) element.parentNode.insertBefore(context, element);
},
after: function(context, element){
if (!element.parentNode) return;
var next = element.nextSibling;
(next) ? element.parentNode.insertBefore(context, next) : element.parentNode.appendChild(context);
},
bottom: function(context, element){
element.appendChild(context);
},
top: function(context, element){
var first = element.firstChild;
(first) ? element.insertBefore(context, first) : element.appendChild(context);
}
};
inserters.inside = inserters.bottom;
Hash.each(inserters, function(inserter, where){
where = where.capitalize();
Element.implement('inject' + where, function(el){
inserter(this, document.id(el, true));
return this;
});
Element.implement('grab' + where, function(el){
inserter(document.id(el, true), this);
return this;
});
});
Element.implement({
set: function(prop, value){
switch ($type(prop)){
case 'object':
for (var p in prop) this.set(p, prop[p]);
break;
case 'string':
var property = Element.Properties.get(prop);
(property && property.set) ? property.set.apply(this, Array.slice(arguments, 1)) : this.setProperty(prop, value);
}
return this;
},
get: function(prop){
var property = Element.Properties.get(prop);
return (property && property.get) ? property.get.apply(this, Array.slice(arguments, 1)) : this.getProperty(prop);
},
erase: function(prop){
var property = Element.Properties.get(prop);
(property && property.erase) ? property.erase.apply(this) : this.removeProperty(prop);
return this;
},
setProperty: function(attribute, value){
var key = attributes[attribute];
if (value == undefined) return this.removeProperty(attribute);
if (key && bools[attribute]) value = !!value;
(key) ? this[key] = value : this.setAttribute(attribute, '' + value);
return this;
},
setProperties: function(attributes){
for (var attribute in attributes) this.setProperty(attribute, attributes[attribute]);
return this;
},
getProperty: function(attribute){
var key = attributes[attribute];
var value = (key) ? this[key] : this.getAttribute(attribute, 2);
return (bools[attribute]) ? !!value : (key) ? value : value || null;
},
getProperties: function(){
var args = $A(arguments);
return args.map(this.getProperty, this).associate(args);
},
removeProperty: function(attribute){
var key = attributes[attribute];
(key) ? this[key] = (key && bools[attribute]) ? false : '' : this.removeAttribute(attribute);
return this;
},
removeProperties: function(){
Array.each(arguments, this.removeProperty, this);
return this;
},
hasClass: function(className){
return this.className.contains(className, ' ');
},
addClass: function(className){
if (!this.hasClass(className)) this.className = (this.className + ' ' + className).clean();
return this;
},
removeClass: function(className){
this.className = this.className.replace(new RegExp('(^|\\s)' + className + '(?:\\s|$)'), '$1');
return this;
},
toggleClass: function(className){
return this.hasClass(className) ? this.removeClass(className) : this.addClass(className);
},
adopt: function(){
Array.flatten(arguments).each(function(element){
element = document.id(element, true);
if (element) this.appendChild(element);
}, this);
return this;
},
appendText: function(text, where){
return this.grab(this.getDocument().newTextNode(text), where);
},
grab: function(el, where){
inserters[where || 'bottom'](document.id(el, true), this);
return this;
},
inject: function(el, where){
inserters[where || 'bottom'](this, document.id(el, true));
return this;
},
replaces: function(el){
el = document.id(el, true);
el.parentNode.replaceChild(this, el);
return this;
},
wraps: function(el, where){
el = document.id(el, true);
return this.replaces(el).grab(el, where);
},
getPrevious: function(match, nocash){
return walk(this, 'previousSibling', null, match, false, nocash);
},
getAllPrevious: function(match, nocash){
return walk(this, 'previousSibling', null, match, true, nocash);
},
getNext: function(match, nocash){
return walk(this, 'nextSibling', null, match, false, nocash);
},
getAllNext: function(match, nocash){
return walk(this, 'nextSibling', null, match, true, nocash);
},
getFirst: function(match, nocash){
return walk(this, 'nextSibling', 'firstChild', match, false, nocash);
},
getLast: function(match, nocash){
return walk(this, 'previousSibling', 'lastChild', match, false, nocash);
},
getParent: function(match, nocash){
return walk(this, 'parentNode', null, match, false, nocash);
},
getParents: function(match, nocash){
return walk(this, 'parentNode', null, match, true, nocash);
},
getSiblings: function(match, nocash) {
return this.getParent().getChildren(match, nocash).erase(this);
},
getChildren: function(match, nocash){
return walk(this, 'nextSibling', 'firstChild', match, true, nocash);
},
getWindow: function(){
return this.ownerDocument.window;
},
getDocument: function(){
return this.ownerDocument;
},
getElementById: function(id, nocash){
var el = this.ownerDocument.getElementById(id);
if (!el) return null;
for (var parent = el.parentNode; parent != this; parent = parent.parentNode){
if (!parent) return null;
}
return document.id(el, nocash);
},
getSelected: function(){
return new Elements($A(this.options).filter(function(option){
return option.selected;
}));
},
getComputedStyle: function(property){
if (this.currentStyle) return this.currentStyle[property.camelCase()];
var computed = this.getDocument().defaultView.getComputedStyle(this, null);
return (computed) ? computed.getPropertyValue([property.hyphenate()]) : null;
},
toQueryString: function(){
var queryString = [];
this.getElements('input, select, textarea', true).each(function(el){
if (!el.name || el.disabled || el.type == 'submit' || el.type == 'reset' || el.type == 'file') return;
var value = (el.tagName.toLowerCase() == 'select') ? Element.getSelected(el).map(function(opt){
return opt.value;
}) : ((el.type == 'radio' || el.type == 'checkbox') && !el.checked) ? null : el.value;
$splat(value).each(function(val){
if (typeof val != 'undefined') queryString.push(el.name + '=' + encodeURIComponent(val));
});
});
return queryString.join('&');
},
clone: function(contents, keepid){
contents = contents !== false;
var clone = this.cloneNode(contents);
var clean = function(node, element){
if (!keepid) node.removeAttribute('id');
if (Browser.Engine.trident){
node.clearAttributes();
node.mergeAttributes(element);
node.removeAttribute('uid');
if (node.options){
var no = node.options, eo = element.options;
for (var j = no.length; j--;) no[j].selected = eo[j].selected;
}
}
var prop = props[element.tagName.toLowerCase()];
if (prop && element[prop]) node[prop] = element[prop];
};
if (contents){
var ce = clone.getElementsByTagName('*'), te = this.getElementsByTagName('*');
for (var i = ce.length; i--;) clean(ce[i], te[i]);
}
clean(clone, this);
return document.id(clone);
},
destroy: function(){
Element.empty(this);
Element.dispose(this);
clean(this, true);
return null;
},
empty: function(){
$A(this.childNodes).each(function(node){
Element.destroy(node);
});
return this;
},
dispose: function(){
return (this.parentNode) ? this.parentNode.removeChild(this) : this;
},
hasChild: function(el){
el = document.id(el, true);
if (!el) return false;
if (Browser.Engine.webkit && Browser.Engine.version < 420) return $A(this.getElementsByTagName(el.tagName)).contains(el);
return (this.contains) ? (this != el && this.contains(el)) : !!(this.compareDocumentPosition(el) & 16);
},
match: function(tag){
return (!tag || (tag == this) || (Element.get(this, 'tag') == tag));
}
});
Native.implement([Element, Window, Document], {
addListener: function(type, fn){
if (type == 'unload'){
var old = fn, self = this;
fn = function(){
self.removeListener('unload', fn);
old();
};
} else {
collected[this.uid] = this;
}
if (this.addEventListener) this.addEventListener(type, fn, false);
else this.attachEvent('on' + type, fn);
return this;
},
removeListener: function(type, fn){
if (this.removeEventListener) this.removeEventListener(type, fn, false);
else this.detachEvent('on' + type, fn);
return this;
},
retrieve: function(property, dflt){
var storage = get(this.uid), prop = storage[property];
if (dflt != undefined && prop == undefined) prop = storage[property] = dflt;
return $pick(prop);
},
store: function(property, value){
var storage = get(this.uid);
storage[property] = value;
return this;
},
eliminate: function(property){
var storage = get(this.uid);
delete storage[property];
return this;
}
});
window.addListener('unload', purge);
})();
Element.Properties = new Hash;
Element.Properties.style = {
set: function(style){
this.style.cssText = style;
},
get: function(){
return this.style.cssText;
},
erase: function(){
this.style.cssText = '';
}
};
Element.Properties.tag = {
get: function(){
return this.tagName.toLowerCase();
}
};
Element.Properties.html = (function(){
var wrapper = document.createElement('div');
var translations = {
table: [1, '<table>', '</table>'],
select: [1, '<select>', '</select>'],
tbody: [2, '<table><tbody>', '</tbody></table>'],
tr: [3, '<table><tbody><tr>', '</tr></tbody></table>']
};
translations.thead = translations.tfoot = translations.tbody;
var html = {
set: function(){
var html = Array.flatten(arguments).join('');
var wrap = Browser.Engine.trident && translations[this.get('tag')];
if (wrap){
var first = wrapper;
first.innerHTML = wrap[1] + html + wrap[2];
for (var i = wrap[0]; i--;) first = first.firstChild;
this.empty().adopt(first.childNodes);
} else {
this.innerHTML = html;
}
}
};
html.erase = html.set;
return html;
})();
if (Browser.Engine.webkit && Browser.Engine.version < 420) Element.Properties.text = {
get: function(){
if (this.innerText) return this.innerText;
var temp = this.ownerDocument.newElement('div', {html: this.innerHTML}).inject(this.ownerDocument.body);
var text = temp.innerText;
temp.destroy();
return text;
}
};
/*
Script: Element.Event.js
Contains Element methods for dealing with events, and custom Events.
License:
MIT-style license.
*/
Element.Properties.events = {set: function(events){
this.addEvents(events);
}};
Native.implement([Element, Window, Document], {
addEvent: function(type, fn){
var events = this.retrieve('events', {});
events[type] = events[type] || {'keys': [], 'values': []};
if (events[type].keys.contains(fn)) return this;
events[type].keys.push(fn);
var realType = type, custom = Element.Events.get(type), condition = fn, self = this;
if (custom){
if (custom.onAdd) custom.onAdd.call(this, fn);
if (custom.condition){
condition = function(event){
if (custom.condition.call(this, event)) return fn.call(this, event);
return true;
};
}
realType = custom.base || realType;
}
var defn = function(){
return fn.call(self);
};
var nativeEvent = Element.NativeEvents[realType];
if (nativeEvent){
if (nativeEvent == 2){
defn = function(event){
event = new Event(event, self.getWindow());
if (condition.call(self, event) === false) event.stop();
};
}
this.addListener(realType, defn);
}
events[type].values.push(defn);
return this;
},
removeEvent: function(type, fn){
var events = this.retrieve('events');
if (!events || !events[type]) return this;
var pos = events[type].keys.indexOf(fn);
if (pos == -1) return this;
events[type].keys.splice(pos, 1);
var value = events[type].values.splice(pos, 1)[0];
var custom = Element.Events.get(type);
if (custom){
if (custom.onRemove) custom.onRemove.call(this, fn);
type = custom.base || type;
}
return (Element.NativeEvents[type]) ? this.removeListener(type, value) : this;
},
addEvents: function(events){
for (var event in events) this.addEvent(event, events[event]);
return this;
},
removeEvents: function(events){
var type;
if ($type(events) == 'object'){
for (type in events) this.removeEvent(type, events[type]);
return this;
}
var attached = this.retrieve('events');
if (!attached) return this;
if (!events){
for (type in attached) this.removeEvents(type);
this.eliminate('events');
} else if (attached[events]){
while (attached[events].keys[0]) this.removeEvent(events, attached[events].keys[0]);
attached[events] = null;
}
return this;
},
fireEvent: function(type, args, delay){
var events = this.retrieve('events');
if (!events || !events[type]) return this;
events[type].keys.each(function(fn){
fn.create({'bind': this, 'delay': delay, 'arguments': args})();
}, this);
return this;
},
cloneEvents: function(from, type){
from = document.id(from);
var fevents = from.retrieve('events');
if (!fevents) return this;
if (!type){
for (var evType in fevents) this.cloneEvents(from, evType);
} else if (fevents[type]){
fevents[type].keys.each(function(fn){
this.addEvent(type, fn);
}, this);
}
return this;
}
});
Element.NativeEvents = {
click: 2, dblclick: 2, mouseup: 2, mousedown: 2, contextmenu: 2, //mouse buttons
mousewheel: 2, DOMMouseScroll: 2, //mouse wheel
mouseover: 2, mouseout: 2, mousemove: 2, selectstart: 2, selectend: 2, //mouse movement
keydown: 2, keypress: 2, keyup: 2, //keyboard
focus: 2, blur: 2, change: 2, reset: 2, select: 2, submit: 2, //form elements
load: 1, unload: 1, beforeunload: 2, resize: 1, move: 1, DOMContentLoaded: 1, readystatechange: 1, //window
error: 1, abort: 1, scroll: 1 //misc
};
(function(){
var $check = function(event){
var related = event.relatedTarget;
if (related == undefined) return true;
if (related === false) return false;
return ($type(this) != 'document' && related != this && related.prefix != 'xul' && !this.hasChild(related));
};
Element.Events = new Hash({
mouseenter: {
base: 'mouseover',
condition: $check
},
mouseleave: {
base: 'mouseout',
condition: $check
},
mousewheel: {
base: (Browser.Engine.gecko) ? 'DOMMouseScroll' : 'mousewheel'
}
});
})();
/*
Script: Element.Style.js
Contains methods for interacting with the styles of Elements in a fashionable way.
License:
MIT-style license.
*/
Element.Properties.styles = {set: function(styles){
this.setStyles(styles);
}};
Element.Properties.opacity = {
set: function(opacity, novisibility){
if (!novisibility){
if (opacity == 0){
if (this.style.visibility != 'hidden') this.style.visibility = 'hidden';
} else {
if (this.style.visibility != 'visible') this.style.visibility = 'visible';
}
}
if (!this.currentStyle || !this.currentStyle.hasLayout) this.style.zoom = 1;
if (Browser.Engine.trident) this.style.filter = (opacity == 1) ? '' : 'alpha(opacity=' + opacity * 100 + ')';
this.style.opacity = opacity;
this.store('opacity', opacity);
},
get: function(){
return this.retrieve('opacity', 1);
}
};
Element.implement({
setOpacity: function(value){
return this.set('opacity', value, true);
},
getOpacity: function(){
return this.get('opacity');
},
setStyle: function(property, value){
switch (property){
case 'opacity': return this.set('opacity', parseFloat(value));
case 'float': property = (Browser.Engine.trident) ? 'styleFloat' : 'cssFloat';
}
property = property.camelCase();
if ($type(value) != 'string'){
var map = (Element.Styles.get(property) || '@').split(' ');
value = $splat(value).map(function(val, i){
if (!map[i]) return '';
return ($type(val) == 'number') ? map[i].replace('@', Math.round(val)) : val;
}).join(' ');
} else if (value == String(Number(value))){
value = Math.round(value);
}
this.style[property] = value;
return this;
},
getStyle: function(property){
switch (property){
case 'opacity': return this.get('opacity');
case 'float': property = (Browser.Engine.trident) ? 'styleFloat' : 'cssFloat';
}
property = property.camelCase();
var result = this.style[property];
if (!$chk(result)){
result = [];
for (var style in Element.ShortStyles){
if (property != style) continue;
for (var s in Element.ShortStyles[style]) result.push(this.getStyle(s));
return result.join(' ');
}
result = this.getComputedStyle(property);
}
if (result){
result = String(result);
var color = result.match(/rgba?\([\d\s,]+\)/);
if (color) result = result.replace(color[0], color[0].rgbToHex());
}
if (Browser.Engine.presto || (Browser.Engine.trident && !$chk(parseInt(result, 10)))){
if (property.test(/^(height|width)$/)){
var values = (property == 'width') ? ['left', 'right'] : ['top', 'bottom'], size = 0;
values.each(function(value){
size += this.getStyle('border-' + value + '-width').toInt() + this.getStyle('padding-' + value).toInt();
}, this);
return this['offset' + property.capitalize()] - size + 'px';
}
if ((Browser.Engine.presto) && String(result).test('px')) return result;
if (property.test(/(border(.+)Width|margin|padding)/)) return '0px';
}
return result;
},
setStyles: function(styles){
for (var style in styles) this.setStyle(style, styles[style]);
return this;
},
getStyles: function(){
var result = {};
Array.flatten(arguments).each(function(key){
result[key] = this.getStyle(key);
}, this);
return result;
}
});
Element.Styles = new Hash({
left: '@px', top: '@px', bottom: '@px', right: '@px',
width: '@px', height: '@px', maxWidth: '@px', maxHeight: '@px', minWidth: '@px', minHeight: '@px',
backgroundColor: 'rgb(@, @, @)', backgroundPosition: '@px @px', color: 'rgb(@, @, @)',
fontSize: '@px', letterSpacing: '@px', lineHeight: '@px', clip: 'rect(@px @px @px @px)',
margin: '@px @px @px @px', padding: '@px @px @px @px', border: '@px @ rgb(@, @, @) @px @ rgb(@, @, @) @px @ rgb(@, @, @)',
borderWidth: '@px @px @px @px', borderStyle: '@ @ @ @', borderColor: 'rgb(@, @, @) rgb(@, @, @) rgb(@, @, @) rgb(@, @, @)',
zIndex: '@', 'zoom': '@', fontWeight: '@', textIndent: '@px', opacity: '@'
});
Element.ShortStyles = {margin: {}, padding: {}, border: {}, borderWidth: {}, borderStyle: {}, borderColor: {}};
['Top', 'Right', 'Bottom', 'Left'].each(function(direction){
var Short = Element.ShortStyles;
var All = Element.Styles;
['margin', 'padding'].each(function(style){
var sd = style + direction;
Short[style][sd] = All[sd] = '@px';
});
var bd = 'border' + direction;
Short.border[bd] = All[bd] = '@px @ rgb(@, @, @)';
var bdw = bd + 'Width', bds = bd + 'Style', bdc = bd + 'Color';
Short[bd] = {};
Short.borderWidth[bdw] = Short[bd][bdw] = All[bdw] = '@px';
Short.borderStyle[bds] = Short[bd][bds] = All[bds] = '@';
Short.borderColor[bdc] = Short[bd][bdc] = All[bdc] = 'rgb(@, @, @)';
});
/*
Script: Element.Dimensions.js
Contains methods to work with size, scroll, or positioning of Elements and the window object.
License:
MIT-style license.
Credits:
- Element positioning based on the [qooxdoo](http://qooxdoo.org/) code and smart browser fixes, [LGPL License](http://www.gnu.org/licenses/lgpl.html).
- Viewport dimensions based on [YUI](http://developer.yahoo.com/yui/) code, [BSD License](http://developer.yahoo.com/yui/license.html).
*/
(function(){
Element.implement({
scrollTo: function(x, y){
if (isBody(this)){
this.getWindow().scrollTo(x, y);
} else {
this.scrollLeft = x;
this.scrollTop = y;
}
return this;
},
getSize: function(){
if (isBody(this)) return this.getWindow().getSize();
return {x: this.offsetWidth, y: this.offsetHeight};
},
getScrollSize: function(){
if (isBody(this)) return this.getWindow().getScrollSize();
return {x: this.scrollWidth, y: this.scrollHeight};
},
getScroll: function(){
if (isBody(this)) return this.getWindow().getScroll();
return {x: this.scrollLeft, y: this.scrollTop};
},
getScrolls: function(){
var element = this, position = {x: 0, y: 0};
while (element && !isBody(element)){
position.x += element.scrollLeft;
position.y += element.scrollTop;
element = element.parentNode;
}
return position;
},
getOffsetParent: function(){
var element = this;
if (isBody(element)) return null;
if (!Browser.Engine.trident) return element.offsetParent;
while ((element = element.parentNode) && !isBody(element)){
if (styleString(element, 'position') != 'static') return element;
}
return null;
},
getOffsets: function(){	
if (this.getBoundingClientRect){
var bound = this.getBoundingClientRect(),
html = document.id(this.getDocument().documentElement),
scroll = html.getScroll(),
isFixed = (styleString(this, 'position') == 'fixed');
return {
x: parseInt(bound.left, 10) + ((isFixed) ? 0 : scroll.x) - html.clientLeft,
y: parseInt(bound.top, 10) + ((isFixed) ? 0 : scroll.y) - html.clientTop
};
}
var element = this, position = {x: 0, y: 0};
if (isBody(this)) return position;
while (element && !isBody(element)){
position.x += element.offsetLeft;
position.y += element.offsetTop;
if (Browser.Engine.gecko){
if (!borderBox(element)){
position.x += leftBorder(element);
position.y += topBorder(element);
}
var parent = element.parentNode;
if (parent && styleString(parent, 'overflow') != 'visible'){
position.x += leftBorder(parent);
position.y += topBorder(parent);
}
} else if (element != this && Browser.Engine.webkit){
position.x += leftBorder(element);
position.y += topBorder(element);
}
element = element.offsetParent;
}
if (Browser.Engine.gecko && !borderBox(this)){
position.x -= leftBorder(this);
position.y -= topBorder(this);
}
return position;
},
getPosition: function(relative){
if (isBody(this)) return {x: 0, y: 0};
var offset = this.getOffsets(), scroll = this.getScrolls();
var position = {x: offset.x - scroll.x, y: offset.y - scroll.y};
var relativePosition = (relative && (relative = document.id(relative))) ? relative.getPosition() : {x: 0, y: 0};
return {x: position.x - relativePosition.x, y: position.y - relativePosition.y};
},
getCoordinates: function(element){
if (isBody(this)) return this.getWindow().getCoordinates();
var position = this.getPosition(element), size = this.getSize();
var obj = {left: position.x, top: position.y, width: size.x, height: size.y};
obj.right = obj.left + obj.width;
obj.bottom = obj.top + obj.height;
return obj;
},
computePosition: function(obj){
return {left: obj.x - styleNumber(this, 'margin-left'), top: obj.y - styleNumber(this, 'margin-top')};
},
setPosition: function(obj){
return this.setStyles(this.computePosition(obj));
}
});
Native.implement([Document, Window], {
getSize: function(){
if (Browser.Engine.presto || Browser.Engine.webkit) {
var win = this.getWindow();
return {x: win.innerWidth, y: win.innerHeight};
}
var doc = getCompatElement(this);
return {x: doc.clientWidth, y: doc.clientHeight};
},
getScroll: function(){
var win = this.getWindow(), doc = getCompatElement(this);
return {x: win.pageXOffset || doc.scrollLeft, y: win.pageYOffset || doc.scrollTop};
},
getScrollSize: function(){
var doc = getCompatElement(this), min = this.getSize();
return {x: Math.max(doc.scrollWidth, min.x), y: Math.max(doc.scrollHeight, min.y)};
},
getPosition: function(){
return {x: 0, y: 0};
},
getCoordinates: function(){
var size = this.getSize();
return {top: 0, left: 0, bottom: size.y, right: size.x, height: size.y, width: size.x};
}
});
// private methods
var styleString = Element.getComputedStyle;
function styleNumber(element, style){
return styleString(element, style).toInt() || 0;
};
function borderBox(element){
return styleString(element, '-moz-box-sizing') == 'border-box';
};
function topBorder(element){
return styleNumber(element, 'border-top-width');
};
function leftBorder(element){
return styleNumber(element, 'border-left-width');
};
function isBody(element){
return (/^(?:body|html)$/i).test(element.tagName);
};
function getCompatElement(element){
var doc = element.getDocument();
return (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body;
};
})();
//aliases
Element.alias('setPosition', 'position'); //compatability
Native.implement([Window, Document, Element], {
getHeight: function(){
return this.getSize().y;
},
getWidth: function(){
return this.getSize().x;
},
getScrollTop: function(){
return this.getScroll().y;
},
getScrollLeft: function(){
return this.getScroll().x;
},
getScrollHeight: function(){
return this.getScrollSize().y;
},
getScrollWidth: function(){
return this.getScrollSize().x;
},
getTop: function(){
return this.getPosition().y;
},
getLeft: function(){
return this.getPosition().x;
}
});
/*
Script: Selectors.js
Adds advanced CSS Querying capabilities for targeting elements. Also includes pseudoselectors support.
License:
MIT-style license.
*/
Native.implement([Document, Element], {
getElements: function(expression, nocash){
expression = expression.split(',');
var items, local = {};
for (var i = 0, l = expression.length; i < l; i++){
var selector = expression[i], elements = Selectors.Utils.search(this, selector, local);
if (i != 0 && elements.item) elements = $A(elements);
items = (i == 0) ? elements : (items.item) ? $A(items).concat(elements) : items.concat(elements);
}
return new Elements(items, {ddup: (expression.length > 1), cash: !nocash});
}
});
Element.implement({
match: function(selector){
if (!selector || (selector == this)) return true;
var tagid = Selectors.Utils.parseTagAndID(selector);
var tag = tagid[0], id = tagid[1];
if (!Selectors.Filters.byID(this, id) || !Selectors.Filters.byTag(this, tag)) return false;
var parsed = Selectors.Utils.parseSelector(selector);
return (parsed) ? Selectors.Utils.filter(this, parsed, {}) : true;
}
});
var Selectors = {Cache: {nth: {}, parsed: {}}};
Selectors.RegExps = {
id: (/#([\w-]+)/),
tag: (/^(\w+|\*)/),
quick: (/^(\w+|\*)$/),
splitter: (/\s*([+>~\s])\s*([a-zA-Z#.*:\[])/g),
combined: (/\.([\w-]+)|\[(\w+)(?:([!*^$~|]?=)(["']?)([^\4]*?)\4)?\]|:([\w-]+)(?:\(["']?(.*?)?["']?\)|$)/g)
};
Selectors.Utils = {
chk: function(item, uniques){
if (!uniques) return true;
var uid = $uid(item);
if (!uniques[uid]) return uniques[uid] = true;
return false;
},
parseNthArgument: function(argument){
if (Selectors.Cache.nth[argument]) return Selectors.Cache.nth[argument];
var parsed = argument.match(/^([+-]?\d*)?([a-z]+)?([+-]?\d*)?$/);
if (!parsed) return false;
var inta = parseInt(parsed[1], 10);
var a = (inta || inta === 0) ? inta : 1;
var special = parsed[2] || false;
var b = parseInt(parsed[3], 10) || 0;
if (a != 0){
b--;
while (b < 1) b += a;
while (b >= a) b -= a;
} else {
a = b;
special = 'index';
}
switch (special){
case 'n': parsed = {a: a, b: b, special: 'n'}; break;
case 'odd': parsed = {a: 2, b: 0, special: 'n'}; break;
case 'even': parsed = {a: 2, b: 1, special: 'n'}; break;
case 'first': parsed = {a: 0, special: 'index'}; break;
case 'last': parsed = {special: 'last-child'}; break;
case 'only': parsed = {special: 'only-child'}; break;
default: parsed = {a: (a - 1), special: 'index'};
}
return Selectors.Cache.nth[argument] = parsed;
},
parseSelector: function(selector){
if (Selectors.Cache.parsed[selector]) return Selectors.Cache.parsed[selector];
var m, parsed = {classes: [], pseudos: [], attributes: []};
while ((m = Selectors.RegExps.combined.exec(selector))){
var cn = m[1], an = m[2], ao = m[3], av = m[5], pn = m[6], pa = m[7];
if (cn){
parsed.classes.push(cn);
} else if (pn){
var parser = Selectors.Pseudo.get(pn);
if (parser) parsed.pseudos.push({parser: parser, argument: pa});
else parsed.attributes.push({name: pn, operator: '=', value: pa});
} else if (an){
parsed.attributes.push({name: an, operator: ao, value: av});
}
}
if (!parsed.classes.length) delete parsed.classes;
if (!parsed.attributes.length) delete parsed.attributes;
if (!parsed.pseudos.length) delete parsed.pseudos;
if (!parsed.classes && !parsed.attributes && !parsed.pseudos) parsed = null;
return Selectors.Cache.parsed[selector] = parsed;
},
parseTagAndID: function(selector){
var tag = selector.match(Selectors.RegExps.tag);
var id = selector.match(Selectors.RegExps.id);
return [(tag) ? tag[1] : '*', (id) ? id[1] : false];
},
filter: function(item, parsed, local){
var i;
if (parsed.classes){
for (i = parsed.classes.length; i--; i){
var cn = parsed.classes[i];
if (!Selectors.Filters.byClass(item, cn)) return false;
}
}
if (parsed.attributes){
for (i = parsed.attributes.length; i--; i){
var att = parsed.attributes[i];
if (!Selectors.Filters.byAttribute(item, att.name, att.operator, att.value)) return false;
}
}
if (parsed.pseudos){
for (i = parsed.pseudos.length; i--; i){
var psd = parsed.pseudos[i];
if (!Selectors.Filters.byPseudo(item, psd.parser, psd.argument, local)) return false;
}
}
return true;
},
getByTagAndID: function(ctx, tag, id){
if (id){
var item = (ctx.getElementById) ? ctx.getElementById(id, true) : Element.getElementById(ctx, id, true);
return (item && Selectors.Filters.byTag(item, tag)) ? [item] : [];
} else {
return ctx.getElementsByTagName(tag);
}
},
search: function(self, expression, local){
var splitters = [];
var selectors = expression.trim().replace(Selectors.RegExps.splitter, function(m0, m1, m2){
splitters.push(m1);
return ':)' + m2;
}).split(':)');
var items, filtered, item;
for (var i = 0, l = selectors.length; i < l; i++){
var selector = selectors[i];
if (i == 0 && Selectors.RegExps.quick.test(selector)){
items = self.getElementsByTagName(selector);
continue;
}
var splitter = splitters[i - 1];
var tagid = Selectors.Utils.parseTagAndID(selector);
var tag = tagid[0], id = tagid[1];
if (i == 0){
items = Selectors.Utils.getByTagAndID(self, tag, id);
} else {
var uniques = {}, found = [];
for (var j = 0, k = items.length; j < k; j++) found = Selectors.Getters[splitter](found, items[j], tag, id, uniques);
items = found;
}
var parsed = Selectors.Utils.parseSelector(selector);
if (parsed){
filtered = [];
for (var m = 0, n = items.length; m < n; m++){
item = items[m];
if (Selectors.Utils.filter(item, parsed, local)) filtered.push(item);
}
items = filtered;
}
}
return items;
}
};
Selectors.Getters = {
' ': function(found, self, tag, id, uniques){
var items = Selectors.Utils.getByTagAndID(self, tag, id);
for (var i = 0, l = items.length; i < l; i++){
var item = items[i];
if (Selectors.Utils.chk(item, uniques)) found.push(item);
}
return found;
},
'>': function(found, self, tag, id, uniques){
var children = Selectors.Utils.getByTagAndID(self, tag, id);
for (var i = 0, l = children.length; i < l; i++){
var child = children[i];
if (child.parentNode == self && Selectors.Utils.chk(child, uniques)) found.push(child);
}
return found;
},
'+': function(found, self, tag, id, uniques){
while ((self = self.nextSibling)){
if (self.nodeType == 1){
if (Selectors.Utils.chk(self, uniques) && Selectors.Filters.byTag(self, tag) && Selectors.Filters.byID(self, id)) found.push(self);
break;
}
}
return found;
},
'~': function(found, self, tag, id, uniques){
while ((self = self.nextSibling)){
if (self.nodeType == 1){
if (!Selectors.Utils.chk(self, uniques)) break;
if (Selectors.Filters.byTag(self, tag) && Selectors.Filters.byID(self, id)) found.push(self);
}
}
return found;
}
};
Selectors.Filters = {
byTag: function(self, tag){
return (tag == '*' || (self.tagName && self.tagName.toLowerCase() == tag));
},
byID: function(self, id){
return (!id || (self.id && self.id == id));
},
byClass: function(self, klass){
return (self.className && self.className.contains(klass, ' '));
},
byPseudo: function(self, parser, argument, local){
return parser.call(self, argument, local);
},
byAttribute: function(self, name, operator, value){
var result = Element.prototype.getProperty.call(self, name);
if (!result) return (operator == '!=');
if (!operator || value == undefined) return true;
switch (operator){
case '=': return (result == value);
case '*=': return (result.contains(value));
case '^=': return (result.substr(0, value.length) == value);
case '$=': return (result.substr(result.length - value.length) == value);
case '!=': return (result != value);
case '~=': return result.contains(value, ' ');
case '|=': return result.contains(value, '-');
}
return false;
}
};
Selectors.Pseudo = new Hash({
// w3c pseudo selectors
checked: function(){
return this.checked;
},
empty: function(){
return !(this.innerText || this.textContent || '').length;
},
not: function(selector){
return !Element.match(this, selector);
},
contains: function(text){
return (this.innerText || this.textContent || '').contains(text);
},
'first-child': function(){
return Selectors.Pseudo.index.call(this, 0);
},
'last-child': function(){
var element = this;
while ((element = element.nextSibling)){
if (element.nodeType == 1) return false;
}
return true;
},
'only-child': function(){
var prev = this;
while ((prev = prev.previousSibling)){
if (prev.nodeType == 1) return false;
}
var next = this;
while ((next = next.nextSibling)){
if (next.nodeType == 1) return false;
}
return true;
},
'nth-child': function(argument, local){
argument = (argument == undefined) ? 'n' : argument;
var parsed = Selectors.Utils.parseNthArgument(argument);
if (parsed.special != 'n') return Selectors.Pseudo[parsed.special].call(this, parsed.a, local);
var count = 0;
local.positions = local.positions || {};
var uid = $uid(this);
if (!local.positions[uid]){
var self = this;
while ((self = self.previousSibling)){
if (self.nodeType != 1) continue;
count ++;
var position = local.positions[$uid(self)];
if (position != undefined){
count = position + count;
break;
}
}
local.positions[uid] = count;
}
return (local.positions[uid] % parsed.a == parsed.b);
},
// custom pseudo selectors
index: function(index){
var element = this, count = 0;
while ((element = element.previousSibling)){
if (element.nodeType == 1 && ++count > index) return false;
}
return (count == index);
},
even: function(argument, local){
return Selectors.Pseudo['nth-child'].call(this, '2n+1', local);
},
odd: function(argument, local){
return Selectors.Pseudo['nth-child'].call(this, '2n', local);
},
selected: function(){
return this.selected;
},
enabled: function(){
return (this.disabled === false);
}
});
/*
Script: Domready.js
Contains the domready custom event.
License:
MIT-style license.
*/
Element.Events.domready = {
onAdd: function(fn){
if (Browser.loaded) fn.call(this);
}
};
(function(){
var domready = function(){
if (Browser.loaded) return;
Browser.loaded = true;
window.fireEvent('domready');
document.fireEvent('domready');
};
if (Browser.Engine.trident){
var temp = document.createElement('div');
(function(){
($try(function(){
temp.doScroll(); // Technique by Diego Perini
return document.id(temp).inject(document.body).set('html', 'temp').dispose();
})) ? domready() : arguments.callee.delay(50);
})();
} else if (Browser.Engine.webkit && Browser.Engine.version < 525){
(function(){
(['loaded', 'complete'].contains(document.readyState)) ? domready() : arguments.callee.delay(50);
})();
} else {
window.addEvent('load', domready);
document.addEvent('DOMContentLoaded', domready);
}
})();
/*
Script: JSON.js
JSON encoder and decoder.
License:
MIT-style license.
See Also:
<http://www.json.org/>
*/
var JSON = new Hash({
$specialChars: {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', '\\': '\\\\'},
$replaceChars: function(chr){
return JSON.$specialChars[chr] || '\\u00' + Math.floor(chr.charCodeAt() / 16).toString(16) + (chr.charCodeAt() % 16).toString(16);
},
encode: function(obj){
switch ($type(obj)){
case 'string':
return '"' + obj.replace(/[\x00-\x1f\\"]/g, JSON.$replaceChars) + '"';
case 'array':
return '[' + String(obj.map(JSON.encode).clean()) + ']';
case 'object': case 'hash':
var string = [];
Hash.each(obj, function(value, key){
var json = JSON.encode(value);
if (json) string.push(JSON.encode(key) + ':' + json);
});
return '{' + string + '}';
case 'number': case 'boolean': return String(obj);
case false: return 'null';
}
return null;
},
decode: function(string, secure){
if ($type(string) != 'string' || !string.length) return null;
if (secure && !(/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(string.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''))) return null;
return eval('(' + string + ')');
}
});
Native.implement([Hash, Array, String, Number], {
toJSON: function(){
return JSON.encode(this);
}
});
/*
Script: Cookie.js
Class for creating, loading, and saving browser Cookies.
License:
MIT-style license.
Credits:
Based on the functions by Peter-Paul Koch (http://quirksmode.org).
*/
var Cookie = new Class({
Implements: Options,
options: {
path: false,
domain: false,
duration: false,
secure: false,
document: document
},
initialize: function(key, options){
this.key = key;
this.setOptions(options);
},
write: function(value){
value = encodeURIComponent(value);
if (this.options.domain) value += '; domain=' + this.options.domain;
if (this.options.path) value += '; path=' + this.options.path;
if (this.options.duration){
var date = new Date();
date.setTime(date.getTime() + this.options.duration * 24 * 60 * 60 * 1000);
value += '; expires=' + date.toGMTString();
}
if (this.options.secure) value += '; secure';
this.options.document.cookie = this.key + '=' + value;
return this;
},
read: function(){
var value = this.options.document.cookie.match('(?:^|;)\\s*' + this.key.escapeRegExp() + '=([^;]*)');
return (value) ? decodeURIComponent(value[1]) : null;
},
dispose: function(){
new Cookie(this.key, $merge(this.options, {duration: -1})).write('');
return this;
}
});
Cookie.write = function(key, value, options){
return new Cookie(key, options).write(value);
};
Cookie.read = function(key){
return new Cookie(key).read();
};
Cookie.dispose = function(key, options){
return new Cookie(key, options).dispose();
};
/*
Script: Fx.js
Contains the basic animation logic to be extended by all other Fx Classes.
License:
MIT-style license.
*/
var Fx = new Class({
Implements: [Chain, Events, Options],
options: {
/*
onStart: $empty,
onCancel: $empty,
onComplete: $empty,
*/
fps: 50,
unit: false,
duration: 500,
link: 'ignore'
},
initialize: function(options){
this.subject = this.subject || this;
this.setOptions(options);
this.options.duration = Fx.Durations[this.options.duration] || this.options.duration.toInt();
var wait = this.options.wait;
if (wait === false) this.options.link = 'cancel';
},
getTransition: function(){
return function(p){
return -(Math.cos(Math.PI * p) - 1) / 2;
};
},
step: function(){
var time = $time();
if (time < this.time + this.options.duration){
var delta = this.transition((time - this.time) / this.options.duration);
this.set(this.compute(this.from, this.to, delta));
} else {
this.set(this.compute(this.from, this.to, 1));
this.complete();
}
},
set: function(now){
return now;
},
compute: function(from, to, delta){
return Fx.compute(from, to, delta);
},
check: function(){
if (!this.timer) return true;
switch (this.options.link){
case 'cancel': this.cancel(); return true;
case 'chain': this.chain(this.caller.bind(this, arguments)); return false;
}
return false;
},
start: function(from, to){
if (!this.check(from, to)) return this;
this.from = from;
this.to = to;
this.time = 0;
this.transition = this.getTransition();
this.startTimer();
this.onStart();
return this;
},
complete: function(){
if (this.stopTimer()) this.onComplete();
return this;
},
cancel: function(){
if (this.stopTimer()) this.onCancel();
return this;
},
onStart: function(){
this.fireEvent('start', this.subject);
},
onComplete: function(){
this.fireEvent('complete', this.subject);
if (!this.callChain()) this.fireEvent('chainComplete', this.subject);
},
onCancel: function(){
this.fireEvent('cancel', this.subject).clearChain();
},
pause: function(){
this.stopTimer();
return this;
},
resume: function(){
this.startTimer();
return this;
},
stopTimer: function(){
if (!this.timer) return false;
this.time = $time() - this.time;
this.timer = $clear(this.timer);
return true;
},
startTimer: function(){
if (this.timer) return false;
this.time = $time() - this.time;
this.timer = this.step.periodical(Math.round(1000 / this.options.fps), this);
return true;
}
});
Fx.compute = function(from, to, delta){
return (to - from) * delta + from;
};
Fx.Durations = {'short': 250, 'normal': 500, 'long': 1000};
/*
Script: Fx.CSS.js
Contains the CSS animation logic. Used by Fx.Tween, Fx.Morph, Fx.Elements.
License:
MIT-style license.
*/
Fx.CSS = new Class({
Extends: Fx,
//prepares the base from/to object
prepare: function(element, property, values){
values = $splat(values);
var values1 = values[1];
if (!$chk(values1)){
values[1] = values[0];
values[0] = element.getStyle(property);
}
var parsed = values.map(this.parse);
return {from: parsed[0], to: parsed[1]};
},
//parses a value into an array
parse: function(value){
value = $lambda(value)();
value = (typeof value == 'string') ? value.split(' ') : $splat(value);
return value.map(function(val){
val = String(val);
var found = false;
Fx.CSS.Parsers.each(function(parser, key){
if (found) return;
var parsed = parser.parse(val);
if ($chk(parsed)) found = {value: parsed, parser: parser};
});
found = found || {value: val, parser: Fx.CSS.Parsers.String};
return found;
});
},
//computes by a from and to prepared objects, using their parsers.
compute: function(from, to, delta){
var computed = [];
(Math.min(from.length, to.length)).times(function(i){
computed.push({value: from[i].parser.compute(from[i].value, to[i].value, delta), parser: from[i].parser});
});
computed.$family = {name: 'fx:css:value'};
return computed;
},
//serves the value as settable
serve: function(value, unit){
if ($type(value) != 'fx:css:value') value = this.parse(value);
var returned = [];
value.each(function(bit){
returned = returned.concat(bit.parser.serve(bit.value, unit));
});
return returned;
},
//renders the change to an element
render: function(element, property, value, unit){
element.setStyle(property, this.serve(value, unit));
},
//searches inside the page css to find the values for a selector
search: function(selector){
if (Fx.CSS.Cache[selector]) return Fx.CSS.Cache[selector];
var to = {};
Array.each(document.styleSheets, function(sheet, j){
var href = sheet.href;
if (href && href.contains('://') && !href.contains(document.domain)) return;
var rules = sheet.rules || sheet.cssRules;
Array.each(rules, function(rule, i){
if (!rule.style) return;
var selectorText = (rule.selectorText) ? rule.selectorText.replace(/^\w+/, function(m){
return m.toLowerCase();
}) : null;
if (!selectorText || !selectorText.test('^' + selector + '$')) return;
Element.Styles.each(function(value, style){
if (!rule.style[style] || Element.ShortStyles[style]) return;
value = String(rule.style[style]);
to[style] = (value.test(/^rgb/)) ? value.rgbToHex() : value;
});
});
});
return Fx.CSS.Cache[selector] = to;
}
});
Fx.CSS.Cache = {};
Fx.CSS.Parsers = new Hash({
Color: {
parse: function(value){
if (value.match(/^#[0-9a-f]{3,6}$/i)) return value.hexToRgb(true);
return ((value = value.match(/(\d+),\s*(\d+),\s*(\d+)/))) ? [value[1], value[2], value[3]] : false;
},
compute: function(from, to, delta){
return from.map(function(value, i){
return Math.round(Fx.compute(from[i], to[i], delta));
});
},
serve: function(value){
return value.map(Number);
}
},
Number: {
parse: parseFloat,
compute: Fx.compute,
serve: function(value, unit){
return (unit) ? value + unit : value;
}
},
String: {
parse: $lambda(false),
compute: $arguments(1),
serve: $arguments(0)
}
});
/*
Script: Fx.Tween.js
Formerly Fx.Style, effect to transition any CSS property for an element.
License:
MIT-style license.
*/
Fx.Tween = new Class({
Extends: Fx.CSS,
initialize: function(element, options){
this.element = this.subject = document.id(element);
this.parent(options);
},
set: function(property, now){
if (arguments.length == 1){
now = property;
property = this.property || this.options.property;
}
this.render(this.element, property, now, this.options.unit);
return this;
},
start: function(property, from, to){
if (!this.check(property, from, to)) return this;
var args = Array.flatten(arguments);
this.property = this.options.property || args.shift();
var parsed = this.prepare(this.element, this.property, args);
return this.parent(parsed.from, parsed.to);
}
});
Element.Properties.tween = {
set: function(options){
var tween = this.retrieve('tween');
if (tween) tween.cancel();
return this.eliminate('tween').store('tween:options', $extend({link: 'cancel'}, options));
},
get: function(options){
if (options || !this.retrieve('tween')){
if (options || !this.retrieve('tween:options')) this.set('tween', options);
this.store('tween', new Fx.Tween(this, this.retrieve('tween:options')));
}
return this.retrieve('tween');
}
};
Element.implement({
tween: function(property, from, to){
this.get('tween').start(arguments);
return this;
},
fade: function(how){
var fade = this.get('tween'), o = 'opacity', toggle;
how = $pick(how, 'toggle');
switch (how){
case 'in': fade.start(o, 1); break;
case 'out': fade.start(o, 0); break;
case 'show': fade.set(o, 1); break;
case 'hide': fade.set(o, 0); break;
case 'toggle':
var flag = this.retrieve('fade:flag', this.get('opacity') == 1);
fade.start(o, (flag) ? 0 : 1);
this.store('fade:flag', !flag);
toggle = true;
break;
default: fade.start(o, arguments);
}
if (!toggle) this.eliminate('fade:flag');
return this;
},
highlight: function(start, end){
if (!end){
end = this.retrieve('highlight:original', this.getStyle('background-color'));
end = (end == 'transparent') ? '#fff' : end;
}
var tween = this.get('tween');
tween.start('background-color', start || '#ffff88', end).chain(function(){
this.setStyle('background-color', this.retrieve('highlight:original'));
tween.callChain();
}.bind(this));
return this;
}
});
/*
Script: Fx.Morph.js
Formerly Fx.Styles, effect to transition any number of CSS properties for an element using an object of rules, or CSS based selector rules.
License:
MIT-style license.
*/
Fx.Morph = new Class({
Extends: Fx.CSS,
initialize: function(element, options){
this.element = this.subject = document.id(element);
this.parent(options);
},
set: function(now){
if (typeof now == 'string') now = this.search(now);
for (var p in now) this.render(this.element, p, now[p], this.options.unit);
return this;
},
compute: function(from, to, delta){
var now = {};
for (var p in from) now[p] = this.parent(from[p], to[p], delta);
return now;
},
start: function(properties){
if (!this.check(properties)) return this;
if (typeof properties == 'string') properties = this.search(properties);
var from = {}, to = {};
for (var p in properties){
var parsed = this.prepare(this.element, p, properties[p]);
from[p] = parsed.from;
to[p] = parsed.to;
}
return this.parent(from, to);
}
});
Element.Properties.morph = {
set: function(options){
var morph = this.retrieve('morph');
if (morph) morph.cancel();
return this.eliminate('morph').store('morph:options', $extend({link: 'cancel'}, options));
},
get: function(options){
if (options || !this.retrieve('morph')){
if (options || !this.retrieve('morph:options')) this.set('morph', options);
this.store('morph', new Fx.Morph(this, this.retrieve('morph:options')));
}
return this.retrieve('morph');
}
};
Element.implement({
morph: function(props){
this.get('morph').start(props);
return this;
}
});
/*
Script: Fx.Transitions.js
Contains a set of advanced transitions to be used with any of the Fx Classes.
License:
MIT-style license.
Credits:
Easing Equations by Robert Penner, <http://www.robertpenner.com/easing/>, modified and optimized to be used with MooTools.
*/
Fx.implement({
getTransition: function(){
var trans = this.options.transition || Fx.Transitions.Sine.easeInOut;
if (typeof trans == 'string'){
var data = trans.split(':');
trans = Fx.Transitions;
trans = trans[data[0]] || trans[data[0].capitalize()];
if (data[1]) trans = trans['ease' + data[1].capitalize() + (data[2] ? data[2].capitalize() : '')];
}
return trans;
}
});
Fx.Transition = function(transition, params){
params = $splat(params);
return $extend(transition, {
easeIn: function(pos){
return transition(pos, params);
},
easeOut: function(pos){
return 1 - transition(1 - pos, params);
},
easeInOut: function(pos){
return (pos <= 0.5) ? transition(2 * pos, params) / 2 : (2 - transition(2 * (1 - pos), params)) / 2;
}
});
};
Fx.Transitions = new Hash({
linear: $arguments(0)
});
Fx.Transitions.extend = function(transitions){
for (var transition in transitions) Fx.Transitions[transition] = new Fx.Transition(transitions[transition]);
};
Fx.Transitions.extend({
Pow: function(p, x){
return Math.pow(p, x[0] || 6);
},
Expo: function(p){
return Math.pow(2, 8 * (p - 1));
},
Circ: function(p){
return 1 - Math.sin(Math.acos(p));
},
Sine: function(p){
return 1 - Math.sin((1 - p) * Math.PI / 2);
},
Back: function(p, x){
x = x[0] || 1.618;
return Math.pow(p, 2) * ((x + 1) * p - x);
},
Bounce: function(p){
var value;
for (var a = 0, b = 1; 1; a += b, b /= 2){
if (p >= (7 - 4 * a) / 11){
value = b * b - Math.pow((11 - 6 * a - 11 * p) / 4, 2);
break;
}
}
return value;
},
Elastic: function(p, x){
return Math.pow(2, 10 * --p) * Math.cos(20 * p * Math.PI * (x[0] || 1) / 3);
}
});
['Quad', 'Cubic', 'Quart', 'Quint'].each(function(transition, i){
Fx.Transitions[transition] = new Fx.Transition(function(p){
return Math.pow(p, [i + 2]);
});
});
/*
Script: Request.js
Powerful all purpose Request Class. Uses XMLHTTPRequest.
License:
MIT-style license.
*/
var Request = new Class({
Implements: [Chain, Events, Options],
options: {/*
onRequest: $empty,
onComplete: $empty,
onCancel: $empty,
onSuccess: $empty,
onFailure: $empty,
onException: $empty,*/
url: '',
data: '',
headers: {
'X-Requested-With': 'XMLHttpRequest',
'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
},
async: true,
format: false,
method: 'post',
link: 'ignore',
isSuccess: null,
emulation: true,
urlEncoded: true,
encoding: 'utf-8',
evalScripts: false,
evalResponse: false,
noCache: false
},
initialize: function(options){
this.xhr = new Browser.Request();
this.setOptions(options);
this.options.isSuccess = this.options.isSuccess || this.isSuccess;
this.headers = new Hash(this.options.headers);
},
onStateChange: function(){
if (this.xhr.readyState != 4 || !this.running) return;
this.running = false;
this.status = 0;
$try(function(){
this.status = this.xhr.status;
}.bind(this));
this.xhr.onreadystatechange = $empty;
if (this.options.isSuccess.call(this, this.status)){
this.response = {text: this.xhr.responseText, xml: this.xhr.responseXML};
this.success(this.response.text, this.response.xml);
} else {
this.response = {text: null, xml: null};
this.failure();
}
},
isSuccess: function(){
return ((this.status >= 200) && (this.status < 300));
},
processScripts: function(text){
if (this.options.evalResponse || (/(ecma|java)script/).test(this.getHeader('Content-type'))) return $exec(text);
return text.stripScripts(this.options.evalScripts);
},
success: function(text, xml){
this.onSuccess(this.processScripts(text), xml);
},
onSuccess: function(){
this.fireEvent('complete', arguments).fireEvent('success', arguments).callChain();
},
failure: function(){
this.onFailure();
},
onFailure: function(){
this.fireEvent('complete').fireEvent('failure', this.xhr);
},
setHeader: function(name, value){
this.headers.set(name, value);
return this;
},
getHeader: function(name){
return $try(function(){
return this.xhr.getResponseHeader(name);
}.bind(this));
},
check: function(){
if (!this.running) return true;
switch (this.options.link){
case 'cancel': this.cancel(); return true;
case 'chain': this.chain(this.caller.bind(this, arguments)); return false;
}
return false;
},
send: function(options){
if (!this.check(options)) return this;
this.running = true;
var type = $type(options);
if (type == 'string' || type == 'element') options = {data: options};
var old = this.options;
options = $extend({data: old.data, url: old.url, method: old.method}, options);
var data = options.data, url = options.url, method = options.method.toLowerCase();
switch ($type(data)){
case 'element': data = document.id(data).toQueryString(); break;
case 'object': case 'hash': data = Hash.toQueryString(data);
}
if (this.options.format){
var format = 'format=' + this.options.format;
data = (data) ? format + '&' + data : format;
}
if (this.options.emulation && !['get', 'post'].contains(method)){
var _method = '_method=' + method;
data = (data) ? _method + '&' + data : _method;
method = 'post';
}
if (this.options.urlEncoded && method == 'post'){
var encoding = (this.options.encoding) ? '; charset=' + this.options.encoding : '';
this.headers.set('Content-type', 'application/x-www-form-urlencoded' + encoding);
}
if (this.options.noCache){
var noCache = 'noCache=' + new Date().getTime();
data = (data) ? noCache + '&' + data : noCache;
}
var trimPosition = url.lastIndexOf('/');
if (trimPosition > -1 && (trimPosition = url.indexOf('#')) > -1) url = url.substr(0, trimPosition);
if (data && method == 'get'){
url = url + (url.contains('?') ? '&' : '?') + data;
data = null;
}
this.xhr.open(method.toUpperCase(), url, this.options.async);
this.xhr.onreadystatechange = this.onStateChange.bind(this);
this.headers.each(function(value, key){
try {
this.xhr.setRequestHeader(key, value);
} catch (e){
this.fireEvent('exception', [key, value]);
}
}, this);
this.fireEvent('request');
this.xhr.send(data);
if (!this.options.async) this.onStateChange();
return this;
},
cancel: function(){
if (!this.running) return this;
this.running = false;
this.xhr.abort();
this.xhr.onreadystatechange = $empty;
this.xhr = new Browser.Request();
this.fireEvent('cancel');
return this;
}
});
(function(){
var methods = {};
['get', 'post', 'put', 'delete', 'GET', 'POST', 'PUT', 'DELETE'].each(function(method){
methods[method] = function(){
var params = Array.link(arguments, {url: String.type, data: $defined});
return this.send($extend(params, {method: method}));
};
});
Request.implement(methods);
})();
Element.Properties.send = {
set: function(options){
var send = this.retrieve('send');
if (send) send.cancel();
return this.eliminate('send').store('send:options', $extend({
data: this, link: 'cancel', method: this.get('method') || 'post', url: this.get('action')
}, options));
},
get: function(options){
if (options || !this.retrieve('send')){
if (options || !this.retrieve('send:options')) this.set('send', options);
this.store('send', new Request(this.retrieve('send:options')));
}
return this.retrieve('send');
}
};
Element.implement({
send: function(url){
var sender = this.get('send');
sender.send({data: this, url: url || sender.options.url});
return this;
}
});
/*
Script: Request.HTML.js
Extends the basic Request Class with additional methods for interacting with HTML responses.
License:
MIT-style license.
*/
Request.HTML = new Class({
Extends: Request,
options: {
update: false,
append: false,
evalScripts: true,
filter: false
},
processHTML: function(text){
var match = text.match(/<body[^>]*>([\s\S]*?)<\/body>/i);
text = (match) ? match[1] : text;
var container = new Element('div');
return $try(function(){
var root = '<root>' + text + '</root>', doc;
if (Browser.Engine.trident){
doc = new ActiveXObject('Microsoft.XMLDOM');
doc.async = false;
doc.loadXML(root);
} else {
doc = new DOMParser().parseFromString(root, 'text/xml');
}
root = doc.getElementsByTagName('root')[0];
if (!root) return null;
for (var i = 0, k = root.childNodes.length; i < k; i++){
var child = Element.clone(root.childNodes[i], true, true);
if (child) container.grab(child);
}
return container;
}) || container.set('html', text);
},
success: function(text){
var options = this.options, response = this.response;
response.html = text.stripScripts(function(script){
response.javascript = script;
});
var temp = this.processHTML(response.html);
response.tree = temp.childNodes;
response.elements = temp.getElements('*');
if (options.filter) response.tree = response.elements.filter(options.filter);
if (options.update) document.id(options.update).empty().set('html', response.html);
else if (options.append) document.id(options.append).adopt(temp.getChildren());
if (options.evalScripts) $exec(response.javascript);
this.onSuccess(response.tree, response.elements, response.html, response.javascript);
}
});
Element.Properties.load = {
set: function(options){
var load = this.retrieve('load');
if (load) load.cancel();
return this.eliminate('load').store('load:options', $extend({data: this, link: 'cancel', update: this, method: 'get'}, options));
},
get: function(options){
if (options || ! this.retrieve('load')){
if (options || !this.retrieve('load:options')) this.set('load', options);
this.store('load', new Request.HTML(this.retrieve('load:options')));
}
return this.retrieve('load');
}
};
Element.implement({
load: function(){
this.get('load').send(Array.link(arguments, {data: Object.type, url: String.type}));
return this;
}
});
/*
Script: Request.JSON.js
Extends the basic Request Class with additional methods for sending and receiving JSON data.
License:
MIT-style license.
*/
Request.JSON = new Class({
Extends: Request,
options: {
secure: true
},
initialize: function(options){
this.parent(options);
this.headers.extend({'Accept': 'application/json', 'X-Request': 'JSON'});
},
success: function(text){
this.response.json = JSON.decode(text, this.options.secure);
this.onSuccess(this.response.json, text);
}
});
//MooTools More, <http://mootools.net/more>. Copyright (c) 2006-2009 Aaron Newton <http://clientcide.com/>, Valerio Proietti <http://mad4milk.net> & the MooTools team <http://mootools.net/developers>, MIT Style License.
MooTools.More = {
'version': '1.2.3.1'
};
/*
Script: MooTools.Lang.js
Provides methods for localization.
License:
MIT-style license.
Authors:
Aaron Newton
*/
(function(){
var data = {
language: 'en-US',
languages: {
'en-US': {}
},
cascades: ['en-US']
};
var cascaded;
MooTools.lang = new Events();
$extend(MooTools.lang, {
setLanguage: function(lang){
if (!data.languages[lang]) return this;
data.language = lang;
this.load();
this.fireEvent('langChange', lang);
return this;
},
load: function() {
var langs = this.cascade(this.getCurrentLanguage());
cascaded = {};
$each(langs, function(set, setName){
cascaded[setName] = this.lambda(set);
}, this);
},
getCurrentLanguage: function(){
return data.language;
},
addLanguage: function(lang){
data.languages[lang] = data.languages[lang] || {};
return this;
},
cascade: function(lang){
var cascades = (data.languages[lang] || {}).cascades || [];
cascades.combine(data.cascades);
cascades.erase(lang).push(lang);
var langs = cascades.map(function(lng){
return data.languages[lng];
}, this);
return $merge.apply(this, langs);
},
lambda: function(set) {
(set || {}).get = function(key, args){
return $lambda(set[key]).apply(this, $splat(args));
};
return set;
},
get: function(set, key, args){
if (cascaded && cascaded[set]) return (key ? cascaded[set].get(key, args) : cascaded[set]);
},
set: function(lang, set, members){
this.addLanguage(lang);
langData = data.languages[lang];
if (!langData[set]) langData[set] = {};
$extend(langData[set], members);
if (lang == this.getCurrentLanguage()){
this.load();
this.fireEvent('langChange', lang);
}
return this;
},
list: function(){
return Hash.getKeys(data.languages);
}
});
})();
/*
Script: Class.Refactor.js
Extends a class onto itself with new property, preserving any items attached to the class's namespace.
License:
MIT-style license.
Authors:
Aaron Newton
*/
Class.refactor = function(original, refactors){
$each(refactors, function(item, name){
var origin = original.prototype[name];
if (origin && (origin = origin._origin) && typeof item == 'function') original.implement(name, function(){
var old = this.previous;
this.previous = origin;
var value = item.apply(this, arguments);
this.previous = old;
return value;
}); else original.implement(name, item);
});
return original;
};
/*
Script: Class.Binds.js
Automagically binds specified methods in a class to the instance of the class.
License:
MIT-style license.
Authors:
Aaron Newton
*/
Class.Mutators.Binds = function(binds){
return binds;
};
Class.Mutators.initialize = function(initialize){
return function(){
$splat(this.Binds).each(function(name){
var original = this[name];
if (original) this[name] = original.bind(this);
}, this);
return initialize.apply(this, arguments);
};
};
/*
Script: Class.Occlude.js
Prevents a class from being applied to a DOM element twice.
License:
MIT-style license.
Authors:
Aaron Newton
*/
Class.Occlude = new Class({
occlude: function(property, element){
element = document.id(element || this.element);
var instance = element.retrieve(property || this.property);
if (instance && !$defined(this.occluded)){
this.occluded = instance;
} else {
this.occluded = false;
element.store(property || this.property, this);
}
return this.occluded;
}
});
/*
Script: Chain.Wait.js
Adds a method to inject pauses between chained events.
License:
MIT-style license.
Authors:
Aaron Newton
*/
(function(){
var wait = {
wait: function(duration){
return this.chain(function(){
this.callChain.delay($pick(duration, 500), this);
}.bind(this));
}
};
Chain.implement(wait);
if (window.Fx){
Fx.implement(wait);
['Css', 'Tween', 'Elements'].each(function(cls){
if (Fx[cls]) Fx[cls].implement(wait);
});
}
try {
Element.implement({
chains: function(effects){
$splat($pick(effects, ['tween', 'morph', 'reveal'])).each(function(effect){
effect = this.get(effect);
if (!effect) return;
effect.setOptions({
link:'chain'
});
}, this);
return this;
},
pauseFx: function(duration, effect){
this.chains(effect).get($pick(effect, 'tween')).wait(duration);
return this;
}
});
} catch(e){}
})();
/*
Script: Array.Extras.js
Extends the Array native object to include useful methods to work with arrays.
License:
MIT-style license.
Authors:
Christoph Pojer
*/
Array.implement({
min: function(){
return Math.min.apply(null, this);
},
max: function(){
return Math.max.apply(null, this);
},
average: function(){
return this.length ? this.sum() / this.length : 0;
},
sum: function(){
var result = 0, l = this.length;
if (l){
do {
result += this[--l];
} while (l);
}
return result;
},
unique: function(){
return [].combine(this);
}
});
/*
Script: Date.js
Extends the Date native object to include methods useful in managing dates.
License:
MIT-style license.
Authors:
Aaron Newton
Nicholas Barthelemy - https://svn.nbarthelemy.com/date-js/
Harald Kirshner - mail [at] digitarald.de; http://digitarald.de
Scott Kyle - scott [at] appden.com; http://appden.com
*/
(function(){
if (!Date.now) Date.now = $time;
Date.Methods = {};
['Date', 'Day', 'FullYear', 'Hours', 'Milliseconds', 'Minutes', 'Month', 'Seconds', 'Time', 'TimezoneOffset',
'Week', 'Timezone', 'GMTOffset', 'DayOfYear', 'LastMonth', 'LastDayOfMonth', 'UTCDate', 'UTCDay', 'UTCFullYear',
'AMPM', 'Ordinal', 'UTCHours', 'UTCMilliseconds', 'UTCMinutes', 'UTCMonth', 'UTCSeconds'].each(function(method){
Date.Methods[method.toLowerCase()] = method;
});
$each({
ms: 'Milliseconds',
year: 'FullYear',
min: 'Minutes',
mo: 'Month',
sec: 'Seconds',
hr: 'Hours'
}, function(value, key){
Date.Methods[key] = value;
});
var zeroize = function(what, length){
return new Array(length - what.toString().length + 1).join('0') + what;
};
Date.implement({
set: function(prop, value){
switch ($type(prop)){
case 'object':
for (var p in prop) this.set(p, prop[p]);
break;
case 'string':
prop = prop.toLowerCase();
var m = Date.Methods;
if (m[prop]) this['set' + m[prop]](value);
}
return this;
},
get: function(prop){
prop = prop.toLowerCase();
var m = Date.Methods;
if (m[prop]) return this['get' + m[prop]]();
return null;
},
clone: function(){
return new Date(this.get('time'));
},
increment: function(interval, times){
interval = interval || 'day';
times = $pick(times, 1);
switch (interval){
case 'year':
return this.increment('month', times * 12);
case 'month':
var d = this.get('date');
this.set('date', 1).set('mo', this.get('mo') + times);
return this.set('date', d.min(this.get('lastdayofmonth')));
case 'week':
return this.increment('day', times * 7);
case 'day':
return this.set('date', this.get('date') + times);
}
if (!Date.units[interval]) throw new Error(interval + ' is not a supported interval');
return this.set('time', this.get('time') + times * Date.units[interval]());
},
decrement: function(interval, times){
return this.increment(interval, -1 * $pick(times, 1));
},
isLeapYear: function(){
return Date.isLeapYear(this.get('year'));
},
clearTime: function(){
return this.set({hr: 0, min: 0, sec: 0, ms: 0});
},
diff: function(d, resolution){
resolution = resolution || 'day';
if ($type(d) == 'string') d = Date.parse(d);
switch (resolution){
case 'year':
return d.get('year') - this.get('year');
case 'month':
var months = (d.get('year') - this.get('year')) * 12;
return months + d.get('mo') - this.get('mo');
default:
var diff = d.get('time') - this.get('time');
if (Date.units[resolution]() > diff.abs()) return 0;
return ((d.get('time') - this.get('time')) / Date.units[resolution]()).round();
}
return null;
},
getLastDayOfMonth: function(){
return Date.daysInMonth(this.get('mo'), this.get('year'));
},
getDayOfYear: function(){
return (Date.UTC(this.get('year'), this.get('mo'), this.get('date') + 1) 
- Date.UTC(this.get('year'), 0, 1)) / Date.units.day();
},
getWeek: function(){
return (this.get('dayofyear') / 7).ceil();
},
getOrdinal: function(day){
return Date.getMsg('ordinal', day || this.get('date'));
},
getTimezone: function(){
return this.toString()
.replace(/^.*? ([A-Z]{3}).[0-9]{4}.*$/, '$1')
.replace(/^.*?\(([A-Z])[a-z]+ ([A-Z])[a-z]+ ([A-Z])[a-z]+\)$/, '$1$2$3');
},
getGMTOffset: function(){
var off = this.get('timezoneOffset');
return ((off > 0) ? '-' : '+') + zeroize((off.abs() / 60).floor(), 2) + zeroize(off % 60, 2);
},
setAMPM: function(ampm){
ampm = ampm.toUpperCase();
var hr = this.get('hr');
if (hr > 11 && ampm == 'AM') return this.decrement('hour', 12);
else if (hr < 12 && ampm == 'PM') return this.increment('hour', 12);
return this;
},
getAMPM: function(){
return (this.get('hr') < 12) ? 'AM' : 'PM';
},
parse: function(str){
this.set('time', Date.parse(str));
return this;
},
isValid: function(date) {
return !!(date || this).valueOf();
},
format: function(f){
if (!this.isValid()) return 'invalid date';
f = f || '%x %X';
f = formats[f.toLowerCase()] || f; // replace short-hand with actual format
var d = this;
return f.replace(/%([a-z%])/gi,
function($1, $2){
switch ($2){
case 'a': return Date.getMsg('days')[d.get('day')].substr(0, 3);
case 'A': return Date.getMsg('days')[d.get('day')];
case 'b': return Date.getMsg('months')[d.get('month')].substr(0, 3);
case 'B': return Date.getMsg('months')[d.get('month')];
case 'c': return d.toString();
case 'd': return zeroize(d.get('date'), 2);
case 'H': return zeroize(d.get('hr'), 2);
case 'I': return ((d.get('hr') % 12) || 12);
case 'j': return zeroize(d.get('dayofyear'), 3);
case 'm': return zeroize((d.get('mo') + 1), 2);
case 'M': return zeroize(d.get('min'), 2);
case 'o': return d.get('ordinal');
case 'p': return Date.getMsg(d.get('ampm'));
case 'S': return zeroize(d.get('seconds'), 2);
case 'U': return zeroize(d.get('week'), 2);
case 'w': return d.get('day');
case 'x': return d.format(Date.getMsg('shortDate'));
case 'X': return d.format(Date.getMsg('shortTime'));
case 'y': return d.get('year').toString().substr(2);
case 'Y': return d.get('year');
case 'T': return d.get('GMTOffset');
case 'Z': return d.get('Timezone');
}
return $2;
}
);
},
toISOString: function(){
return this.format('iso8601');
}
});
Date.alias('diff', 'compare');
Date.alias('format', 'strftime');
var formats = {
db: '%Y-%m-%d %H:%M:%S',
compact: '%Y%m%dT%H%M%S',
iso8601: '%Y-%m-%dT%H:%M:%S%T',
rfc822: '%a, %d %b %Y %H:%M:%S %Z',
'short': '%d %b %H:%M',
'long': '%B %d, %Y %H:%M'
};
var nativeParse = Date.parse;
var parseWord = function(type, word, num){
var ret = -1;
var translated = Date.getMsg(type + 's');
switch ($type(word)){
case 'object':
ret = translated[word.get(type)];
break;
case 'number':
ret = translated[month - 1];
if (!ret) throw new Error('Invalid ' + type + ' index: ' + index);
break;
case 'string':
var match = translated.filter(function(name){
return this.test(name);
}, new RegExp('^' + word, 'i'));
if (!match.length) throw new Error('Invalid ' + type + ' string');
if (match.length > 1) throw new Error('Ambiguous ' + type);
ret = match[0];
}
return (num) ? translated.indexOf(ret) : ret;
};
Date.extend({
getMsg: function(key, args) {
return MooTools.lang.get('Date', key, args);
},
units: {
ms: $lambda(1),
second: $lambda(1000),
minute: $lambda(60000),
hour: $lambda(3600000),
day: $lambda(86400000),
week: $lambda(608400000),
month: function(month, year){
var d = new Date;
return Date.daysInMonth($pick(month, d.get('mo')), $pick(year, d.get('year'))) * 86400000;
},
year: function(year){
year = year || new Date().get('year');
return Date.isLeapYear(year) ? 31622400000 : 31536000000;
}
},
daysInMonth: function(month, year){
return [31, Date.isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
},
isLeapYear: function(year){
return new Date(year, 1, 29).get('date') == 29;
},
parse: function(from){
var t = $type(from);
if (t == 'number') return new Date(from);
if (t != 'string') return from;
from = from.clean();
if (!from.length) return null;
var parsed;
Date.parsePatterns.some(function(pattern){
var r = pattern.re.exec(from);
return (r) ? (parsed = pattern.handler(r)) : false;
});
return parsed || new Date(nativeParse(from));
},
parseDay: function(day, num){
return parseWord('day', day, num);
},
parseMonth: function(month, num){
return parseWord('month', month, num);
},
parseUTC: function(value){
var localDate = new Date(value);
var utcSeconds = Date.UTC(localDate.get('year'), 
localDate.get('mo'),
localDate.get('date'), 
localDate.get('hr'), 
localDate.get('min'), 
localDate.get('sec'));
return new Date(utcSeconds);
},
orderIndex: function(unit){
return Date.getMsg('dateOrder').indexOf(unit) + 1;
},
defineFormat: function(name, format){
formats[name] = format;
},
defineFormats: function(formats){
for (var name in formats) Date.defineFormat(name, formats[f]);
},
parsePatterns: [],
defineParser: function(pattern){
Date.parsePatterns.push( pattern.re && pattern.handler ? pattern : build(pattern) );
},
defineParsers: function(){
Array.flatten(arguments).each(Date.defineParser);
},
define2DigitYearStart: function(year){
yr_start = year % 100;
yr_base = year - yr_start;
}
});
var yr_base = 1900;
var yr_start = 70;
var replacers = function(key){
switch(key){
case 'x': // iso8601 covers yyyy-mm-dd, so just check if month is first
return (Date.orderIndex('month') == 1) ? '%m[.-/]%d([.-/]%y)?' : '%d[.-/]%m([.-/]%y)?';
case 'X':
return '%H([.:]%M)?([.:]%S([.:]%s)?)?\\s?%p?\\s?%T?';
case 'o':
return '[^\\d\\s]*';
}
return null;
};
var keys = {
a: /[a-z]{3,}/,
d: /[0-2]?[0-9]|3[01]/,
H: /[01]?[0-9]|2[0-3]/,
I: /0?[1-9]|1[0-2]/,
M: /[0-5]?\d/,
s: /\d+/,
p: /[ap]\.?m\.?/,
y: /\d{2}|\d{4}/,
Y: /\d{4}/,
T: /Z|[+-]\d{2}(?::?\d{2})?/
};
keys.B = keys.b = keys.A = keys.a;
keys.m = keys.I;
keys.S = keys.M;
var lang;
var build = function(format){
if (!lang) return {format: format}; // wait until language is set
var parsed = [null];
var re = (format.source || format) // allow format to be regex
.replace(/%([a-z])/gi,
function($1, $2){
return replacers($2) || $1;
}
).replace(/\((?!\?)/g, '(?:') // make all groups non-capturing
.replace(/ (?!\?|\*)/g, ',? ') // be forgiving with spaces and commas
.replace(/%([a-z%])/gi,
function($1, $2){
var p = keys[$2];
if (!p) return $2;
parsed.push($2);
return '(' + p.source + ')';
}
);
return {
format: format,
re: new RegExp('^' + re + '$', 'i'),
handler: function(bits){
var date = new Date().clearTime();
for (var i = 1; i < parsed.length; i++)
date = handle.call(date, parsed[i], bits[i]);
return date;
}
};
};
var handle = function(key, value){
if (!value){
if (key == 'm' || key == 'd') value = 1;
else return this;
}
switch(key){
case 'a': case 'A': return this.set('day', Date.parseDay(value, true));
case 'b': case 'B': return this.set('mo', Date.parseMonth(value, true));
case 'd': return this.set('date', value);
case 'H': case 'I': return this.set('hr', value);
case 'm': return this.set('mo', value - 1);
case 'M': return this.set('min', value);
case 'p': return this.set('ampm', value.replace(/\./g, ''));
case 'S': return this.set('sec', value);
case 's': return this.set('ms', ('0.' + value) * 1000);
case 'w': return this.set('day', value);
case 'Y': return this.set('year', value);
case 'y':
value = +value;
if (value < 100) value += yr_base + (value < yr_start ? 100 : 0);
return this.set('year', value);
case 'T':
if (value == 'Z') value = '+00';
var offset = value.match(/([+-])(\d{2}):?(\d{2})?/);
offset = (offset[1] + '1') * (offset[2] * 60 + (+offset[3] || 0)) + this.getTimezoneOffset();
return this.set('time', (this * 1) - offset * 60000);
}
return this;
};
Date.defineParsers(
'%Y([-./]%m([-./]%d((T| )%X)?)?)?', // "1999-12-31", "1999-12-31 11:59pm", "1999-12-31 23:59:59", ISO8601
'%Y%m%d(T%H(%M%S?)?)?', // "19991231", "19991231T1159", compact
'%x( %X)?', // "12/31", "12.31.99", "12-31-1999", "12/31/2008 11:59 PM"
'%d%o( %b( %Y)?)?( %X)?', // "31st", "31st December", "31 Dec 1999", "31 Dec 1999 11:59pm"
'%b %d%o?( %Y)?( %X)?', // Same as above with month and day switched
'%b %Y' // "December 1999"
);
MooTools.lang.addEvent('langChange', function(language){
if (!MooTools.lang.get('Date')) return;
lang = language;
Date.parsePatterns.each(function(pattern, i){
if (pattern.format) Date.parsePatterns[i] = build(pattern.format);
});
}).fireEvent('langChange', MooTools.lang.getCurrentLanguage());
})();
/*
Script: Date.Extras.js
Extends the Date native object to include extra methods (on top of those in Date.js).
License:
MIT-style license.
Authors:
Aaron Newton
*/
Date.implement({
timeDiffInWords: function(relative_to){
return Date.distanceOfTimeInWords(this, relative_to || new Date);
}
});
Date.alias('timeDiffInWords', 'timeAgoInWords');
Date.extend({
distanceOfTimeInWords: function(from, to){
return Date.getTimePhrase(((to - from) / 1000).toInt());
},
getTimePhrase: function(delta){
var suffix = (delta < 0) ? 'Until' : 'Ago';
if (delta < 0) delta *= -1;
var msg = (delta < 60) ? 'lessThanMinute' :
(delta < 120) ? 'minute' :
(delta < (45 * 60)) ? 'minutes' :
(delta < (90 * 60)) ? 'hour' :
(delta < (24 * 60 * 60)) ? 'hours' :
(delta < (48 * 60 * 60)) ? 'day' :
'days';
switch(msg){
case 'minutes': delta = (delta / 60).round(); break;
case 'hours': delta = (delta / 3600).round(); break;
case 'days': delta = (delta / 86400).round();
}
return Date.getMsg(msg + suffix, delta).substitute({delta: delta});
}
});
Date.defineParsers(
{
// "today", "tomorrow", "yesterday"
re: /^tod|tom|yes/i,
handler: function(bits){
var d = new Date().clearTime();
switch(bits[0]){
case 'tom': return d.increment();
case 'yes': return d.decrement();
default: return d;
}
}
},
{
// "next Wednesday", "last Thursday"
re: /^(next|last) ([a-z]+)$/i,
handler: function(bits){
var d = new Date().clearTime();
var day = d.getDay();
var newDay = Date.parseDay(bits[2], true);
var addDays = newDay - day;
if (newDay <= day) addDays += 7;
if (bits[1] == 'last') addDays -= 7;
return d.set('date', d.getDate() + addDays);
}
}
);
/*
Script: Hash.Extras.js
Extends the Hash native object to include getFromPath which allows a path notation to child elements.
License:
MIT-style license.
Authors:
Aaron Newton
*/
Hash.implement({
getFromPath: function(notation){
var source = this.getClean();
notation.replace(/\[([^\]]+)\]|\.([^.[]+)|[^[.]+/g, function(match){
if (!source) return null;
var prop = arguments[2] || arguments[1] || arguments[0];
source = (prop in source) ? source[prop] : null;
return match;
});
return source;
},
cleanValues: function(method){
method = method || $defined;
this.each(function(v, k){
if (!method(v)) this.erase(k);
}, this);
return this;
},
run: function(){
var args = arguments;
this.each(function(v, k){
if ($type(v) == 'function') v.run(args);
});
}
});
/*
Script: String.Extras.js
Extends the String native object to include methods useful in managing various kinds of strings (query strings, urls, html, etc).
License:
MIT-style license.
Authors:
Aaron Newton
Guillermo Rauch
*/
(function(){
var special = ['À','à','Á','á','Â','â','Ã','ã','Ä','ä','Å','å','?','?','?','?','?','?','?','?','Ç','ç', '?','?','?','?', 'È','è','É','é','Ê','ê','Ë','ë','?','?','?','?', '?','?','Ì','ì','Í','í','Î','î','Ï','ï', '?','?','?','?','?','?', 'Ñ','ñ','?','?','?','?','Ò','ò','Ó','ó','Ô','ô','Õ','õ','Ö','ö','Ø','ø','?','?','?','?','?','Š','š','?','?','?','?', '?','?','?','?','?','?','Ù','ù','Ú','ú','Û','û','Ü','ü','?','?', 'Ÿ','ÿ','ý','Ý','Ž','ž','?','?','?','?', 'Þ','þ','Ð','ð','ß','Œ','œ','Æ','æ','µ'];
var standard = ['A','a','A','a','A','a','A','a','Ae','ae','A','a','A','a','A','a','C','c','C','c','C','c','D','d','D','d', 'E','e','E','e','E','e','E','e','E','e','E','e','G','g','I','i','I','i','I','i','I','i','L','l','L','l','L','l', 'N','n','N','n','N','n', 'O','o','O','o','O','o','O','o','Oe','oe','O','o','o', 'R','r','R','r', 'S','s','S','s','S','s','T','t','T','t','T','t', 'U','u','U','u','U','u','Ue','ue','U','u','Y','y','Y','y','Z','z','Z','z','Z','z','TH','th','DH','dh','ss','OE','oe','AE','ae','u'];
var tidymap = {
"[\xa0\u2002\u2003\u2009]": " ",
"\xb7": "*",
"[\u2018\u2019]": "'",
"[\u201c\u201d]": '"',
"\u2026": "...",
"\u2013": "-",
"\u2014": "--",
"\uFFFD": "&raquo;"
};
String.implement({
standardize: function(){
var text = this;
special.each(function(ch, i){
text = text.replace(new RegExp(ch, 'g'), standard[i]);
});
return text;
},
repeat: function(times){
return new Array(times + 1).join(this);
},
pad: function(length, str, dir){
if (this.length >= length) return this;
str = str || ' ';
var pad = str.repeat(length - this.length).substr(0, length - this.length);
if (!dir || dir == 'right') return this + pad;
if (dir == 'left') return pad + this;
return pad.substr(0, (pad.length / 2).floor()) + this + pad.substr(0, (pad.length / 2).ceil());
},
stripTags: function(){
return this.replace(/<\/?[^>]+>/gi, '');
},
tidy: function(){
var txt = this.toString();
$each(tidymap, function(value, key){
txt = txt.replace(new RegExp(key, 'g'), value);
});
return txt;
}
});
})();
/*
Script: String.QueryString.js
...
License:
MIT-style license.
Authors:
Sebastian Markbåge, Aaron Newton, Lennart Pilon, Valerio Proietti
*/
String.implement({
parseQueryString: function(){
var vars = this.split(/[&;]/), res = {};
if (vars.length) vars.each(function(val){
var index = val.indexOf('='),
keys = index < 0 ? [''] : val.substr(0, index).match(/[^\]\[]+/g),
value = decodeURIComponent(val.substr(index + 1)),
obj = res;
keys.each(function(key, i){
var current = obj[key];
if(i < keys.length - 1)
obj = obj[key] = current || {};
else if($type(current) == 'array')
current.push(value);
else
obj[key] = $defined(current) ? [current, value] : value;
});
});
return res;
},
cleanQueryString: function(method){
return this.split('&').filter(function(val){
var index = val.indexOf('='),
key = index < 0 ? '' : val.substr(0, index),
value = val.substr(index + 1);
return method ? method.run([key, value]) : $chk(value);
}).join('&');
}
});
/*
Script: URI.js
Provides methods useful in managing the window location and uris.
License:
MIT-style license.
Authors:
Sebastian Markbge, Aaron Newton
*/
var URI = new Class({
Implements: Options,
/*
options: {
base: false
},
*/
regex: /^(?:(\w+):)?(?:\/\/(?:(?:([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)?(\.\.?$|(?:[^?#\/]*\/)*)([^?#]*)(?:\?([^#]*))?(?:#(.*))?/,
parts: ['scheme', 'user', 'password', 'host', 'port', 'directory', 'file', 'query', 'fragment'],
schemes: { http: 80, https: 443, ftp: 21, rtsp: 554, mms: 1755, file: 0 },
initialize: function(uri, options){
this.setOptions(options);
var base = this.options.base || URI.base;
uri = uri || base;
if (uri && uri.parsed)
this.parsed = $unlink(uri.parsed);
else
this.set('value', uri.href || uri.toString(), base ? new URI(base) : false);
},
parse: function(value, base){
var bits = value.match(this.regex);
if (!bits) return false;
bits.shift();
return this.merge(bits.associate(this.parts), base);
},
merge: function(bits, base){
if ((!bits || !bits.scheme) && (!base || !base.scheme)) return false;
if (base){
this.parts.every(function(part){
if (bits[part]) return false;
bits[part] = base[part] || '';
return true;
});
}
bits.port = bits.port || this.schemes[bits.scheme.toLowerCase()];
bits.directory = bits.directory ? this.parseDirectory(bits.directory, base ? base.directory : '') : '/';
return bits;
},
parseDirectory: function(directory, baseDirectory) {
directory = (directory.substr(0, 1) == '/' ? '' : (baseDirectory || '/')) + directory;
if (!directory.test(URI.regs.directoryDot)) return directory;
var result = [];
directory.replace(URI.regs.endSlash, '').split('/').each(function(dir){
if (dir == '..' && result.length > 0) result.pop();
else if (dir != '.') result.push(dir);
});
return result.join('/') + '/';
},
combine: function(bits){
return bits.value || bits.scheme + '://' +
(bits.user ? bits.user + (bits.password ? ':' + bits.password : '') + '@' : '') +
(bits.host || '') + (bits.port && bits.port != this.schemes[bits.scheme] ? ':' + bits.port : '') +
(bits.directory || '/') + (bits.file || '') +
(bits.query ? '?' + bits.query : '') +
(bits.fragment ? '#' + bits.fragment : '');
},
set: function(part, value, base){
if (part == 'value'){
var scheme = value.match(URI.regs.scheme);
if (scheme) scheme = scheme[1];
if (scheme && !$defined(this.schemes[scheme.toLowerCase()])) this.parsed = { scheme: scheme, value: value };
else this.parsed = this.parse(value, (base || this).parsed) || (scheme ? { scheme: scheme, value: value } : { value: value });
} else if (part == 'data') {
this.setData(value);
} else {
this.parsed[part] = value;
}
return this;
},
get: function(part, base){
switch(part){
case 'value': return this.combine(this.parsed, base ? base.parsed : false);
case 'data' : return this.getData();
}
return this.parsed[part] || undefined;
},
go: function(){
document.location.href = this.toString();
},
toURI: function(){
return this;
},
getData: function(key, part){
var qs = this.get(part || 'query');
if (!$chk(qs)) return key ? null : {};
var obj = qs.parseQueryString();
return key ? obj[key] : obj;
},
setData: function(values, merge, part){
if ($type(arguments[0]) == 'string'){ 
values = this.getData(); 
values[arguments[0]] = arguments[1]; 
} else if (merge) {
values = $merge(this.getData(), values);
}
return this.set(part || 'query', Hash.toQueryString(values));
},
clearData: function(part){
return this.set(part || 'query', '');
}
});
['toString', 'valueOf'].each(function(method){
URI.prototype[method] = function(){
return this.get('value');
};
});
URI.regs = {
endSlash: /\/$/,
scheme: /^(\w+):/,
directoryDot: /\.\/|\.$/
};
URI.base = new URI($$('base[href]').getLast(), { base: document.location });
String.implement({
toURI: function(options){ return new URI(this, options); }
});
/*
Script: URI.Relative.js
Extends the URI class to add methods for computing relative and absolute urls.
License:
MIT-style license.
Authors:
Sebastian Markbåge
*/
URI = Class.refactor(URI, {
combine: function(bits, base){
if (!base || bits.scheme != base.scheme || bits.host != base.host || bits.port != base.port)
return this.previous.apply(this, arguments);
var end = bits.file + (bits.query ? '?' + bits.query : '') + (bits.fragment ? '#' + bits.fragment : '');
if (!base.directory) return (bits.directory || (bits.file ? '' : './')) + end;
var baseDir = base.directory.split('/'),
relDir = bits.directory.split('/'),
path = '',
offset;
var i = 0;
for(offset = 0; offset < baseDir.length && offset < relDir.length && baseDir[offset] == relDir[offset]; offset++);
for(i = 0; i < baseDir.length - offset - 1; i++) path += '../';
for(i = offset; i < relDir.length - 1; i++) path += relDir[i] + '/';
return (path || (bits.file ? '' : './')) + end;
},
toAbsolute: function(base){
base = new URI(base);
if (base) base.set('directory', '').set('file', '');
return this.toRelative(base);
},
toRelative: function(base){
return this.get('value', new URI(base));
}
});
/*
Script: Element.Forms.js
Extends the Element native object to include methods useful in managing inputs.
License:
MIT-style license.
Authors:
Aaron Newton
*/
Element.implement({
tidy: function(){
this.set('value', this.get('value').tidy());
},
getTextInRange: function(start, end){
return this.get('value').substring(start, end);
},
getSelectedText: function(){
if (this.setSelectionRange) return this.getTextInRange(this.getSelectionStart(), this.getSelectionEnd());
return document.selection.createRange().text;
},
getSelectedRange: function() {
if ($defined(this.selectionStart)) return {start: this.selectionStart, end: this.selectionEnd};
var pos = {start: 0, end: 0};
var range = this.getDocument().selection.createRange();
if (!range || range.parentElement() != this) return pos;
var dup = range.duplicate();
if (this.type == 'text') {
pos.start = 0 - dup.moveStart('character', -100000);
pos.end = pos.start + range.text.length;
} else {
var value = this.get('value');
var offset = value.length - value.match(/[\n\r]*$/)[0].length;
dup.moveToElementText(this);
dup.setEndPoint('StartToEnd', range);
pos.end = offset - dup.text.length;
dup.setEndPoint('StartToStart', range);
pos.start = offset - dup.text.length;
}
return pos;
},
getSelectionStart: function(){
return this.getSelectedRange().start;
},
getSelectionEnd: function(){
return this.getSelectedRange().end;
},
setCaretPosition: function(pos){
if (pos == 'end') pos = this.get('value').length;
this.selectRange(pos, pos);
return this;
},
getCaretPosition: function(){
return this.getSelectedRange().start;
},
selectRange: function(start, end){
if (this.setSelectionRange) {
this.focus();
this.setSelectionRange(start, end);
} else {
var value = this.get('value');
var diff = value.substr(start, end - start).replace(/\r/g, '').length;
start = value.substr(0, start).replace(/\r/g, '').length;
var range = this.createTextRange();
range.collapse(true);
range.moveEnd('character', start + diff);
range.moveStart('character', start);
range.select();
}
return this;
},
insertAtCursor: function(value, select){
var pos = this.getSelectedRange();
var text = this.get('value');
this.set('value', text.substring(0, pos.start) + value + text.substring(pos.end, text.length));
if ($pick(select, true)) this.selectRange(pos.start, pos.start + value.length);
else this.setCaretPosition(pos.start + value.length);
return this;
},
insertAroundCursor: function(options, select){
options = $extend({
before: '',
defaultMiddle: '',
after: ''
}, options);
var value = this.getSelectedText() || options.defaultMiddle;
var pos = this.getSelectedRange();
var text = this.get('value');
if (pos.start == pos.end){
this.set('value', text.substring(0, pos.start) + options.before + value + options.after + text.substring(pos.end, text.length));
this.selectRange(pos.start + options.before.length, pos.end + options.before.length + value.length);
} else {
var current = text.substring(pos.start, pos.end);
this.set('value', text.substring(0, pos.start) + options.before + current + options.after + text.substring(pos.end, text.length));
var selStart = pos.start + options.before.length;
if ($pick(select, true)) this.selectRange(selStart, selStart + current.length);
else this.setCaretPosition(selStart + text.length);
}
return this;
}
});
/*
Script: Element.Measure.js
Extends the Element native object to include methods useful in measuring dimensions.
Element.measure / .expose methods by Daniel Steigerwald
License: MIT-style license.
Copyright: Copyright (c) 2008 Daniel Steigerwald, daniel.steigerwald.cz
License:
MIT-style license.
Authors:
Aaron Newton
*/
Element.implement({
measure: function(fn){
var vis = function(el) {
return !!(!el || el.offsetHeight || el.offsetWidth);
};
if (vis(this)) return fn.apply(this);
var parent = this.getParent(),
toMeasure = [], 
restorers = [];
while (!vis(parent) && parent != document.body) {
toMeasure.push(parent.expose());
parent = parent.getParent();
}
var restore = this.expose();
var result = fn.apply(this);
restore();
toMeasure.each(function(restore){
restore();
});
return result;
},
expose: function(){
if (this.getStyle('display') != 'none') return $empty;
var before = this.style.cssText;
this.setStyles({
display: 'block',
position: 'absolute',
visibility: 'hidden'
});
return function(){
this.style.cssText = before;
}.bind(this);
},
getDimensions: function(options){
options = $merge({computeSize: false},options);
var dim = {};
var getSize = function(el, options){
return (options.computeSize)?el.getComputedSize(options):el.getSize();
};
if (this.getStyle('display') == 'none'){
dim = this.measure(function(){
return getSize(this, options);
});
} else {
try { //safari sometimes crashes here, so catch it
dim = getSize(this, options);
}catch(e){}
}
return $chk(dim.x) ? $extend(dim, {width: dim.x, height: dim.y}) : $extend(dim, {x: dim.width, y: dim.height});
},
getComputedSize: function(options){
options = $merge({
styles: ['padding','border'],
plains: {
height: ['top','bottom'],
width: ['left','right']
},
mode: 'both'
}, options);
var size = {width: 0,height: 0};
switch (options.mode){
case 'vertical':
delete size.width;
delete options.plains.width;
break;
case 'horizontal':
delete size.height;
delete options.plains.height;
break;
}
var getStyles = [];
//this function might be useful in other places; perhaps it should be outside this function?
$each(options.plains, function(plain, key){
plain.each(function(edge){
options.styles.each(function(style){
getStyles.push((style == 'border') ? style + '-' + edge + '-' + 'width' : style + '-' + edge);
});
});
});
var styles = {};
getStyles.each(function(style){ styles[style] = this.getComputedStyle(style); }, this);
var subtracted = [];
$each(options.plains, function(plain, key){ //keys: width, height, plains: ['left', 'right'], ['top','bottom']
var capitalized = key.capitalize();
size['total' + capitalized] = 0;
size['computed' + capitalized] = 0;
plain.each(function(edge){ //top, left, right, bottom
size['computed' + edge.capitalize()] = 0;
getStyles.each(function(style, i){ //padding, border, etc.
//'padding-left'.test('left') size['totalWidth'] = size['width'] + [padding-left]
if (style.test(edge)){
styles[style] = styles[style].toInt() || 0; //styles['padding-left'] = 5;
size['total' + capitalized] = size['total' + capitalized] + styles[style];
size['computed' + edge.capitalize()] = size['computed' + edge.capitalize()] + styles[style];
}
//if width != width (so, padding-left, for instance), then subtract that from the total
if (style.test(edge) && key != style &&
(style.test('border') || style.test('padding')) && !subtracted.contains(style)){
subtracted.push(style);
size['computed' + capitalized] = size['computed' + capitalized]-styles[style];
}
});
});
});
['Width', 'Height'].each(function(value){
var lower = value.toLowerCase();
if(!$chk(size[lower])) return;
size[lower] = size[lower] + this['offset' + value] + size['computed' + value];
size['total' + value] = size[lower] + size['total' + value];
delete size['computed' + value];
}, this);
return $extend(styles, size);
}
});
/*
Script: Element.Pin.js
Extends the Element native object to include the pin method useful for fixed positioning for elements.
License:
MIT-style license.
Authors:
Aaron Newton
*/
(function(){
var supportsPositionFixed = false;
window.addEvent('domready', function(){
var test = new Element('div').setStyles({
position: 'fixed',
top: 0,
right: 0
}).inject(document.body);
supportsPositionFixed = (test.offsetTop === 0);
test.dispose();
});
Element.implement({
pin: function(enable){
if (this.getStyle('display') == 'none') return null;
var p;
if (enable !== false){
p = this.getPosition();
if (!this.retrieve('pinned')){
var pos = {
top: p.y - window.getScroll().y,
left: p.x - window.getScroll().x
};
if (supportsPositionFixed){
this.setStyle('position', 'fixed').setStyles(pos);
} else {
this.store('pinnedByJS', true);
this.setStyles({
position: 'absolute',
top: p.y,
left: p.x
});
this.store('scrollFixer', (function(){
if (this.retrieve('pinned'))
this.setStyles({
top: pos.top.toInt() + window.getScroll().y,
left: pos.left.toInt() + window.getScroll().x
});
}).bind(this));
window.addEvent('scroll', this.retrieve('scrollFixer'));
}
this.store('pinned', true);
}
} else {
var op;
if (!Browser.Engine.trident){
if (this.getParent().getComputedStyle('position') != 'static') op = this.getParent();
else op = this.getParent().getOffsetParent();
}
p = this.getPosition(op);
this.store('pinned', false);
var reposition;
if (supportsPositionFixed && !this.retrieve('pinnedByJS')){
reposition = {
top: p.y + window.getScroll().y,
left: p.x + window.getScroll().x
};
} else {
this.store('pinnedByJS', false);
window.removeEvent('scroll', this.retrieve('scrollFixer'));
reposition = {
top: p.y,
left: p.x
};
}
this.setStyles($merge(reposition, {position: 'absolute'}));
}
return this.addClass('isPinned');
},
unpin: function(){
return this.pin(false).removeClass('isPinned');
},
togglepin: function(){
this.pin(!this.retrieve('pinned'));
}
});
})();
/*
Script: Element.Position.js
Extends the Element native object to include methods useful positioning elements relative to others.
License:
MIT-style license.
Authors:
Aaron Newton
*/
(function(){
var original = Element.prototype.position;
Element.implement({
position: function(options){
//call original position if the options are x/y values
if (options && ($defined(options.x) || $defined(options.y))) return original ? original.apply(this, arguments) : this;
$each(options||{}, function(v, k){ if (!$defined(v)) delete options[k]; });
options = $merge({
relativeTo: document.body,
position: {
x: 'center', //left, center, right
y: 'center' //top, center, bottom
},
edge: false,
offset: {x: 0, y: 0},
returnPos: false,
relFixedPosition: false,
ignoreMargins: false,
allowNegative: false
}, options);
//compute the offset of the parent positioned element if this element is in one
var parentOffset = {x: 0, y: 0};
var parentPositioned = false;
/* dollar around getOffsetParent should not be necessary, but as it does not return
* a mootools extended element in IE, an error occurs on the call to expose. See:
* http://mootools.lighthouseapp.com/projects/2706/tickets/333-element-getoffsetparent-inconsistency-between-ie-and-other-browsers */
var offsetParent = this.measure(function(){
return document.id(this.getOffsetParent());
});
if (offsetParent && offsetParent != this.getDocument().body){
parentOffset = offsetParent.measure(function(){
return this.getPosition();
});
parentPositioned = true;
options.offset.x = options.offset.x - parentOffset.x;
options.offset.y = options.offset.y - parentOffset.y;
}
//upperRight, bottomRight, centerRight, upperLeft, bottomLeft, centerLeft
//topRight, topLeft, centerTop, centerBottom, center
var fixValue = function(option){
if ($type(option) != 'string') return option;
option = option.toLowerCase();
var val = {};
if (option.test('left')) val.x = 'left';
else if (option.test('right')) val.x = 'right';
else val.x = 'center';
if (option.test('upper') || option.test('top')) val.y = 'top';
else if (option.test('bottom')) val.y = 'bottom';
else val.y = 'center';
return val;
};
options.edge = fixValue(options.edge);
options.position = fixValue(options.position);
if (!options.edge){
if (options.position.x == 'center' && options.position.y == 'center') options.edge = {x:'center', y:'center'};
else options.edge = {x:'left', y:'top'};
}
this.setStyle('position', 'absolute');
var rel = document.id(options.relativeTo) || document.body;
var calc = rel == document.body ? window.getScroll() : rel.getPosition();
var top = calc.y;
var left = calc.x;
if (Browser.Engine.trident){
var scrolls = rel.getScrolls();
top += scrolls.y;
left += scrolls.x;
}
var dim = this.getDimensions({computeSize: true, styles:['padding', 'border','margin']});
if (options.ignoreMargins){
options.offset.x = options.offset.x - dim['margin-left'];
options.offset.y = options.offset.y - dim['margin-top'];
}
var pos = {};
var prefY = options.offset.y;
var prefX = options.offset.x;
var winSize = window.getSize();
switch(options.position.x){
case 'left':
pos.x = left + prefX;
break;
case 'right':
pos.x = left + prefX + rel.offsetWidth;
break;
default: //center
pos.x = left + ((rel == document.body ? winSize.x : rel.offsetWidth)/2) + prefX;
break;
}
switch(options.position.y){
case 'top':
pos.y = top + prefY;
break;
case 'bottom':
pos.y = top + prefY + rel.offsetHeight;
break;
default: //center
pos.y = top + ((rel == document.body ? winSize.y : rel.offsetHeight)/2) + prefY;
break;
}
if (options.edge){
var edgeOffset = {};
switch(options.edge.x){
case 'left':
edgeOffset.x = 0;
break;
case 'right':
edgeOffset.x = -dim.x-dim.computedRight-dim.computedLeft;
break;
default: //center
edgeOffset.x = -(dim.x/2);
break;
}
switch(options.edge.y){
case 'top':
edgeOffset.y = 0;
break;
case 'bottom':
edgeOffset.y = -dim.y-dim.computedTop-dim.computedBottom;
break;
default: //center
edgeOffset.y = -(dim.y/2);
break;
}
pos.x = pos.x + edgeOffset.x;
pos.y = pos.y + edgeOffset.y;
}
pos = {
left: ((pos.x >= 0 || parentPositioned || options.allowNegative) ? pos.x : 0).toInt(),
top: ((pos.y >= 0 || parentPositioned || options.allowNegative) ? pos.y : 0).toInt()
};
if (rel.getStyle('position') == 'fixed' || options.relFixedPosition){
var winScroll = window.getScroll();
pos.top = pos.top.toInt() + winScroll.y;
pos.left = pos.left.toInt() + winScroll.x;
}
if (options.returnPos) return pos;
else this.setStyles(pos);
return this;
}
});
})();
/*
Script: Element.Shortcuts.js
Extends the Element native object to include some shortcut methods.
License:
MIT-style license.
Authors:
Aaron Newton
*/
Element.implement({
isDisplayed: function(){
return this.getStyle('display') != 'none';
},
toggle: function(){
return this[this.isDisplayed() ? 'hide' : 'show']();
},
hide: function(){
var d;
try {
//IE fails here if the element is not in the dom
if ('none' != this.getStyle('display')) d = this.getStyle('display');
} catch(e){}
return this.store('originalDisplay', d || 'block').setStyle('display', 'none');
},
show: function(display){
return this.setStyle('display', display || this.retrieve('originalDisplay') || 'block');
},
swapClass: function(remove, add){
return this.removeClass(remove).addClass(add);
}
});
/*
Script: Fx.Elements.js
Effect to change any number of CSS properties of any number of Elements.
License:
MIT-style license.
Authors:
Valerio Proietti
*/
Fx.Elements = new Class({
Extends: Fx.CSS,
initialize: function(elements, options){
this.elements = this.subject = $$(elements);
this.parent(options);
},
compute: function(from, to, delta){
var now = {};
for (var i in from){
var iFrom = from[i], iTo = to[i], iNow = now[i] = {};
for (var p in iFrom) iNow[p] = this.parent(iFrom[p], iTo[p], delta);
}
return now;
},
set: function(now){
for (var i in now){
var iNow = now[i];
for (var p in iNow) this.render(this.elements[i], p, iNow[p], this.options.unit);
}
return this;
},
start: function(obj){
if (!this.check(obj)) return this;
var from = {}, to = {};
for (var i in obj){
var iProps = obj[i], iFrom = from[i] = {}, iTo = to[i] = {};
for (var p in iProps){
var parsed = this.prepare(this.elements[i], p, iProps[p]);
iFrom[p] = parsed.from;
iTo[p] = parsed.to;
}
}
return this.parent(from, to);
}
});
/*
Script: Fx.Accordion.js
An Fx.Elements extension which allows you to easily create accordion type controls.
License:
MIT-style license.
Authors:
Valerio Proietti
*/
var Accordion = Fx.Accordion = new Class({
Extends: Fx.Elements,
options: {/*
onActive: $empty(toggler, section),
onBackground: $empty(toggler, section),*/
display: 0,
show: false,
height: true,
width: false,
opacity: true,
fixedHeight: false,
fixedWidth: false,
wait: false,
alwaysHide: false,
trigger: 'click',
initialDisplayFx: true
},
initialize: function(){
var params = Array.link(arguments, {'container': Element.type, 'options': Object.type, 'togglers': $defined, 'elements': $defined});
this.parent(params.elements, params.options);
this.togglers = $$(params.togglers);
this.container = document.id(params.container);
this.previous = -1;
if (this.options.alwaysHide) this.options.wait = true;
if ($chk(this.options.show)){
this.options.display = false;
this.previous = this.options.show;
}
if (this.options.start){
this.options.display = false;
this.options.show = false;
}
this.effects = {};
if (this.options.opacity) this.effects.opacity = 'fullOpacity';
if (this.options.width) this.effects.width = this.options.fixedWidth ? 'fullWidth' : 'offsetWidth';
if (this.options.height) this.effects.height = this.options.fixedHeight ? 'fullHeight' : 'scrollHeight';
for (var i = 0, l = this.togglers.length; i < l; i++) this.addSection(this.togglers[i], this.elements[i]);
this.elements.each(function(el, i){
if (this.options.show === i){
this.fireEvent('active', [this.togglers[i], el]);
} else {
for (var fx in this.effects) el.setStyle(fx, 0);
}
}, this);
if ($chk(this.options.display)) this.display(this.options.display, this.options.initialDisplayFx);
},
addSection: function(toggler, element){
toggler = document.id(toggler);
element = document.id(element);
var test = this.togglers.contains(toggler);
this.togglers.include(toggler);
this.elements.include(element);
var idx = this.togglers.indexOf(toggler);
toggler.addEvent(this.options.trigger, this.display.bind(this, idx));
if (this.options.height) element.setStyles({'padding-top': 0, 'border-top': 'none', 'padding-bottom': 0, 'border-bottom': 'none'});
if (this.options.width) element.setStyles({'padding-left': 0, 'border-left': 'none', 'padding-right': 0, 'border-right': 'none'});
element.fullOpacity = 1;
if (this.options.fixedWidth) element.fullWidth = this.options.fixedWidth;
if (this.options.fixedHeight) element.fullHeight = this.options.fixedHeight;
element.setStyle('overflow', 'hidden');
if (!test){
for (var fx in this.effects) element.setStyle(fx, 0);
}
return this;
},
display: function(index, useFx){
useFx = $pick(useFx, true);
index = ($type(index) == 'element') ? this.elements.indexOf(index) : index;
if ((this.timer && this.options.wait) || (index === this.previous && !this.options.alwaysHide)) return this;
this.previous = index;
var obj = {};
this.elements.each(function(el, i){
obj[i] = {};
var hide = (i != index) || (this.options.alwaysHide && (el.offsetHeight > 0));
this.fireEvent(hide ? 'background' : 'active', [this.togglers[i], el]);
for (var fx in this.effects) obj[i][fx] = hide ? 0 : el[this.effects[fx]];
}, this);
return useFx ? this.start(obj) : this.set(obj);
}
});
/*
Script: Fx.Move.js
Defines Fx.Move, a class that works with Element.Position.js to transition an element from one location to another.
License:
MIT-style license.
Authors:
Aaron Newton
*/
Fx.Move = new Class({
Extends: Fx.Morph,
options: {
relativeTo: document.body,
position: 'center',
edge: false,
offset: {x: 0, y: 0}
},
start: function(destination){
return this.parent(this.element.position($merge(this.options, destination, {returnPos: true})));
}
});
Element.Properties.move = {
set: function(options){
var morph = this.retrieve('move');
if (morph) morph.cancel();
return this.eliminate('move').store('move:options', $extend({link: 'cancel'}, options));
},
get: function(options){
if (options || !this.retrieve('move')){
if (options || !this.retrieve('move:options')) this.set('move', options);
this.store('move', new Fx.Move(this, this.retrieve('move:options')));
}
return this.retrieve('move');
}
};
Element.implement({
move: function(options){
this.get('move').start(options);
return this;
}
});
/*
Script: Fx.Reveal.js
Defines Fx.Reveal, a class that shows and hides elements with a transition.
License:
MIT-style license.
Authors:
Aaron Newton
*/
Fx.Reveal = new Class({
Extends: Fx.Morph,
options: {/*	
onShow: $empty(thisElement),
onHide: $empty(thisElement),
onComplete: $empty(thisElement),
heightOverride: null,
widthOverride: null, */
styles: ['padding', 'border', 'margin'],
transitionOpacity: !Browser.Engine.trident4,
mode: 'vertical',
display: 'block',
hideInputs: Browser.Engine.trident ? 'select, input, textarea, object, embed' : false
},
dissolve: function(){
try {
if (!this.hiding && !this.showing){
if (this.element.getStyle('display') != 'none'){
this.hiding = true;
this.showing = false;
this.hidden = true;
var startStyles = this.element.getComputedSize({
styles: this.options.styles,
mode: this.options.mode
});
var setToAuto = (this.element.style.height === ''||this.element.style.height == 'auto');
this.element.setStyle('display', 'block');
if (this.options.transitionOpacity) startStyles.opacity = 1;
var zero = {};
$each(startStyles, function(style, name){
zero[name] = [style, 0];
}, this);
var overflowBefore = this.element.getStyle('overflow');
this.element.setStyle('overflow', 'hidden');
var hideThese = this.options.hideInputs ? this.element.getElements(this.options.hideInputs) : null;
this.$chain.unshift(function(){
if (this.hidden){
this.hiding = false;
$each(startStyles, function(style, name){
startStyles[name] = style;
}, this);
this.element.setStyles($merge({display: 'none', overflow: overflowBefore}, startStyles));
if (setToAuto){
if (['vertical', 'both'].contains(this.options.mode)) this.element.style.height = '';
if (['width', 'both'].contains(this.options.mode)) this.element.style.width = '';
}
if (hideThese) hideThese.setStyle('visibility', 'visible');
}
this.fireEvent('hide', this.element);
this.callChain();
}.bind(this));
if (hideThese) hideThese.setStyle('visibility', 'hidden');
this.start(zero);
} else {
this.callChain.delay(10, this);
this.fireEvent('complete', this.element);
this.fireEvent('hide', this.element);
}
} else if (this.options.link == 'chain'){
this.chain(this.dissolve.bind(this));
} else if (this.options.link == 'cancel' && !this.hiding){
this.cancel();
this.dissolve();
}
} catch(e){
this.hiding = false;
this.element.setStyle('display', 'none');
this.callChain.delay(10, this);
this.fireEvent('complete', this.element);
this.fireEvent('hide', this.element);
}
return this;
},
reveal: function(){
try {
if (!this.showing && !this.hiding){
if (this.element.getStyle('display') == 'none' ||
this.element.getStyle('visiblity') == 'hidden' ||
this.element.getStyle('opacity') == 0){
this.showing = true;
this.hiding = false;
this.hidden = false;
var setToAuto, startStyles;
//toggle display, but hide it
this.element.measure(function(){
setToAuto = (this.element.style.height === '' || this.element.style.height == 'auto');
//create the styles for the opened/visible state
startStyles = this.element.getComputedSize({
styles: this.options.styles,
mode: this.options.mode
});
}.bind(this));
$each(startStyles, function(style, name){
startStyles[name] = style;
});
//if we're overridding height/width
if ($chk(this.options.heightOverride)) startStyles.height = this.options.heightOverride.toInt();
if ($chk(this.options.widthOverride)) startStyles.width = this.options.widthOverride.toInt();
if (this.options.transitionOpacity) {
this.element.setStyle('opacity', 0);
startStyles.opacity = 1;
}
//create the zero state for the beginning of the transition
var zero = {
height: 0,
display: this.options.display
};
$each(startStyles, function(style, name){ zero[name] = 0; });
var overflowBefore = this.element.getStyle('overflow');
//set to zero
this.element.setStyles($merge(zero, {overflow: 'hidden'}));
//hide inputs
var hideThese = this.options.hideInputs ? this.element.getElements(this.options.hideInputs) : null;
if (hideThese) hideThese.setStyle('visibility', 'hidden');
//start the effect
this.start(startStyles);
this.$chain.unshift(function(){
this.element.setStyle('overflow', overflowBefore);
if (!this.options.heightOverride && setToAuto){
if (['vertical', 'both'].contains(this.options.mode)) this.element.style.height = '';
if (['width', 'both'].contains(this.options.mode)) this.element.style.width = '';
}
if (!this.hidden) this.showing = false;
if (hideThese) hideThese.setStyle('visibility', 'visible');
this.callChain();
this.fireEvent('show', this.element);
}.bind(this));
} else {
this.callChain();
this.fireEvent('complete', this.element);
this.fireEvent('show', this.element);
}
} else if (this.options.link == 'chain'){
this.chain(this.reveal.bind(this));
} else if (this.options.link == 'cancel' && !this.showing){
this.cancel();
this.reveal();
}
} catch(e){
this.element.setStyles({
display: this.options.display,
visiblity: 'visible',
opacity: 1
});
this.showing = false;
this.callChain.delay(10, this);
this.fireEvent('complete', this.element);
this.fireEvent('show', this.element);
}
return this;
},
toggle: function(){
if (this.element.getStyle('display') == 'none' ||
this.element.getStyle('visiblity') == 'hidden' ||
this.element.getStyle('opacity') == 0){
this.reveal();
} else {
this.dissolve();
}
return this;
}
});
Element.Properties.reveal = {
set: function(options){
var reveal = this.retrieve('reveal');
if (reveal) reveal.cancel();
return this.eliminate('reveal').store('reveal:options', $extend({link: 'cancel'}, options));
},
get: function(options){
if (options || !this.retrieve('reveal')){
if (options || !this.retrieve('reveal:options')) this.set('reveal', options);
this.store('reveal', new Fx.Reveal(this, this.retrieve('reveal:options')));
}
return this.retrieve('reveal');
}
};
Element.Properties.dissolve = Element.Properties.reveal;
Element.implement({
reveal: function(options){
this.get('reveal', options).reveal();
return this;
},
dissolve: function(options){
this.get('reveal', options).dissolve();
return this;
},
nix: function(){
var params = Array.link(arguments, {destroy: Boolean.type, options: Object.type});
this.get('reveal', params.options).dissolve().chain(function(){
this[params.destroy ? 'destroy' : 'dispose']();
}.bind(this));
return this;
},
wink: function(){
var params = Array.link(arguments, {duration: Number.type, options: Object.type});
var reveal = this.get('reveal', params.options);
reveal.reveal().chain(function(){
(function(){
reveal.dissolve();
}).delay(params.duration || 2000);
});
}
});
/*
Script: Fx.Scroll.js
Effect to smoothly scroll any element, including the window.
License:
MIT-style license.
Authors:
Valerio Proietti
*/
Fx.Scroll = new Class({
Extends: Fx,
options: {
offset: {x: 0, y: 0},
wheelStops: true
},
initialize: function(element, options){
this.element = this.subject = document.id(element);
this.parent(options);
var cancel = this.cancel.bind(this, false);
if ($type(this.element) != 'element') this.element = document.id(this.element.getDocument().body);
var stopper = this.element;
if (this.options.wheelStops){
this.addEvent('start', function(){
stopper.addEvent('mousewheel', cancel);
}, true);
this.addEvent('complete', function(){
stopper.removeEvent('mousewheel', cancel);
}, true);
}
},
set: function(){
var now = Array.flatten(arguments);
this.element.scrollTo(now[0], now[1]);
},
compute: function(from, to, delta){
return [0, 1].map(function(i){
return Fx.compute(from[i], to[i], delta);
});
},
start: function(x, y){
if (!this.check(x, y)) return this;
var offsetSize = this.element.getSize(), scrollSize = this.element.getScrollSize();
var scroll = this.element.getScroll(), values = {x: x, y: y};
for (var z in values){
var max = scrollSize[z] - offsetSize[z];
if ($chk(values[z])) values[z] = ($type(values[z]) == 'number') ? values[z].limit(0, max) : max;
else values[z] = scroll[z];
values[z] += this.options.offset[z];
}
return this.parent([scroll.x, scroll.y], [values.x, values.y]);
},
toTop: function(){
return this.start(false, 0);
},
toLeft: function(){
return this.start(0, false);
},
toRight: function(){
return this.start('right', false);
},
toBottom: function(){
return this.start(false, 'bottom');
},
toElement: function(el){
var position = document.id(el).getPosition(this.element);
return this.start(position.x, position.y);
},
scrollIntoView: function(el, axes, offset){
axes = axes ? $splat(axes) : ['x','y'];
var to = {};
el = document.id(el);
var pos = el.getPosition(this.element);
var size = el.getSize();
var scroll = this.element.getScroll();
var containerSize = this.element.getSize();
var edge = {
x: pos.x + size.x,
y: pos.y + size.y
};
['x','y'].each(function(axis) {
if (axes.contains(axis)) {
if (edge[axis] > scroll[axis] + containerSize[axis]) to[axis] = edge[axis] - containerSize[axis];
if (pos[axis] < scroll[axis]) to[axis] = pos[axis];
}
if (to[axis] == null) to[axis] = scroll[axis];
if (offset && offset[axis]) to[axis] = to[axis] + offset[axis];
}, this);
if (to.x != scroll.x || to.y != scroll.y) this.start(to.x, to.y);
return this;
}
});
/*
Script: Fx.Slide.js
Effect to slide an element in and out of view.
License:
MIT-style license.
Authors:
Valerio Proietti
*/
Fx.Slide = new Class({
Extends: Fx,
options: {
mode: 'vertical'
},
initialize: function(element, options){
this.addEvent('complete', function(){
this.open = (this.wrapper['offset' + this.layout.capitalize()] != 0);
if (this.open && Browser.Engine.webkit419) this.element.dispose().inject(this.wrapper);
}, true);
this.element = this.subject = document.id(element);
this.parent(options);
var wrapper = this.element.retrieve('wrapper');
this.wrapper = wrapper || new Element('div', {
styles: $extend(this.element.getStyles('margin', 'position'), {overflow: 'hidden'})
}).wraps(this.element);
this.element.store('wrapper', this.wrapper).setStyle('margin', 0);
this.now = [];
this.open = true;
},
vertical: function(){
this.margin = 'margin-top';
this.layout = 'height';
this.offset = this.element.offsetHeight;
},
horizontal: function(){
this.margin = 'margin-left';
this.layout = 'width';
this.offset = this.element.offsetWidth;
},
set: function(now){
this.element.setStyle(this.margin, now[0]);
this.wrapper.setStyle(this.layout, now[1]);
return this;
},
compute: function(from, to, delta){
return [0, 1].map(function(i){
return Fx.compute(from[i], to[i], delta);
});
},
start: function(how, mode){
if (!this.check(how, mode)) return this;
this[mode || this.options.mode]();
var margin = this.element.getStyle(this.margin).toInt();
var layout = this.wrapper.getStyle(this.layout).toInt();
var caseIn = [[margin, layout], [0, this.offset]];
var caseOut = [[margin, layout], [-this.offset, 0]];
var start;
switch (how){
case 'in': start = caseIn; break;
case 'out': start = caseOut; break;
case 'toggle': start = (layout == 0) ? caseIn : caseOut;
}
return this.parent(start[0], start[1]);
},
slideIn: function(mode){
return this.start('in', mode);
},
slideOut: function(mode){
return this.start('out', mode);
},
hide: function(mode){
this[mode || this.options.mode]();
this.open = false;
return this.set([-this.offset, 0]);
},
show: function(mode){
this[mode || this.options.mode]();
this.open = true;
return this.set([0, this.offset]);
},
toggle: function(mode){
return this.start('toggle', mode);
}
});
Element.Properties.slide = {
set: function(options){
var slide = this.retrieve('slide');
if (slide) slide.cancel();
return this.eliminate('slide').store('slide:options', $extend({link: 'cancel'}, options));
},
get: function(options){
if (options || !this.retrieve('slide')){
if (options || !this.retrieve('slide:options')) this.set('slide', options);
this.store('slide', new Fx.Slide(this, this.retrieve('slide:options')));
}
return this.retrieve('slide');
}
};
Element.implement({
slide: function(how, mode){
how = how || 'toggle';
var slide = this.get('slide'), toggle;
switch (how){
case 'hide': slide.hide(mode); break;
case 'show': slide.show(mode); break;
case 'toggle':
var flag = this.retrieve('slide:flag', slide.open);
slide[flag ? 'slideOut' : 'slideIn'](mode);
this.store('slide:flag', !flag);
toggle = true;
break;
default: slide.start(how, mode);
}
if (!toggle) this.eliminate('slide:flag');
return this;
}
});
/*
Script: Fx.SmoothScroll.js
Class for creating a smooth scrolling effect to all internal links on the page.
License:
MIT-style license.
Authors:
Valerio Proietti
*/
var SmoothScroll = Fx.SmoothScroll = new Class({
Extends: Fx.Scroll,
initialize: function(options, context){
context = context || document;
this.doc = context.getDocument();
var win = context.getWindow();
this.parent(this.doc, options);
this.links = this.options.links ? $$(this.options.links) : $$(this.doc.links);
var location = win.location.href.match(/^[^#]*/)[0] + '#';
this.links.each(function(link){
if (link.href.indexOf(location) != 0) {return;}
var anchor = link.href.substr(location.length);
if (anchor) this.useLink(link, anchor);
}, this);
if (!Browser.Engine.webkit419) {
this.addEvent('complete', function(){
win.location.hash = this.anchor;
}, true);
}
},
useLink: function(link, anchor){
var el;
link.addEvent('click', function(event){
if (el !== false && !el) el = document.id(anchor) || this.doc.getElement('a[name=' + anchor + ']');
if (el) {
event.preventDefault();
this.anchor = anchor;
this.toElement(el);
link.blur();
}
}.bind(this));
}
});
/*
Script: Fx.Sort.js
Defines Fx.Sort, a class that reorders lists with a transition.
License:
MIT-style license.
Authors:
Aaron Newton
*/
Fx.Sort = new Class({
Extends: Fx.Elements,
options: {
mode: 'vertical'
},
initialize: function(elements, options){
this.parent(elements, options);
this.elements.each(function(el){
if (el.getStyle('position') == 'static') el.setStyle('position', 'relative');
});
this.setDefaultOrder();
},
setDefaultOrder: function(){
this.currentOrder = this.elements.map(function(el, index){
return index;
});
},
sort: function(newOrder){
if ($type(newOrder) != 'array') return false;
var top = 0;
var left = 0;
var zero = {};
var vert = this.options.mode == 'vertical';
var current = this.elements.map(function(el, index){
var size = el.getComputedSize({styles: ['border', 'padding', 'margin']});
var val;
if (vert){
val = {
top: top,
margin: size['margin-top'],
height: size.totalHeight
};
top += val.height - size['margin-top'];
} else {
val = {
left: left,
margin: size['margin-left'],
width: size.totalWidth
};
left += val.width;
}
var plain = vert ? 'top' : 'left';
zero[index] = {};
var start = el.getStyle(plain).toInt();
zero[index][plain] = start || 0;
return val;
}, this);
this.set(zero);
newOrder = newOrder.map(function(i){ return i.toInt(); });
if (newOrder.length != this.elements.length){
this.currentOrder.each(function(index){
if (!newOrder.contains(index)) newOrder.push(index);
});
if (newOrder.length > this.elements.length)
newOrder.splice(this.elements.length-1, newOrder.length - this.elements.length);
}
top = 0;
left = 0;
var margin = 0;
var next = {};
newOrder.each(function(item, index){
var newPos = {};
if (vert){
newPos.top = top - current[item].top - margin;
top += current[item].height;
} else {
newPos.left = left - current[item].left;
left += current[item].width;
}
margin = margin + current[item].margin;
next[item]=newPos;
}, this);
var mapped = {};
$A(newOrder).sort().each(function(index){
mapped[index] = next[index];
});
this.start(mapped);
this.currentOrder = newOrder;
return this;
},
rearrangeDOM: function(newOrder){
newOrder = newOrder || this.currentOrder;
var parent = this.elements[0].getParent();
var rearranged = [];
this.elements.setStyle('opacity', 0);
//move each element and store the new default order
newOrder.each(function(index){
rearranged.push(this.elements[index].inject(parent).setStyles({
top: 0,
left: 0
}));
}, this);
this.elements.setStyle('opacity', 1);
this.elements = $$(rearranged);
this.setDefaultOrder();
return this;
},
getDefaultOrder: function(){
return this.elements.map(function(el, index){
return index;
});
},
forward: function(){
return this.sort(this.getDefaultOrder());
},
backward: function(){
return this.sort(this.getDefaultOrder().reverse());
},
reverse: function(){
return this.sort(this.currentOrder.reverse());
},
sortByElements: function(elements){
return this.sort(elements.map(function(el){
return this.elements.indexOf(el);
}, this));
},
swap: function(one, two){
if ($type(one) == 'element') one = this.elements.indexOf(one);
if ($type(two) == 'element') two = this.elements.indexOf(two);
var newOrder = $A(this.currentOrder);
newOrder[this.currentOrder.indexOf(one)] = two;
newOrder[this.currentOrder.indexOf(two)] = one;
this.sort(newOrder);
}
});
/*
Script: Drag.js
The base Drag Class. Can be used to drag and resize Elements using mouse events.
License:
MIT-style license.
Authors:
Valerio Proietti
Tom Occhinno
Jan Kassens
*/
var Drag = new Class({
Implements: [Events, Options],
options: {/*
onBeforeStart: $empty(thisElement),
onStart: $empty(thisElement, event),
onSnap: $empty(thisElement)
onDrag: $empty(thisElement, event),
onCancel: $empty(thisElement),
onComplete: $empty(thisElement, event),*/
snap: 6,
unit: 'px',
grid: false,
style: true,
limit: false,
handle: false,
invert: false,
preventDefault: false,
modifiers: {x: 'left', y: 'top'}
},
initialize: function(){
var params = Array.link(arguments, {'options': Object.type, 'element': $defined});
this.element = document.id(params.element);
this.document = this.element.getDocument();
this.setOptions(params.options || {});
var htype = $type(this.options.handle);
this.handles = ((htype == 'array' || htype == 'collection') ? $$(this.options.handle) : document.id(this.options.handle)) || this.element;
this.mouse = {'now': {}, 'pos': {}};
this.value = {'start': {}, 'now': {}};
this.selection = (Browser.Engine.trident) ? 'selectstart' : 'mousedown';
this.bound = {
start: this.start.bind(this),
check: this.check.bind(this),
drag: this.drag.bind(this),
stop: this.stop.bind(this),
cancel: this.cancel.bind(this),
eventStop: $lambda(false)
};
this.attach();
},
attach: function(){
this.handles.addEvent('mousedown', this.bound.start);
return this;
},
detach: function(){
this.handles.removeEvent('mousedown', this.bound.start);
return this;
},
start: function(event){
if (this.options.preventDefault) event.preventDefault();
this.mouse.start = event.page;
this.fireEvent('beforeStart', this.element);
var limit = this.options.limit;
this.limit = {x: [], y: []};
for (var z in this.options.modifiers){
if (!this.options.modifiers[z]) continue;
if (this.options.style) this.value.now[z] = this.element.getStyle(this.options.modifiers[z]).toInt();
else this.value.now[z] = this.element[this.options.modifiers[z]];
if (this.options.invert) this.value.now[z] *= -1;
this.mouse.pos[z] = event.page[z] - this.value.now[z];
if (limit && limit[z]){
for (var i = 2; i--; i){
if ($chk(limit[z][i])) this.limit[z][i] = $lambda(limit[z][i])();
}
}
}
if ($type(this.options.grid) == 'number') this.options.grid = {x: this.options.grid, y: this.options.grid};
this.document.addEvents({mousemove: this.bound.check, mouseup: this.bound.cancel});
this.document.addEvent(this.selection, this.bound.eventStop);
},
check: function(event){
if (this.options.preventDefault) event.preventDefault();
var distance = Math.round(Math.sqrt(Math.pow(event.page.x - this.mouse.start.x, 2) + Math.pow(event.page.y - this.mouse.start.y, 2)));
if (distance > this.options.snap){
this.cancel();
this.document.addEvents({
mousemove: this.bound.drag,
mouseup: this.bound.stop
});
this.fireEvent('start', [this.element, event]).fireEvent('snap', this.element);
}
},
drag: function(event){
if (this.options.preventDefault) event.preventDefault();
this.mouse.now = event.page;
for (var z in this.options.modifiers){
if (!this.options.modifiers[z]) continue;
this.value.now[z] = this.mouse.now[z] - this.mouse.pos[z];
if (this.options.invert) this.value.now[z] *= -1;
if (this.options.limit && this.limit[z]){
if ($chk(this.limit[z][1]) && (this.value.now[z] > this.limit[z][1])){
this.value.now[z] = this.limit[z][1];
} else if ($chk(this.limit[z][0]) && (this.value.now[z] < this.limit[z][0])){
this.value.now[z] = this.limit[z][0];
}
}
if (this.options.grid[z]) this.value.now[z] -= ((this.value.now[z] - (this.limit[z][0]||0)) % this.options.grid[z]);
if (this.options.style) this.element.setStyle(this.options.modifiers[z], this.value.now[z] + this.options.unit);
else this.element[this.options.modifiers[z]] = this.value.now[z];
}
this.fireEvent('drag', [this.element, event]);
},
cancel: function(event){
this.document.removeEvent('mousemove', this.bound.check);
this.document.removeEvent('mouseup', this.bound.cancel);
if (event){
this.document.removeEvent(this.selection, this.bound.eventStop);
this.fireEvent('cancel', this.element);
}
},
stop: function(event){
this.document.removeEvent(this.selection, this.bound.eventStop);
this.document.removeEvent('mousemove', this.bound.drag);
this.document.removeEvent('mouseup', this.bound.stop);
if (event) this.fireEvent('complete', [this.element, event]);
}
});
Element.implement({
makeResizable: function(options){
var drag = new Drag(this, $merge({modifiers: {x: 'width', y: 'height'}}, options));
this.store('resizer', drag);
return drag.addEvent('drag', function(){
this.fireEvent('resize', drag);
}.bind(this));
}
});
/*
Script: Drag.Move.js
A Drag extension that provides support for the constraining of draggables to containers and droppables.
License:
MIT-style license.
Authors:
Valerio Proietti
Tom Occhinno
Jan Kassens*/
Drag.Move = new Class({
Extends: Drag,
options: {/*
onEnter: $empty(thisElement, overed),
onLeave: $empty(thisElement, overed),
onDrop: $empty(thisElement, overed, event),*/
droppables: [],
container: false,
precalculate: false,
includeMargins: true,
checkDroppables: true
},
initialize: function(element, options){
this.parent(element, options);
this.droppables = $$(this.options.droppables);
this.container = document.id(this.options.container);
if (this.container && $type(this.container) != 'element') this.container = document.id(this.container.getDocument().body);
var position = this.element.getStyle('position');
if (position=='static') position = 'absolute';
if ([this.element.getStyle('left'), this.element.getStyle('top')].contains('auto')) this.element.position(this.element.getPosition(this.element.offsetParent));
this.element.setStyle('position', position);
this.addEvent('start', this.checkDroppables, true);
this.overed = null;
},
start: function(event){
if (this.container){
var ccoo = this.container.getCoordinates(this.element.getOffsetParent()), cbs = {}, ems = {};
['top', 'right', 'bottom', 'left'].each(function(pad){
cbs[pad] = this.container.getStyle('border-' + pad).toInt();
ems[pad] = this.element.getStyle('margin-' + pad).toInt();
}, this);
var width = this.element.offsetWidth + ems.left + ems.right;
var height = this.element.offsetHeight + ems.top + ems.bottom;
if (this.options.includeMargins) {
$each(ems, function(value, key) {
ems[key] = 0;
});
}
if (this.container == this.element.getOffsetParent()) {
this.options.limit = {
x: [0 - ems.left, ccoo.right - cbs.left - cbs.right - width + ems.right],
y: [0 - ems.top, ccoo.bottom - cbs.top - cbs.bottom - height + ems.bottom]
};
} else {
this.options.limit = {
x: [ccoo.left + cbs.left - ems.left, ccoo.right - cbs.right - width + ems.right],
y: [ccoo.top + cbs.top - ems.top, ccoo.bottom - cbs.bottom - height + ems.bottom]
};
}
}
if (this.options.precalculate){
this.positions = this.droppables.map(function(el) {
return el.getCoordinates();
});
}
this.parent(event);
},
checkAgainst: function(el, i){
el = (this.positions) ? this.positions[i] : el.getCoordinates();
var now = this.mouse.now;
return (now.x > el.left && now.x < el.right && now.y < el.bottom && now.y > el.top);
},
checkDroppables: function(){
var overed = this.droppables.filter(this.checkAgainst, this).getLast();
if (this.overed != overed){
if (this.overed) this.fireEvent('leave', [this.element, this.overed]);
if (overed) this.fireEvent('enter', [this.element, overed]);
this.overed = overed;
}
},
drag: function(event){
this.parent(event);
if (this.options.checkDroppables && this.droppables.length) this.checkDroppables();
},
stop: function(event){
this.checkDroppables();
this.fireEvent('drop', [this.element, this.overed, event]);
this.overed = null;
return this.parent(event);
}
});
Element.implement({
makeDraggable: function(options){
var drag = new Drag.Move(this, options);
this.store('dragger', drag);
return drag;
}
});
/*
Script: Slider.js
Class for creating horizontal and vertical slider controls.
License:
MIT-style license.
Authors:
Valerio Proietti
*/
var Slider = new Class({
Implements: [Events, Options],
Binds: ['clickedElement', 'draggedKnob', 'scrolledElement'],
options: {/*
onTick: $empty(intPosition),
onChange: $empty(intStep),
onComplete: $empty(strStep),*/
onTick: function(position){
if (this.options.snap) position = this.toPosition(this.step);
this.knob.setStyle(this.property, position);
},
snap: false,
offset: 0,
range: false,
wheel: false,
steps: 100,
mode: 'horizontal'
},
initialize: function(element, knob, options){
this.setOptions(options);
this.element = document.id(element);
this.knob = document.id(knob);
this.previousChange = this.previousEnd = this.step = -1;
var offset, limit = {}, modifiers = {'x': false, 'y': false};
switch (this.options.mode){
case 'vertical':
this.axis = 'y';
this.property = 'top';
offset = 'offsetHeight';
break;
case 'horizontal':
this.axis = 'x';
this.property = 'left';
offset = 'offsetWidth';
}
this.half = this.knob[offset] / 2;
this.full = this.element[offset] - this.knob[offset] + (this.options.offset * 2);
this.min = $chk(this.options.range[0]) ? this.options.range[0] : 0;
this.max = $chk(this.options.range[1]) ? this.options.range[1] : this.options.steps;
this.range = this.max - this.min;
this.steps = this.options.steps || this.full;
this.stepSize = Math.abs(this.range) / this.steps;
this.stepWidth = this.stepSize * this.full / Math.abs(this.range) ;
this.knob.setStyle('position', 'relative').setStyle(this.property, - this.options.offset);
modifiers[this.axis] = this.property;
limit[this.axis] = [- this.options.offset, this.full - this.options.offset];
this.bound = {
clickedElement: this.clickedElement.bind(this),
scrolledElement: this.scrolledElement.bindWithEvent(this),
draggedKnob: this.draggedKnob.bind(this)
};
var dragOptions = {
snap: 0,
limit: limit,
modifiers: modifiers,
onDrag: this.bound.draggedKnob,
onStart: this.bound.draggedKnob,
onBeforeStart: (function(){
this.isDragging = true;
}).bind(this),
onComplete: function(){
this.isDragging = false;
this.draggedKnob();
this.end();
}.bind(this)
};
if (this.options.snap){
dragOptions.grid = Math.ceil(this.stepWidth);
dragOptions.limit[this.axis][1] = this.full;
}
this.drag = new Drag(this.knob, dragOptions);
this.attach();
},
attach: function(){
this.element.addEvent('mousedown', this.bound.clickedElement);
if (this.options.wheel) this.element.addEvent('mousewheel', this.bound.scrolledElement);
this.drag.attach();
return this;
},
detach: function(){
this.element.removeEvent('mousedown', this.bound.clickedElement);
this.element.removeEvent('mousewheel', this.bound.scrolledElement);
this.drag.detach();
return this;
},
set: function(step){
if (!((this.range > 0) ^ (step < this.min))) step = this.min;
if (!((this.range > 0) ^ (step > this.max))) step = this.max;
this.step = Math.round(step);
this.checkStep();
this.fireEvent('tick', this.toPosition(this.step));
this.end();
return this;
},
clickedElement: function(event){
if (this.isDragging || event.target == this.knob) return;
var dir = this.range < 0 ? -1 : 1;
var position = event.page[this.axis] - this.element.getPosition()[this.axis] - this.half;
position = position.limit(-this.options.offset, this.full -this.options.offset);
this.step = Math.round(this.min + dir * this.toStep(position));
this.checkStep();
this.fireEvent('tick', position);
this.end();
},
scrolledElement: function(event){
var mode = (this.options.mode == 'horizontal') ? (event.wheel < 0) : (event.wheel > 0);
this.set(mode ? this.step - this.stepSize : this.step + this.stepSize);
event.stop();
},
draggedKnob: function(){
var dir = this.range < 0 ? -1 : 1;
var position = this.drag.value.now[this.axis];
position = position.limit(-this.options.offset, this.full -this.options.offset);
this.step = Math.round(this.min + dir * this.toStep(position));
this.checkStep();
},
checkStep: function(){
if (this.previousChange != this.step){
this.previousChange = this.step;
this.fireEvent('change', this.step);
}
},
end: function(){
if (this.previousEnd !== this.step){
this.previousEnd = this.step;
this.fireEvent('complete', this.step + '');
}
},
toStep: function(position){
var step = (position + this.options.offset) * this.stepSize / this.full * this.steps;
return this.options.steps ? Math.round(step -= step % this.stepSize) : step;
},
toPosition: function(step){
return (this.full * Math.abs(this.min - step)) / (this.steps * this.stepSize) - this.options.offset;
}
});
/*
Script: Sortables.js
Class for creating a drag and drop sorting interface for lists of items.
License:
MIT-style license.
Authors:
Tom Occhino
*/
var Sortables = new Class({
Implements: [Events, Options],
options: {/*
onSort: $empty(element, clone),
onStart: $empty(element, clone),
onComplete: $empty(element),*/
snap: 4,
opacity: 1,
clone: false,
revert: false,
handle: false,
constrain: false
},
initialize: function(lists, options){
this.setOptions(options);
this.elements = [];
this.lists = [];
this.idle = true;
this.addLists($$(document.id(lists) || lists));
if (!this.options.clone) this.options.revert = false;
if (this.options.revert) this.effect = new Fx.Morph(null, $merge({duration: 250, link: 'cancel'}, this.options.revert));
},
attach: function(){
this.addLists(this.lists);
return this;
},
detach: function(){
this.lists = this.removeLists(this.lists);
return this;
},
addItems: function(){
Array.flatten(arguments).each(function(element){
this.elements.push(element);
var start = element.retrieve('sortables:start', this.start.bindWithEvent(this, element));
(this.options.handle ? element.getElement(this.options.handle) || element : element).addEvent('mousedown', start);
}, this);
return this;
},
addLists: function(){
Array.flatten(arguments).each(function(list){
this.lists.push(list);
this.addItems(list.getChildren());
}, this);
return this;
},
removeItems: function(){
return $$(Array.flatten(arguments).map(function(element){
this.elements.erase(element);
var start = element.retrieve('sortables:start');
(this.options.handle ? element.getElement(this.options.handle) || element : element).removeEvent('mousedown', start);
return element;
}, this));
},
removeLists: function(){
return $$(Array.flatten(arguments).map(function(list){
this.lists.erase(list);
this.removeItems(list.getChildren());
return list;
}, this));
},
getClone: function(event, element){
if (!this.options.clone) return new Element('div').inject(document.body);
if ($type(this.options.clone) == 'function') return this.options.clone.call(this, event, element, this.list);
return element.clone(true).setStyles({
margin: '0px',
position: 'absolute',
visibility: 'hidden',
'width': element.getStyle('width')
}).inject(this.list).position(element.getPosition(element.getOffsetParent()));
},
getDroppables: function(){
var droppables = this.list.getChildren();
if (!this.options.constrain) droppables = this.lists.concat(droppables).erase(this.list);
return droppables.erase(this.clone).erase(this.element);
},
insert: function(dragging, element){
var where = 'inside';
if (this.lists.contains(element)){
this.list = element;
this.drag.droppables = this.getDroppables();
} else {
where = this.element.getAllPrevious().contains(element) ? 'before' : 'after';
}
this.element.inject(element, where);
this.fireEvent('sort', [this.element, this.clone]);
},
start: function(event, element){
if (!this.idle) return;
this.idle = false;
this.element = element;
this.opacity = element.get('opacity');
this.list = element.getParent();
this.clone = this.getClone(event, element);
this.drag = new Drag.Move(this.clone, {
snap: this.options.snap,
container: this.options.constrain && this.element.getParent(),
droppables: this.getDroppables(),
onSnap: function(){
event.stop();
this.clone.setStyle('visibility', 'visible');
this.element.set('opacity', this.options.opacity || 0);
this.fireEvent('start', [this.element, this.clone]);
}.bind(this),
onEnter: this.insert.bind(this),
onCancel: this.reset.bind(this),
onComplete: this.end.bind(this)
});
this.clone.inject(this.element, 'before');
this.drag.start(event);
},
end: function(){
this.drag.detach();
this.element.set('opacity', this.opacity);
if (this.effect){
var dim = this.element.getStyles('width', 'height');
var pos = this.clone.computePosition(this.element.getPosition(this.clone.offsetParent));
this.effect.element = this.clone;
this.effect.start({
top: pos.top,
left: pos.left,
width: dim.width,
height: dim.height,
opacity: 0.25
}).chain(this.reset.bind(this));
} else {
this.reset();
}
},
reset: function(){
this.idle = true;
this.clone.destroy();
this.fireEvent('complete', this.element);
},
serialize: function(){
var params = Array.link(arguments, {modifier: Function.type, index: $defined});
var serial = this.lists.map(function(list){
return list.getChildren().map(params.modifier || function(element){
return element.get('id');
}, this);
}, this);
var index = params.index;
if (this.lists.length == 1) index = 0;
return $chk(index) && index >= 0 && index < this.lists.length ? serial[index] : serial;
}
});
/*
Script: Assets.js
Provides methods to dynamically load JavaScript, CSS, and Image files into the document.
License:
MIT-style license.
Authors:
Valerio Proietti
*/
var Asset = {
javascript: function(source, properties){
properties = $extend({
onload: $empty,
document: document,
check: $lambda(true)
}, properties);
var script = new Element('script', {src: source, type: 'text/javascript'});
var load = properties.onload.bind(script), check = properties.check, doc = properties.document;
delete properties.onload; delete properties.check; delete properties.document;
script.addEvents({
load: load,
readystatechange: function(){
if (['loaded', 'complete'].contains(this.readyState)) load();
}
}).set(properties);
if (Browser.Engine.webkit419) var checker = (function(){
if (!$try(check)) return;
$clear(checker);
load();
}).periodical(50);
return script.inject(doc.head);
},
css: function(source, properties){
return new Element('link', $merge({
rel: 'stylesheet', media: 'screen', type: 'text/css', href: source
}, properties)).inject(document.head);
},
image: function(source, properties){
properties = $merge({
onload: $empty,
onabort: $empty,
onerror: $empty
}, properties);
var image = new Image();
var element = document.id(image) || new Element('img');
['load', 'abort', 'error'].each(function(name){
var type = 'on' + name;
var event = properties[type];
delete properties[type];
image[type] = function(){
if (!image) return;
if (!element.parentNode){
element.width = image.width;
element.height = image.height;
}
image = image.onload = image.onabort = image.onerror = null;
event.delay(1, element, element);
element.fireEvent(name, element, 1);
};
});
image.src = element.src = source;
if (image && image.complete) image.onload.delay(1);
return element.set(properties);
},
images: function(sources, options){
options = $merge({
onComplete: $empty,
onProgress: $empty,
onError: $empty,
properties: {}
}, options);
sources = $splat(sources);
var images = [];
var counter = 0;
return new Elements(sources.map(function(source){
return Asset.image(source, $extend(options.properties, {
onload: function(){
options.onProgress.call(this, counter, sources.indexOf(source));
counter++;
if (counter == sources.length) options.onComplete();
},
onerror: function(){
options.onError.call(this, counter, sources.indexOf(source));
counter++;
if (counter == sources.length) options.onComplete();
}
}));
}));
}
};
/*
Script: Tips.js
Class for creating nice tips that follow the mouse cursor when hovering an element.
License:
MIT-style license.
Authors:
Valerio Proietti
Christoph Pojer
*/
var Tips = new Class({
Implements: [Events, Options],
options: {
onShow: function(tip){
tip.setStyle('visibility', 'visible');
},
onHide: function(tip){
tip.setStyle('visibility', 'hidden');
},
title: 'title',
text: function(el){
return el.get('rel') || el.get('href');
},
showDelay: 100,
hideDelay: 100,
className: null,
offset: {x: 16, y: 16},
fixed: false
},
initialize: function(){
var params = Array.link(arguments, {options: Object.type, elements: $defined});
if (params.options && params.options.offsets) params.options.offset = params.options.offsets;
this.setOptions(params.options);
this.container = new Element('div', {'class': 'tip'});
this.tip = this.getTip();
if (params.elements) this.attach(params.elements);
},
getTip: function(){
return new Element('div', {
'class': this.options.className,
styles: {
visibility: 'hidden',
display: 'none',
position: 'absolute',
top: 0,
left: 0
}
}).adopt(
new Element('div', {'class': 'tip-top'}),
this.container,
new Element('div', {'class': 'tip-bottom'})
).inject(document.body);
},
attach: function(elements){
var read = function(option, element){
if (option == null) return '';
return $type(option) == 'function' ? option(element) : element.get(option);
};
$$(elements).each(function(element){
var title = read(this.options.title, element);
element.erase('title').store('tip:native', title).retrieve('tip:title', title);
element.retrieve('tip:text', read(this.options.text, element));
var events = ['enter', 'leave'];
if (!this.options.fixed) events.push('move');
events.each(function(value){
element.addEvent('mouse' + value, element.retrieve('tip:' + value, this['element' + value.capitalize()].bindWithEvent(this, element)));
}, this);
}, this);
return this;
},
detach: function(elements){
$$(elements).each(function(element){
['enter', 'leave', 'move'].each(function(value){
element.removeEvent('mouse' + value, element.retrieve('tip:' + value) || $empty);
});
element.eliminate('tip:enter').eliminate('tip:leave').eliminate('tip:move');
if ($type(this.options.title) == 'string' && this.options.title == 'title'){
var original = element.retrieve('tip:native');
if (original) element.set('title', original);
}
}, this);
return this;
},
elementEnter: function(event, element){
$A(this.container.childNodes).each(Element.dispose);
['title', 'text'].each(function(value){
var content = element.retrieve('tip:' + value);
if (!content) return;
this[value + 'Element'] = new Element('div', {'class': 'tip-' + value}).inject(this.container);
this.fill(this[value + 'Element'], content);
}, this);
this.timer = $clear(this.timer);
this.timer = this.show.delay(this.options.showDelay, this, element);
this.tip.setStyle('display', 'block');
this.position((!this.options.fixed) ? event : {page: element.getPosition()});
},
elementLeave: function(event, element){
$clear(this.timer);
this.tip.setStyle('display', 'none');
this.timer = this.hide.delay(this.options.hideDelay, this, element);
},
elementMove: function(event){
this.position(event);
},
position: function(event){
var size = window.getSize(), scroll = window.getScroll(),
tip = {x: this.tip.offsetWidth, y: this.tip.offsetHeight},
props = {x: 'left', y: 'top'},
obj = {};
for (var z in props){
obj[props[z]] = event.page[z] + this.options.offset[z];
if ((obj[props[z]] + tip[z] - scroll[z]) > size[z]) obj[props[z]] = event.page[z] - this.options.offset[z] - tip[z];
}
this.tip.setStyles(obj);
},
fill: function(element, contents){
if(typeof contents == 'string') element.set('html', contents);
else element.adopt(contents);
},
show: function(el){
this.fireEvent('show', [this.tip, el]);
},
hide: function(el){
this.fireEvent('hide', [this.tip, el]);
}
});
/*
Script: Date.English.US.js
Date messages for US English.
License:
MIT-style license.
Authors:
Aaron Newton
*/
MooTools.lang.set('en-US', 'Date', {
months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
//culture's date order: MM/DD/YYYY
dateOrder: ['month', 'date', 'year'],
shortDate: '%m/%d/%Y',
shortTime: '%I:%M%p',
AM: 'AM',
PM: 'PM',
/* Date.Extras */
ordinal: function(dayOfMonth){
//1st, 2nd, 3rd, etc.
return (dayOfMonth > 3 && dayOfMonth < 21) ? 'th' : ['th', 'st', 'nd', 'rd', 'th'][Math.min(dayOfMonth % 10, 4)];
},
lessThanMinuteAgo: 'less than a minute ago',
minuteAgo: 'about a minute ago',
minutesAgo: '{delta} minutes ago',
hourAgo: 'about an hour ago',
hoursAgo: 'about {delta} hours ago',
dayAgo: '1 day ago',
daysAgo: '{delta} days ago',
lessThanMinuteUntil: 'less than a minute from now',
minuteUntil: 'about a minute from now',
minutesUntil: '{delta} minutes from now',
hourUntil: 'about an hour from now',
hoursUntil: 'about {delta} hours from now',
dayUntil: '1 day from now',
daysUntil: '{delta} days from now'
});
// cmscript: globals
var isIE5or6, isIE6;
cxlEnv.isIE5or6 = cxlEnv.isIE6 = isIE5or6 = isIE6 = Browser.Engine.trident4;
// cmscript: clientcide
/*
Script: dbug.js
A wrapper for Firebug console.* statements.
License:
http://clientside.cnet.com/wiki/cnet-libraries#license
*/
var dbug = {
logged: [],	
timers: {},
firebug: false, 
enabled: false, 
log: function() {
dbug.logged.push(arguments);
},
nolog: function(msg) {
dbug.logged.push(arguments);
},
time: function(name){
dbug.timers[name] = new Date().getTime();
},
timeEnd: function(name){
if (dbug.timers[name]) {
var end = new Date().getTime() - dbug.timers[name];
dbug.timers[name] = false;
dbug.log('%s: %s', name, end);
} else dbug.log('no such timer: %s', name);
},
enable: function(silent) { 
if(dbug.firebug) {
try {
dbug.enabled = true;
dbug.log = function(){
(console.debug || console.log).apply(console, arguments);
};
dbug.time = function(){
console.time.apply(console, arguments);
};
dbug.timeEnd = function(){
console.timeEnd.apply(console, arguments);
};
if(!silent) dbug.log('enabling dbug');
for(var i=0;i<dbug.logged.length;i++){ dbug.log.apply(console, dbug.logged[i]); }
dbug.logged=[];
} catch(e) {
dbug.enable.delay(400);
}
}
},
disable: function(){ 
if(dbug.firebug) dbug.enabled = false;
dbug.log = dbug.nolog;
dbug.time = function(){};
dbug.timeEnd = function(){};
},
cookie: function(set){
var value = document.cookie.match('(?:^|;)\\s*jsdebug=([^;]*)');
var debugCookie = value ? unescape(value[1]) : false;
if((debugCookie != 'true' || set) && !set) {
dbug.enable();
dbug.log('setting debugging cookie');
var date = new Date();
date.setTime(date.getTime()+(24*60*60*1000));
document.cookie = 'jsdebug=true;expires='+date.toGMTString()+';path=/;';
} else dbug.disableCookie();
},
disableCookie: function(){
dbug.log('disabling debugging cookie');
document.cookie = 'jsdebug=false;path=/;';
}
};
(function(){
var fb = typeof console != "undefined";
var debugMethods = ['debug','info','warn','error','assert','dir','dirxml'];
var otherMethods = ['trace','group','groupEnd','profile','profileEnd','count'];
function set(methodList, defaultFunction) {
for(var i = 0; i < methodList.length; i++){
dbug[methodList[i]] = (fb && console[methodList[i]])?console[methodList[i]]:defaultFunction;
}
};
set(debugMethods, dbug.log);
set(otherMethods, function(){});
})();
if (typeof console != "undefined" && console.warn){
dbug.firebug = true;
var value = document.cookie.match('(?:^|;)\\s*jsdebug=([^;]*)');
var debugCookie = value ? unescape(value[1]) : false;
if(window.location.href.indexOf("jsdebug=true")>0 || debugCookie=='true') dbug.enable();
if(debugCookie=='true')dbug.log('debugging cookie enabled');
if(window.location.href.indexOf("jsdebugCookie=true")>0){
dbug.cookie();
if(!dbug.enabled)dbug.enable();
}
if(window.location.href.indexOf("jsdebugCookie=false")>0)dbug.disableCookie();
}
/*
Script: Element.Measure.js
Extends the Element native object to include methods useful in measuring dimensions.
License:
http://clientside.cnet.com/wiki/cnet-libraries#license
*/
Element.implement({
expose: function(){
if (this.getStyle('display') != 'none') return $empty;
var before = {};
var styles = { visibility: 'hidden', display: 'block', position:'absolute' };
//use this method instead of getStyles 
$each(styles, function(value, style){
before[style] = this.style[style]||'';
}, this);
//this.getStyles('visibility', 'display', 'position');
this.setStyles(styles);
return (function(){ this.setStyles(before); }).bind(this);
},
getDimensions: function(options) {
options = $merge({computeSize: false},options);
var dim = {};
function getSize(el, options){
return (options.computeSize)?el.getComputedSize(options):el.getSize();
};
if(this.getStyle('display') == 'none'){
var restore = this.expose();
dim = getSize(this, options); //works now, because the display isn't none
restore(); //put it back where it was
} else {
try { //safari sometimes crashes here, so catch it
dim = getSize(this, options);
}catch(e){}
}
return $chk(dim.x)?$extend(dim, {width: dim.x, height: dim.y}):$extend(dim, {x: dim.width, y: dim.height});
},
getComputedSize: function(options){
options = $merge({
styles: ['padding','border'],
plains: {height: ['top','bottom'], width: ['left','right']},
mode: 'both'
}, options);
var size = {width: 0,height: 0};
switch (options.mode){
case 'vertical':
delete size.width;
delete options.plains.width;
break;
case 'horizontal':
delete size.height;
delete options.plains.height;
break;
};
var getStyles = [];
//this function might be useful in other places; perhaps it should be outside this function?
$each(options.plains, function(plain, key){
plain.each(function(edge){
options.styles.each(function(style){
getStyles.push((style=="border")?style+'-'+edge+'-'+'width':style+'-'+edge);
});
});
});
var styles = this.getStyles.apply(this, getStyles);
var subtracted = [];
$each(options.plains, function(plain, key){ //keys: width, height, plains: ['left','right'], ['top','bottom']
size['total'+key.capitalize()] = 0;
size['computed'+key.capitalize()] = 0;
plain.each(function(edge){ //top, left, right, bottom
size['computed'+edge.capitalize()] = 0;
getStyles.each(function(style,i){ //padding, border, etc.
//'padding-left'.test('left') size['totalWidth'] = size['width']+[padding-left]
if(style.test(edge)) {
styles[style] = styles[style].toInt(); //styles['padding-left'] = 5;
if(isNaN(styles[style]))styles[style]=0;
size['total'+key.capitalize()] = size['total'+key.capitalize()]+styles[style];
size['computed'+edge.capitalize()] = size['computed'+edge.capitalize()]+styles[style];
}
//if width != width (so, padding-left, for instance), then subtract that from the total
if(style.test(edge) && key!=style && 
(style.test('border') || style.test('padding')) && !subtracted.contains(style)) {
subtracted.push(style);
size['computed'+key.capitalize()] = size['computed'+key.capitalize()]-styles[style];
}
});
});
});
if($chk(size.width)) {
size.width = size.width+this.offsetWidth+size.computedWidth;
size.totalWidth = size.width + size.totalWidth;
delete size.computedWidth;
}
if($chk(size.height)) {
size.height = size.height+this.offsetHeight+size.computedHeight;
size.totalHeight = size.height + size.totalHeight;
delete size.computedHeight;
}
return $extend(styles, size);
}
});
/*
Script: Element.Shortcuts.js
Extends the Element native object to include some shortcut methods.
License:
http://clientside.cnet.com/wiki/cnet-libraries#license
*/
Element.implement({
isVisible: function() {
return this.getStyle('display') != 'none';
},
toggle: function() {
return this[this.isVisible() ? 'hide' : 'show']();
},
hide: function() {
var d;
try {
//IE fails here if the element is not in the dom
d = this.getStyle('display');
} catch(e){}
this.store('originalDisplay', d||'block'); 
this.setStyle('display','none');
return this;
},
show: function(display) {
original = this.retrieve('originalDisplay')?this.retrieve('originalDisplay'):this.get('originalDisplay');
this.setStyle('display',(display || original || 'block'));
return this;
},
swapClass: function(remove, add) {
return this.removeClass(remove).addClass(add);
},
//TODO
//DO NOT USE THIS METHOD
//it is temporary, as Mootools 1.1 will negate its requirement
fxOpacityOk: function(){
return !Browser.Engine.trident4;
}
});
/*
Script: Fx.Reveal.js
Defines Fx.Reveal, a class that shows and hides elements with a transition.
License:
http://clientside.cnet.com/wiki/cnet-libraries#license
*/
Fx.Reveal = new Class({
Extends: Fx.Morph,
options: {
styles: ['padding','border','margin'],
transitionOpacity: true,
mode:'vertical',
heightOverride: null,
widthOverride: null
},
dissolve: function(){
try {
if(!this.hiding && !this.showing) {
if(this.element.getStyle('display') != 'none'){
this.hiding = true;
this.showing = false;
this.hidden = true;
var startStyles = this.element.getComputedSize({
styles: this.options.styles,
mode: this.options.mode
});
var setToAuto = this.element.style.height === ""||this.element.style.height=="auto";
this.element.setStyle('display', 'block');
if (this.element.fxOpacityOk() && this.options.transitionOpacity) startStyles.opacity = 1;
var zero = {};
$each(startStyles, function(style, name){
zero[name] = [style, 0]; 
}, this);
var overflowBefore = this.element.getStyle('overflow');
this.element.setStyle('overflow', 'hidden');
//put the final fx method at the front of the chain
if (!this.$chain) this.$chain = [];
this.$chain.unshift(function(){
if(this.hidden) {
this.hiding = false;
$each(startStyles, function(style, name) {
startStyles[name] = style;
}, this);
this.element.setStyles($merge({display: 'none', overflow: overflowBefore}, startStyles));
if (setToAuto) this.element.setStyle('height', 'auto');
}
this.callChain();
}.bind(this));
this.start(zero);
} else {
this.callChain.delay(10, this);
this.fireEvent('onComplete', this.element);
}
}
} catch(e) {
this.hiding = false;
this.element.hide();
this.callChain.delay(10, this);
this.fireEvent('onComplete', this.element);
}
return this;
},
reveal: function(){
try {
if(!this.showing && !this.hiding) {
if(this.element.getStyle('display') == "none" || 
this.element.getStyle('visiblity') == "hidden" || 
this.element.getStyle('opacity')==0){
this.showing = true;
this.hiding = false;
this.hidden = false;
//toggle display, but hide it
var before = this.element.getStyles('visibility', 'display', 'position');
this.element.setStyles({
visibility: 'hidden',
display: 'block',
position:'absolute'
});
var setToAuto = this.element.style.height === ""||this.element.style.height=="auto";
//enable opacity effects
if(this.element.fxOpacityOk() && this.options.transitionOpacity) this.element.setStyle('opacity',0);
//create the styles for the opened/visible state
var startStyles = this.element.getComputedSize({
styles: this.options.styles,
mode: this.options.mode
});
//reset the styles back to hidden now
this.element.setStyles(before);
$each(startStyles, function(style, name) {
startStyles[name] = style;
}, this);
//if we're overridding height/width
if($chk(this.options.heightOverride)) startStyles['height'] = this.options.heightOverride.toInt();
if($chk(this.options.widthOverride)) startStyles['width'] = this.options.widthOverride.toInt();
if(this.element.fxOpacityOk() && this.options.transitionOpacity) startStyles.opacity = 1;
//create the zero state for the beginning of the transition
var zero = { 
height: 0,
display: 'block'
};
$each(startStyles, function(style, name){ zero[name] = 0 }, this);
var overflowBefore = this.element.getStyle('overflow');
//set to zero
this.element.setStyles($merge(zero, {overflow: 'hidden'}));
//start the effect
this.start(startStyles);
if (!this.$chain) this.$chain = [];
this.$chain.unshift(function(){
if (!this.options.heightOverride && setToAuto) {
if (["vertical", "both"].contains(this.options.mode)) this.element.setStyle('height', 'auto');
if (["width", "both"].contains(this.options.mode)) this.element.setStyle('width', 'auto');
}
if(!this.hidden) this.showing = false;
this.element.setStyle('overflow', overflowBefore);
this.callChain();
}.bind(this));
} else {
this.callChain();
this.fireEvent('onComplete', this.element);
}
}
} catch(e) {
this.element.setStyles({
display: 'block',
visiblity: 'visible',
opacity: 1
});
this.showing = false;
this.callChain.delay(10, this);
this.fireEvent('onComplete', this.element);
}
return this;
},
toggle: function(){
try {
if(this.element.getStyle('display') == "none" || 
this.element.getStyle('visiblity') == "hidden" || 
this.element.getStyle('opacity')==0){
this.reveal();
} else {
this.dissolve();
}
} catch(e) { this.show(); }
return this;
}
});
Element.Properties.reveal = {
set: function(options){
var reveal = this.retrieve('reveal');
if (reveal) reveal.cancel();
return this.eliminate('reveal').store('reveal:options', $extend({link: 'cancel'}, options));
},
get: function(options){
if (options || !this.retrieve('reveal')){
if (options || !this.retrieve('reveal:options')) this.set('reveal', options);
this.store('reveal', new Fx.Reveal(this, this.retrieve('reveal:options')));
}
return this.retrieve('reveal');
}
};
Element.Properties.dissolve = Element.Properties.reveal;
Element.implement({
reveal: function(options){
this.get('reveal', options).reveal();
return this;
},
dissolve: function(options){
this.get('reveal', options).dissolve();
return this;
}
});
/*
Script: MultipleOpenAccordion.js
Creates a Mootools Fx.Accordion that allows the user to open more than one element.
License:
http://clientside.cnet.com/wiki/cnet-libraries#license
*/
var MultipleOpenAccordion = new Class({
Implements: [Options, Events, Chain],
options: {
togglers: [],
elements: [],
openAll: true,
firstElementsOpen: [0],
fixedHeight: false,
fixedWidth: false,
height: true,
opacity: true,
width: false
//	onActive: $empty,
//	onBackground: $empty
},
togglers: [],
elements: [],
initialize: function(container, options){
this.setOptions(options);
this.container = $(container);
elements = $$(options.elements);
$$(options.togglers).each(function(toggler, idx){
this.addSection(toggler, elements[idx], idx);
}, this);
if (this.togglers.length) {
if (this.options.openAll) this.showAll();
else this.openSections(this.options.firstElementsOpen);
}
},
addSection: function(toggler, element, pos){
toggler = $(toggler);
element = $(element);
var test = this.togglers.contains(toggler);
var len = this.togglers.length;
this.togglers.include(toggler);
this.elements.include(element);
if (len && (!test || pos)){
pos = $pick(pos - 1, len - 1);
toggler.inject(this.elements[pos], 'after');
element.inject(toggler, 'after');
} else if (this.container && !test){
toggler.inject(this.container);
element.inject(this.container);
}
var idx = this.togglers.indexOf(toggler);
toggler.addEvent('click', this.toggleSection.bind(this, idx));
var mode;
if (this.options.height && this.options.width) mode = "both";
else mode = (this.options.height)?"vertical":"horizontal";
element.store('reveal', new Fx.Reveal(element, {
transitionOpacity: this.options.opacity,
mode: mode,
heightOverride: this.options.fixedHeight,
widthOverride: this.options.fixedWidth
}));
return this;
},
onComplete: function(idx, callChain){
this.fireEvent(this.elements[idx].isVisible()?'onActive':'onBackground', [this.togglers[idx], this.elements[idx]]);
this.callChain();
return this;
},
showSection: function(idx, useFx){
alert("showing");
this.toggleSection(idx, useFx, true);
},
hideSection: function(idx, useFx){
this.toggleSection(idx, useFx, false);
},
toggleSection: function(idx, useFx, show, callChain){
var method = show?'reveal':$defined(show)?'dissolve':'toggle';
callChain = $pick(callChain, true);
if($pick(useFx, true)) {
this.elements[idx].retrieve('reveal')[method]().chain(
this.onComplete.bind(this, [idx, callChain])
);
} else {
if (method == "toggle") el.togglek();
else el[method == "reveal"?'show':'hide']();
this.onComplete(idx, callChain);
}
return this;
},
toggleAll: function(useFx, show){
var method = show?'reveal':$chk(show)?'disolve':'toggle';
var last = this.elements.getLast();
this.elements.each(function(el, idx){
this.toggleSection(idx, useFx, show, el == last);
}, this);
return this;
},
toggleSections: function(sections, useFx, show) {
last = sections.getLast();
this.elements.each(function(el,idx){
this.toggleSection(idx, useFx, sections.contains(idx), show, idx == last);
}, this);
return this;
},
openSections: function(sections, useFx){
this.toggleSections(sections, useFx, true);
},
closeSections: function(sections, useFx){
this.toggleSections(sections, useFx, false);
},
showAll: function(useFx){
return this.toggleAll(useFx, true);
},
hideAll: function(useFx){
return this.toggleAll(useFx, false);
}
});
/*
Script: SimpleCarousel.js
Builds a carousel object that manages the basic functions of a generic carousel (a carousel	here being a collection of "slides" that play from one to the next, with a collection of "buttons" that reference each slide).
License:
http://clientside.cnet.com/wiki/cnet-libraries#license
*/
var SimpleCarousel = new Class({
Implements: [Options, Events],
options: {
//	onRotate: $empty,
//	onStop: $empty,
//	onAutoPlay: $empty,
//	onShowSlide: $empty,
slideInterval: 4000,
transitionDuration: 700,
startIndex: 0,
buttonOnClass: "selected",
buttonOffClass: "off",
rotateAction: "none",
rotateActionDuration: 100,
autoplay: true
},
initialize: function(container, slides, buttons, options){
this.container = $(container);
if(this.container.hasClass('hasCarousel')) return false;
this.setOptions(options);
this.container.addClass('hasCarousel');
this.slides = $$(slides);
this.buttons = $$(buttons);
this.createFx();
this.showSlide(this.options.startIndex);
if(this.options.autoplay) this.autoplay();
if(this.options.rotateAction != 'none') this.setupAction(this.options.rotateAction);
return this;
},
toElement: function(){
return this.container;
},
setupAction: function(action) {
this.buttons.each(function(el, idx){
$(el).addEvent(action, function() {
this.slideFx.setOptions(this.slideFx.options, {duration: this.options.rotateActionDuration});
if(this.currentSlide != idx) this.showSlide(idx);
this.stop();
}.bind(this));
}, this);
},
createFx: function(){
if (!this.slideFx) this.slideFx = new Fx.Elements(this.slides, {duration: this.options.transitionDuration});
this.slides.each(function(slide){
slide.setStyle('opacity',0);
});
},
showSlide: function(slideIndex){
var action = {};
this.slides.each(function(slide, index){
if(index == slideIndex && index != this.currentSlide){ //show
$(this.buttons[index]).swapClass(this.options.buttonOffClass, this.options.buttonOnClass);
action[index.toString()] = {
opacity: 1
};
} else {
$(this.buttons[index]).swapClass(this.options.buttonOnClass, this.options.buttonOffClass);
action[index.toString()] = {
opacity:0
};
}
}, this);
this.fireEvent('onShowSlide', slideIndex);
this.currentSlide = slideIndex;
this.slideFx.start(action);
return this;
},
autoplay: function(){
this.slideshowInt = this.rotate.periodical(this.options.slideInterval, this);
this.fireEvent('onAutoPlay');
return this;
},
stop: function(){
$clear(this.slideshowInt);
this.fireEvent('onStop');
return this;
},
rotate: function(){
current = this.currentSlide;
next = (current+1 >= this.slides.length) ? 0 : current+1;
this.showSlide(next);
this.fireEvent('onRotate', next);
return this;
}
});
// cmscript: tipsx3 
/*
Script: TipsX3.js
Tooltips, BubbleTips, whatever they are, they will appear on mouseover
License:
MIT-style license.
Credits:
The idea behind Tips.js is based on Bubble Tooltips (<http://web-graphics.com/mtarchive/001717.php>) by Alessandro Fulcitiniti <http://web-graphics.com>
TipsX3.js is based on Tips.js, with slight modifications, by razvan@e-magine.ro
*/
/*
Class: TipsX3
Display a tip on any element with a title and/or href.
Note:
Tips requires an XHTML doctype.
Arguments:
elements - a collection of elements to apply the tooltips to on mouseover.
options - an object. See options Below.
Options:
maxTitleChars - the maximum number of characters to display in the title of the tip. defaults to 30.
onShow - optionally you can alter the default onShow behaviour with this option (like displaying a fade in effect);
onHide - optionally you can alter the default onHide behaviour with this option (like displaying a fade out effect);
showDelay - the delay the onShow method is called. (defaults to 100 ms)
hideDelay - the delay the onHide method is called. (defaults to 100 ms)
className - the prefix for your tooltip classNames. defaults to 'tool'.
the whole tooltip will have as classname: tool-tip
the title will have as classname: tool-title
the text will have as classname: tool-text
offsets - the distance of your tooltip from the mouse. an Object with x/y properties.
fixed - if set to true, the toolTip will not follow the mouse.
loadingText - text to display as a title while loading an AJAX tooltip.
errTitle, errText - text to display when there's a problem with the AJAX request.
Example:
(start code)
<img src="/images/i.png" title="The body of the tooltip is stored in the title" class="toolTipImg"/>
<script>
var myTips = new Tips($$('.toolTipImg'), {
maxTitleChars: 50	//I like my captions a little long
});
</script>
(end)
Note:
The title of the element will always be used as the tooltip body. If you put :: on your title, the text before :: will become the tooltip title.
If you put DOM:someElementID in your title, $('someElementID').innerHTML will be used as your tooltip contents (same syntax as above).
If you put AJAX:http://www.example.com/path/to/ajax_file.php in your title, the response text will be used as tooltip contents (same syntax as above). Either absolute or relative paths are ok.
*/
var TipsX3 = new Class({
options: { // modded for X3
onShow: function(tip){
tip.setStyle('visibility', 'visible');
},
onHide: function(tip){
tip.setStyle('visibility', 'hidden');
},
maxTitleChars: 30,
showDelay: 100,
hideDelay: 100,
className: 'tool',
offsets: {'x': 16, 'y': 16},
fixed: false,
loadingText: 'Loading...',
errTitle: 'Oops..',
errText: 'There was a problem retrieving the tooltip.'
},
initialize: function(elements, options){
this.setOptions(options);
this.toolTip = new Element('div', {
'class': this.options.className + '-tip',
'styles': {
'position': 'absolute',
'top': '0',
'left': '0',
'visibility': 'hidden'
}
}).inject(document.body);
this.wrapper = new Element('div').inject(this.toolTip);
$$(elements).each(this.build, this);
if (this.options.initialize) this.options.initialize.call(this);
},
build: function(el){ // modded for X3
el.$tmp.myTitle = (el.href && el.getTag() == 'a') ? el.href.replace('http://', '') : (el.rel || false);
if (el.title){
// check if we need to extract contents from a DOM element
if (el.title.test('^DOM:', 'i')) {
el.title = $(el.title.split(':')[1].trim()).innerHTML;	
}
// check for an URL to retrieve content from
if (el.title.test('^AJAX:', 'i')) {
el.title = this.options.loadingText + '::' + el.title;
}
var dual = el.title.split('::');
if (dual.length > 1) {
el.$tmp.myTitle = dual[0].trim();
el.$tmp.myText = dual[1].trim();
} else {
el.$tmp.myText = el.title;
}
el.removeAttribute('title');
} else {
el.$tmp.myText = false;
}
if (el.$tmp.myTitle && el.$tmp.myTitle.length > this.options.maxTitleChars) el.$tmp.myTitle = el.$tmp.myTitle.substr(0, this.options.maxTitleChars - 1) + "&hellip;";
el.addEvent('mouseenter', function(event){
this.start(el);
if (!this.options.fixed) this.locate(event);
else this.position(el);
}.bind(this));
if (!this.options.fixed) el.addEvent('mousemove', this.locate.bindWithEvent(this));
var end = this.end.bind(this);
el.addEvent('mouseleave', end);
el.addEvent('trash', end);
},
start: function(el){ // modded for X3
this.wrapper.empty();
// check if we have an AJAX request - if so, show a loading animation and launch the request	
if (el.$tmp.myText && el.$tmp.myText.test('^AJAX:', 'i')) {
//if (this.ajax) this.ajax.cancel();
this.ajax = new Ajax (el.$tmp.myText.replace(/AJAX:/i,''), {
onComplete: function (responseText, responseXML) {
el.title = responseText;
this.build(el);
this.start(el);
}.bind(this),
onFailure: function () {
el.title = this.options.errTitle + '::' + this.options.errText;
this.build(el);
this.start(el);
}.bind(this),
method: 'get'
}).request();	
el.$tmp.myText = '<div class="' + this.options.className + '-loading">&nbsp;</div>';	
}
if (el.$tmp.myTitle){
this.title = new Element('span').inject(
new Element('div', {'class': this.options.className + '-title'}).inject(this.wrapper)
).setHTML(el.$tmp.myTitle);
}
if (el.$tmp.myText){
this.text = new Element('span').inject(
new Element('div', {'class': this.options.className + '-text'}).inject(this.wrapper)
).setHTML(el.$tmp.myText);
}
$clear(this.timer);
this.timer = this.show.delay(this.options.showDelay, this);
},
end: function(event){
$clear(this.timer);
this.timer = this.hide.delay(this.options.hideDelay, this);
},
position: function(element){
var pos = element.getPosition();
this.toolTip.setStyles({
'left': pos.x + this.options.offsets.x,
'top': pos.y + this.options.offsets.y
});
},
locate: function(event){
var win = {'x': window.getWidth(), 'y': window.getHeight()};
var scroll = {'x': window.getScrollLeft(), 'y': window.getScrollTop()};
var tip = {'x': this.toolTip.offsetWidth, 'y': this.toolTip.offsetHeight};
var prop = {'x': 'left', 'y': 'top'};
for (var z in prop){
var pos = event.page[z] + this.options.offsets[z];
if ((pos + tip[z] - scroll[z]) > win[z]) pos = event.page[z] - this.options.offsets[z] - tip[z];
this.toolTip.setStyle(prop[z], pos);
};
},
show: function(){
if (this.options.timeout) this.timer = this.hide.delay(this.options.timeout, this);
this.fireEvent('onShow', [this.toolTip]);
},
hide: function(){
this.fireEvent('onHide', [this.toolTip]);
}
});
TipsX3.implement(new Events, new Options);
// cmscript: cookie 
// =========================================================================
// Cookie functions
// =========================================================================
/* This function is used to set cookies */
function setCookie(name,value,expires,path,domain,secure) {
document.cookie = name + "=" + escape (value) +
((expires) ? "; expires=" + expires.toGMTString() : "") +
((path) ? "; path=" + path : "") +
((domain) ? "; domain=" + domain : "") + ((secure) ? "; secure" : "");
}
/* This function is used to get cookies */
function getCookie(name) {
var prefix = name + "=";
var start = document.cookie.indexOf(prefix);
if (start==-1) {
return null;
}
var end = document.cookie.indexOf(";", start+prefix.length);
if (end==-1) {
end=document.cookie.length;
}
var value=document.cookie.substring(start+prefix.length, end);
return unescape(value);
}
/* This function is used to delete cookies */
function deleteCookie(name,path,domain) {
if (getCookie(name)) {
document.cookie = name + "=" +
((path) ? "; path=" + path : "") +
((domain) ? "; domain=" + domain : "") +
"; expires=Thu, 01-Jan-70 00:00:01 GMT";
}
}
function setMenuCookie(id, context) {
if (cxlEnv)
cxlEnv.previousMenuCookie = getCookie("subMenu");
setCookie("subMenu", id, "", "/");
}
function revertMenuCookie()
{
if (cxlEnv.previousMenuCookie)
setMenuCookie(cxlEnv.previousMenuCookie);
}
// cmscript: topnav 
/* (c) 2005 CaribMedia
* this module places IFRAME elements behind UL elements
* in order to prevent content to be placed
* on top of the dynamic menus
*/
/*
* @name addMenuEffects
* @description places the IFRAME
* preconditions:
* - there can be only one IFRAME
* - the menu has an id of "nav"
* - the menu is built as a nested list (UL/LI)
* - the script is run in IE
* @author Michiel van der Blonk
* @date Nov 22, 2005
*/
/* anonymous function wrapper, protects global namespace */
(function() {
if (!document.getElementById)
return;
if (!window.MooTools)
return;
window.debugInfo = function(s) {
if (!$('contentPane'))
return;
if (!window.debugmode)
window.debugmode = true;
else
$('contentPane').innerHTML = '';
$('contentPane').innerHTML += s;
};
var addMenuEffects = function(obj, doShim, doHover)
{
/* only in IE */
if (!cxlEnv.isIE5or6 || !obj)
return;
var iframeCode = '<iframe class="menushim" src="about:blank" scrolling="no" frameborder="0"></iframe>';
// add an IFRAME to all UL's in the menu,
// this will make IE display the menu on top of all other elements
if (doShim)
{
$(obj).getElements('ul').each(function(tag) {
tag.innerHTML=(iframeCode + tag.innerHTML);
//tag.addEvent('mouseover', function() {tag.addClass('over');});
//tag.addEvent('mouseout', function() {tag.removeClass('over');});
});
}
// resize the iframe
$(obj).getElements('li ul').each(function(tag) {
tag.addEvent('mouseenter', function() {
tag.getElements('iframe')[0].setStyle('height', tag.clientHeight -1 + 'px');
});
});
};
/*
* @name startList
* @description adds the menu effects for several menus
* @author Michiel van der Blonk
* @date Nov 22, 2005
*/
var startList = function()
{
['dynamicMenu', 'nav', 'subMenu'].each(function(item) {
if ($(item))
addMenuEffects($(item), true, true);
});
};
/*
* @name addEvent
* @description adds an event handler to an element
* this way multiple functions can be triggered by an event
* @author Michiel van der Blonk
* @date Nov 22, 2005
*/
if (!window.addEvent)
{
window.addEvent = function(obj, evType, fn)
{
var ret = false;
// MB:check if fn exists
if (!fn || typeof fn != 'function')
return false;
// adds an eventListener for browsers which support it
// Written by Scott Andrew: nice one, Scott
if (obj.addEventListener)
{
obj.addEventListener(evType, fn, true);
ret = true;
}
else
if (obj.attachEvent)
{
var r = obj.attachEvent("on"+evType,fn);
ret = r;
}
return ret;
};
}
var dragStuff = function()
{
// if mootools is loaded, use the short version
if (window.MooTools && $chk(Drag))
$$('.drag').makeDraggable();
else
{
if (!window.Drag || !document.getElementById)
return;
draggableItems = ['obj1', 'extra3'];
for (var i=0; i < draggableItems.length; i++) {
var dragger = document.getElementById(draggableItems[i]);
if (dragger) {
dragger.style.position = 'relative';
Drag.init(dragger, null);
}
}
}
};
// window.addEvent('load', startList);
window.addEvent('load', dragStuff);
window.addEvent('load', function(){setMenuCookie(-1);});
})();
// cmscript: swfobject 
/*! SWFObject v2.1 <http://code.google.com/p/swfobject/>
Copyright (c) 2007-2008 Geoff Stearns, Michael Williams, and Bobby van der Sluis
This software is released under the MIT License <http://www.opensource.org/licenses/mit-license.php>
*/
var swfobject = function() {
var UNDEF = "undefined",
OBJECT = "object",
SHOCKWAVE_FLASH = "Shockwave Flash",
SHOCKWAVE_FLASH_AX = "ShockwaveFlash.ShockwaveFlash",
FLASH_MIME_TYPE = "application/x-shockwave-flash",
EXPRESS_INSTALL_ID = "SWFObjectExprInst",
win = window,
doc = document,
nav = navigator,
domLoadFnArr = [],
regObjArr = [],
objIdArr = [],
listenersArr = [],
script,
timer = null,
storedAltContent = null,
storedAltContentId = null,
isDomLoaded = false,
isExpressInstallActive = false;
/* Centralized function for browser feature detection
- Proprietary feature detection (conditional compiling) is used to detect Internet Explorer's features
- User agent string detection is only used when no alternative is possible
- Is executed directly for optimal performance
*/	
var ua = function() {
var w3cdom = typeof doc.getElementById != UNDEF && typeof doc.getElementsByTagName != UNDEF && typeof doc.createElement != UNDEF,
playerVersion = [0,0,0],
d = null;
if (typeof nav.plugins != UNDEF && typeof nav.plugins[SHOCKWAVE_FLASH] == OBJECT) {
d = nav.plugins[SHOCKWAVE_FLASH].description;
if (d && !(typeof nav.mimeTypes != UNDEF && nav.mimeTypes[FLASH_MIME_TYPE] && !nav.mimeTypes[FLASH_MIME_TYPE].enabledPlugin)) { // navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin indicates whether plug-ins are enabled or disabled in Safari 3+
d = d.replace(/^.*\s+(\S+\s+\S+$)/, "$1");
playerVersion[0] = parseInt(d.replace(/^(.*)\..*$/, "$1"), 10);
playerVersion[1] = parseInt(d.replace(/^.*\.(.*)\s.*$/, "$1"), 10);
playerVersion[2] = /r/.test(d) ? parseInt(d.replace(/^.*r(.*)$/, "$1"), 10) : 0;
}
}
else if (typeof win.ActiveXObject != UNDEF) {
var a = null, fp6Crash = false;
try {
a = new ActiveXObject(SHOCKWAVE_FLASH_AX + ".7");
}
catch(e) {
try { 
a = new ActiveXObject(SHOCKWAVE_FLASH_AX + ".6");
playerVersion = [6,0,21];
a.AllowScriptAccess = "always";	// Introduced in fp6.0.47
}
catch(e) {
if (playerVersion[0] == 6) {
fp6Crash = true;
}
}
if (!fp6Crash) {
try {
a = new ActiveXObject(SHOCKWAVE_FLASH_AX);
}
catch(e) {}
}
}
if (!fp6Crash && a) { // a will return null when ActiveX is disabled
try {
d = a.GetVariable("$version");	// Will crash fp6.0.21/23/29
if (d) {
d = d.split(" ")[1].split(",");
playerVersion = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];
}
}
catch(e) {}
}
}
var u = nav.userAgent.toLowerCase(),
p = nav.platform.toLowerCase(),
webkit = /webkit/.test(u) ? parseFloat(u.replace(/^.*webkit\/(\d+(\.\d+)?).*$/, "$1")) : false, // returns either the webkit version or false if not webkit
ie = false,
windows = p ? /win/.test(p) : /win/.test(u),
mac = p ? /mac/.test(p) : /mac/.test(u);
/*@cc_on
ie = true;
@if (@_win32)
windows = true;
@elif (@_mac)
mac = true;
@end
@*/
return { w3cdom:w3cdom, pv:playerVersion, webkit:webkit, ie:ie, win:windows, mac:mac };
}();
/* Cross-browser onDomLoad
- Based on Dean Edwards' solution: http://dean.edwards.name/weblog/2006/06/again/
- Will fire an event as soon as the DOM of a page is loaded (supported by Gecko based browsers - like Firefox -, IE, Opera9+, Safari)
*/ 
var onDomLoad = function() {
if (!ua.w3cdom) {
return;
}
addDomLoadEvent(main);
if (ua.ie && ua.win) {
try {	// Avoid a possible Operation Aborted error
doc.write("<scr" + "ipt id=__ie_ondomload defer=true src=//:></scr" + "ipt>"); // String is split into pieces to avoid Norton AV to add code that can cause errors 
script = getElementById("__ie_ondomload");
if (script) {
addListener(script, "onreadystatechange", checkReadyState);
}
}
catch(e) {}
}
if (ua.webkit && typeof doc.readyState != UNDEF) {
timer = setInterval(function() { if (/loaded|complete/.test(doc.readyState)) { callDomLoadFunctions(); }}, 10);
}
if (typeof doc.addEventListener != UNDEF) {
doc.addEventListener("DOMContentLoaded", callDomLoadFunctions, null);
}
addLoadEvent(callDomLoadFunctions);
}();
function checkReadyState() {
if (script.readyState == "complete") {
script.parentNode.removeChild(script);
callDomLoadFunctions();
}
}
function callDomLoadFunctions() {
if (isDomLoaded) {
return;
}
if (ua.ie && ua.win) { // Test if we can really add elements to the DOM; we don't want to fire it too early
var s = createElement("span");
try { // Avoid a possible Operation Aborted error
var t = doc.getElementsByTagName("body")[0].appendChild(s);
t.parentNode.removeChild(t);
}
catch (e) {
return;
}
}
isDomLoaded = true;
if (timer) {
clearInterval(timer);
timer = null;
}
var dl = domLoadFnArr.length;
for (var i = 0; i < dl; i++) {
domLoadFnArr[i]();
}
}
function addDomLoadEvent(fn) {
if (isDomLoaded) {
fn();
}
else { 
domLoadFnArr[domLoadFnArr.length] = fn; // Array.push() is only available in IE5.5+
}
}
/* Cross-browser onload
- Based on James Edwards' solution: http://brothercake.com/site/resources/scripts/onload/
- Will fire an event as soon as a web page including all of its assets are loaded 
*/
function addLoadEvent(fn) {
if (typeof win.addEventListener != UNDEF) {
win.addEventListener("load", fn, false);
}
else if (typeof doc.addEventListener != UNDEF) {
doc.addEventListener("load", fn, false);
}
else if (typeof win.attachEvent != UNDEF) {
addListener(win, "onload", fn);
}
else if (typeof win.onload == "function") {
var fnOld = win.onload;
win.onload = function() {
fnOld();
fn();
};
}
else {
win.onload = fn;
}
}
/* Main function
- Will preferably execute onDomLoad, otherwise onload (as a fallback)
*/
function main() { // Static publishing only
var rl = regObjArr.length;
for (var i = 0; i < rl; i++) { // For each registered object element
var id = regObjArr[i].id;
if (ua.pv[0] > 0) {
var obj = getElementById(id);
if (obj) {
regObjArr[i].width = obj.getAttribute("width") ? obj.getAttribute("width") : "0";
regObjArr[i].height = obj.getAttribute("height") ? obj.getAttribute("height") : "0";
if (hasPlayerVersion(regObjArr[i].swfVersion)) { // Flash plug-in version >= Flash content version: Houston, we have a match!
if (ua.webkit && ua.webkit < 312) { // Older webkit engines ignore the object element's nested param elements
fixParams(obj);
}
setVisibility(id, true);
}
else if (regObjArr[i].expressInstall && !isExpressInstallActive && hasPlayerVersion("6.0.65") && (ua.win || ua.mac)) { // Show the Adobe Express Install dialog if set by the web page author and if supported (fp6.0.65+ on Win/Mac OS only)
showExpressInstall(regObjArr[i]);
}
else { // Flash plug-in and Flash content version mismatch: display alternative content instead of Flash content
displayAltContent(obj);
}
}
}
else {	// If no fp is installed, we let the object element do its job (show alternative content)
setVisibility(id, true);
}
}
}
/* Fix nested param elements, which are ignored by older webkit engines
- This includes Safari up to and including version 1.2.2 on Mac OS 10.3
- Fall back to the proprietary embed element
*/
function fixParams(obj) {
var nestedObj = obj.getElementsByTagName(OBJECT)[0];
if (nestedObj) {
var e = createElement("embed"), a = nestedObj.attributes;
if (a) {
var al = a.length;
for (var i = 0; i < al; i++) {
if (a[i].nodeName == "DATA") {
e.setAttribute("src", a[i].nodeValue);
}
else {
e.setAttribute(a[i].nodeName, a[i].nodeValue);
}
}
}
var c = nestedObj.childNodes;
if (c) {
var cl = c.length;
for (var j = 0; j < cl; j++) {
if (c[j].nodeType == 1 && c[j].nodeName == "PARAM") {
e.setAttribute(c[j].getAttribute("name"), c[j].getAttribute("value"));
}
}
}
obj.parentNode.replaceChild(e, obj);
}
}
/* Show the Adobe Express Install dialog
- Reference: http://www.adobe.com/cfusion/knowledgebase/index.cfm?id=6a253b75
*/
function showExpressInstall(regObj) {
isExpressInstallActive = true;
var obj = getElementById(regObj.id);
if (obj) {
if (regObj.altContentId) {
var ac = getElementById(regObj.altContentId);
if (ac) {
storedAltContent = ac;
storedAltContentId = regObj.altContentId;
}
}
else {
storedAltContent = abstractAltContent(obj);
}
if (!(/%$/.test(regObj.width)) && parseInt(regObj.width, 10) < 310) {
regObj.width = "310";
}
if (!(/%$/.test(regObj.height)) && parseInt(regObj.height, 10) < 137) {
regObj.height = "137";
}
doc.title = doc.title.slice(0, 47) + " - Flash Player Installation";
var pt = ua.ie && ua.win ? "ActiveX" : "PlugIn",
dt = doc.title,
fv = "MMredirectURL=" + win.location + "&MMplayerType=" + pt + "&MMdoctitle=" + dt,
replaceId = regObj.id;
// For IE when a SWF is loading (AND: not available in cache) wait for the onload event to fire to remove the original object element
// In IE you cannot properly cancel a loading SWF file without breaking browser load references, also obj.onreadystatechange doesn't work
if (ua.ie && ua.win && obj.readyState != 4) {
var newObj = createElement("div");
replaceId += "SWFObjectNew";
newObj.setAttribute("id", replaceId);
obj.parentNode.insertBefore(newObj, obj); // Insert placeholder div that will be replaced by the object element that loads expressinstall.swf
obj.style.display = "none";
var fn = function() {
obj.parentNode.removeChild(obj);
};
addListener(win, "onload", fn);
}
createSWF({ data:regObj.expressInstall, id:EXPRESS_INSTALL_ID, width:regObj.width, height:regObj.height }, { flashvars:fv }, replaceId);
}
}
/* Functions to abstract and display alternative content
*/
function displayAltContent(obj) {
if (ua.ie && ua.win && obj.readyState != 4) {
// For IE when a SWF is loading (AND: not available in cache) wait for the onload event to fire to remove the original object element
// In IE you cannot properly cancel a loading SWF file without breaking browser load references, also obj.onreadystatechange doesn't work
var el = createElement("div");
obj.parentNode.insertBefore(el, obj); // Insert placeholder div that will be replaced by the alternative content
el.parentNode.replaceChild(abstractAltContent(obj), el);
obj.style.display = "none";
var fn = function() {
obj.parentNode.removeChild(obj);
};
addListener(win, "onload", fn);
}
else {
obj.parentNode.replaceChild(abstractAltContent(obj), obj);
}
} 
function abstractAltContent(obj) {
var ac = createElement("div");
if (ua.win && ua.ie) {
ac.innerHTML = obj.innerHTML;
}
else {
var nestedObj = obj.getElementsByTagName(OBJECT)[0];
if (nestedObj) {
var c = nestedObj.childNodes;
if (c) {
var cl = c.length;
for (var i = 0; i < cl; i++) {
if (!(c[i].nodeType == 1 && c[i].nodeName == "PARAM") && !(c[i].nodeType == 8)) {
ac.appendChild(c[i].cloneNode(true));
}
}
}
}
}
return ac;
}
/* Cross-browser dynamic SWF creation
*/
function createSWF(attObj, parObj, id) {
var r, el = getElementById(id);
if (el) {
if (typeof attObj.id == UNDEF) { // if no 'id' is defined for the object element, it will inherit the 'id' from the alternative content
attObj.id = id;
}
if (ua.ie && ua.win) { // IE, the object element and W3C DOM methods do not combine: fall back to outerHTML
var att = "";
for (var i in attObj) {
if (attObj[i] != Object.prototype[i]) { // Filter out prototype additions from other potential libraries, like Object.prototype.toJSONString = function() {}
if (i.toLowerCase() == "data") {
parObj.movie = attObj[i];
}
else if (i.toLowerCase() == "styleclass") { // 'class' is an ECMA4 reserved keyword
att += ' class="' + attObj[i] + '"';
}
else if (i.toLowerCase() != "classid") {
att += ' ' + i + '="' + attObj[i] + '"';
}
}
}
var par = "";
for (var j in parObj) {
if (parObj[j] != Object.prototype[j]) { // Filter out prototype additions from other potential libraries
par += '<param name="' + j + '" value="' + parObj[j] + '" />';
}
}
el.outerHTML = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"' + att + '>' + par + '</object>';
objIdArr[objIdArr.length] = attObj.id; // Stored to fix object 'leaks' on unload (dynamic publishing only)
r = getElementById(attObj.id);	
}
else if (ua.webkit && ua.webkit < 312) { // Older webkit engines ignore the object element's nested param elements: fall back to the proprietary embed element
var e = createElement("embed");
e.setAttribute("type", FLASH_MIME_TYPE);
for (var k in attObj) {
if (attObj[k] != Object.prototype[k]) { // Filter out prototype additions from other potential libraries
if (k.toLowerCase() == "data") {
e.setAttribute("src", attObj[k]);
}
else if (k.toLowerCase() == "styleclass") { // 'class' is an ECMA4 reserved keyword
e.setAttribute("class", attObj[k]);
}
else if (k.toLowerCase() != "classid") { // Filter out IE specific attribute
e.setAttribute(k, attObj[k]);
}
}
}
for (var l in parObj) {
if (parObj[l] != Object.prototype[l]) { // Filter out prototype additions from other potential libraries
if (l.toLowerCase() != "movie") { // Filter out IE specific param element
e.setAttribute(l, parObj[l]);
}
}
}
el.parentNode.replaceChild(e, el);
r = e;
}
else { // Well-behaving browsers
var o = createElement(OBJECT);
o.setAttribute("type", FLASH_MIME_TYPE);
for (var m in attObj) {
if (attObj[m] != Object.prototype[m]) { // Filter out prototype additions from other potential libraries
if (m.toLowerCase() == "styleclass") { // 'class' is an ECMA4 reserved keyword
o.setAttribute("class", attObj[m]);
}
else if (m.toLowerCase() != "classid") { // Filter out IE specific attribute
o.setAttribute(m, attObj[m]);
}
}
}
for (var n in parObj) {
if (parObj[n] != Object.prototype[n] && n.toLowerCase() != "movie") { // Filter out prototype additions from other potential libraries and IE specific param element
createObjParam(o, n, parObj[n]);
}
}
el.parentNode.replaceChild(o, el);
r = o;
}
}
return r;
}
function createObjParam(el, pName, pValue) {
var p = createElement("param");
p.setAttribute("name", pName);	
p.setAttribute("value", pValue);
el.appendChild(p);
}
/* Cross-browser SWF removal
- Especially needed to safely and completely remove a SWF in Internet Explorer
*/
function removeSWF(id) {
var obj = getElementById(id);
if (obj && (obj.nodeName == "OBJECT" || obj.nodeName == "EMBED")) {
if (ua.ie && ua.win) {
if (obj.readyState == 4) {
removeObjectInIE(id);
}
else {
win.attachEvent("onload", function() {
removeObjectInIE(id);
});
}
}
else {
obj.parentNode.removeChild(obj);
}
}
}
function removeObjectInIE(id) {
var obj = getElementById(id);
if (obj) {
for (var i in obj) {
if (typeof obj[i] == "function") {
obj[i] = null;
}
}
obj.parentNode.removeChild(obj);
}
}
/* Functions to optimize JavaScript compression
*/
function getElementById(id) {
var el = null;
try {
el = doc.getElementById(id);
}
catch (e) {}
return el;
}
function createElement(el) {
return doc.createElement(el);
}
/* Updated attachEvent function for Internet Explorer
- Stores attachEvent information in an Array, so on unload the detachEvent functions can be called to avoid memory leaks
*/	
function addListener(target, eventType, fn) {
target.attachEvent(eventType, fn);
listenersArr[listenersArr.length] = [target, eventType, fn];
}
/* Flash Player and SWF content version matching
*/
function hasPlayerVersion(rv) {
var pv = ua.pv, v = rv.split(".");
v[0] = parseInt(v[0], 10);
v[1] = parseInt(v[1], 10) || 0; // supports short notation, e.g. "9" instead of "9.0.0"
v[2] = parseInt(v[2], 10) || 0;
return (pv[0] > v[0] || (pv[0] == v[0] && pv[1] > v[1]) || (pv[0] == v[0] && pv[1] == v[1] && pv[2] >= v[2])) ? true : false;
}
/* Cross-browser dynamic CSS creation
- Based on Bobby van der Sluis' solution: http://www.bobbyvandersluis.com/articles/dynamicCSS.php
*/	
function createCSS(sel, decl) {
if (ua.ie && ua.mac) {
return;
}
var h = doc.getElementsByTagName("head")[0], s = createElement("style");
s.setAttribute("type", "text/css");
s.setAttribute("media", "screen");
if (!(ua.ie && ua.win) && typeof doc.createTextNode != UNDEF) {
s.appendChild(doc.createTextNode(sel + " {" + decl + "}"));
}
h.appendChild(s);
if (ua.ie && ua.win && typeof doc.styleSheets != UNDEF && doc.styleSheets.length > 0) {
var ls = doc.styleSheets[doc.styleSheets.length - 1];
if (typeof ls.addRule == OBJECT) {
ls.addRule(sel, decl);
}
}
}
function setVisibility(id, isVisible) {
var v = isVisible ? "visible" : "hidden";
if (isDomLoaded && getElementById(id)) {
getElementById(id).style.visibility = v;
}
else {
createCSS("#" + id, "visibility:" + v);
}
}
/* Filter to avoid XSS attacks 
*/
function urlEncodeIfNecessary(s) {
var regex = /[\\\"<>\.;]/;
var hasBadChars = regex.exec(s) != null;
return hasBadChars ? encodeURIComponent(s) : s;
}
/* Release memory to avoid memory leaks caused by closures, fix hanging audio/video threads and force open sockets/NetConnections to disconnect (Internet Explorer only)
*/
var cleanup = function() {
if (ua.ie && ua.win) {
window.attachEvent("onunload", function() {
// remove listeners to avoid memory leaks
var ll = listenersArr.length;
for (var i = 0; i < ll; i++) {
listenersArr[i][0].detachEvent(listenersArr[i][1], listenersArr[i][2]);
}
// cleanup dynamically embedded objects to fix audio/video threads and force open sockets and NetConnections to disconnect
var il = objIdArr.length;
for (var j = 0; j < il; j++) {
removeSWF(objIdArr[j]);
}
// cleanup library's main closures to avoid memory leaks
for (var k in ua) {
ua[k] = null;
}
ua = null;
for (var l in swfobject) {
swfobject[l] = null;
}
swfobject = null;
});
}
}();
return {
/* Public API
- Reference: http://code.google.com/p/swfobject/wiki/SWFObject_2_0_documentation
*/ 
registerObject: function(objectIdStr, swfVersionStr, xiSwfUrlStr) {
if (!ua.w3cdom || !objectIdStr || !swfVersionStr) {
return;
}
var regObj = {};
regObj.id = objectIdStr;
regObj.swfVersion = swfVersionStr;
regObj.expressInstall = xiSwfUrlStr ? xiSwfUrlStr : false;
regObjArr[regObjArr.length] = regObj;
setVisibility(objectIdStr, false);
},
getObjectById: function(objectIdStr) {
var r = null;
if (ua.w3cdom) {
var o = getElementById(objectIdStr);
if (o) {
var n = o.getElementsByTagName(OBJECT)[0];
if (!n || (n && typeof o.SetVariable != UNDEF)) {
r = o;
}
else if (typeof n.SetVariable != UNDEF) {
r = n;
}
}
}
return r;
},
embedSWF: function(swfUrlStr, replaceElemIdStr, widthStr, heightStr, swfVersionStr, xiSwfUrlStr, flashvarsObj, parObj, attObj) {
if (!ua.w3cdom || !swfUrlStr || !replaceElemIdStr || !widthStr || !heightStr || !swfVersionStr) {
return;
}
widthStr += ""; // Auto-convert to string
heightStr += "";
if (hasPlayerVersion(swfVersionStr)) {
setVisibility(replaceElemIdStr, false);
var att = {};
if (attObj && typeof attObj === OBJECT) {
for (var i in attObj) {
if (attObj[i] != Object.prototype[i]) { // Filter out prototype additions from other potential libraries
att[i] = attObj[i];
}
}
}
att.data = swfUrlStr;
att.width = widthStr;
att.height = heightStr;
var par = {}; 
if (parObj && typeof parObj === OBJECT) {
for (var j in parObj) {
if (parObj[j] != Object.prototype[j]) { // Filter out prototype additions from other potential libraries
par[j] = parObj[j];
}
}
}
if (flashvarsObj && typeof flashvarsObj === OBJECT) {
for (var k in flashvarsObj) {
if (flashvarsObj[k] != Object.prototype[k]) { // Filter out prototype additions from other potential libraries
if (typeof par.flashvars != UNDEF) {
par.flashvars += "&" + k + "=" + flashvarsObj[k];
}
else {
par.flashvars = k + "=" + flashvarsObj[k];
}
}
}
}
addDomLoadEvent(function() {
createSWF(att, par, replaceElemIdStr);
if (att.id == replaceElemIdStr) {
setVisibility(replaceElemIdStr, true);
}
});
}
else if (xiSwfUrlStr && !isExpressInstallActive && hasPlayerVersion("6.0.65") && (ua.win || ua.mac)) {
isExpressInstallActive = true; // deferred execution
setVisibility(replaceElemIdStr, false);
addDomLoadEvent(function() {
var regObj = {};
regObj.id = regObj.altContentId = replaceElemIdStr;
regObj.width = widthStr;
regObj.height = heightStr;
regObj.expressInstall = xiSwfUrlStr;
showExpressInstall(regObj);
});
}
},
getFlashPlayerVersion: function() {
return { major:ua.pv[0], minor:ua.pv[1], release:ua.pv[2] };
},
hasFlashPlayerVersion: hasPlayerVersion,
createSWF: function(attObj, parObj, replaceElemIdStr) {
if (ua.w3cdom) {
return createSWF(attObj, parObj, replaceElemIdStr);
}
else {
return undefined;
}
},
removeSWF: function(objElemIdStr) {
if (ua.w3cdom) {
removeSWF(objElemIdStr);
}
},
createCSS: function(sel, decl) {
if (ua.w3cdom) {
createCSS(sel, decl);
}
},
addDomLoadEvent: addDomLoadEvent,
addLoadEvent: addLoadEvent,
getQueryParamValue: function(param) {
var q = doc.location.search || doc.location.hash;
if (param == null) {
return urlEncodeIfNecessary(q);
}
if (q) {
var pairs = q.substring(1).split("&");
for (var i = 0; i < pairs.length; i++) {
if (pairs[i].substring(0, pairs[i].indexOf("=")) == param) {
return urlEncodeIfNecessary(pairs[i].substring((pairs[i].indexOf("=") + 1)));
}
}
}
return "";
},
// For internal usage only
expressInstallCallback: function() {
if (isExpressInstallActive && storedAltContent) {
var obj = getElementById(EXPRESS_INSTALL_ID);
if (obj) {
obj.parentNode.replaceChild(storedAltContent, obj);
if (storedAltContentId) {
setVisibility(storedAltContentId, true);
if (ua.ie && ua.win) {
storedAltContent.style.display = "block";
}
}
storedAltContent = null;
storedAltContentId = null;
isExpressInstallActive = false;
}
} 
}
};
}();
// cmscript: calendar 
// Calendar: a Javascript class for Mootools that adds accessible and unobtrusive date pickers to your form elements <http://electricprism.com/aeron/calendar>
// Calendar RC4, Copyright (c) 2007 Aeron Glemann <http://electricprism.com/aeron>, MIT Style License.
// Mootools 1.2 compatibility by Davorin Šego
var Calendar = new Class({	
Implements: Options,
options: {
blocked: [], // blocked dates 
classes: [], // ['calendar', 'prev', 'next', 'month', 'year', 'today', 'invalid', 'valid', 'inactive', 'active', 'hover', 'hilite']
days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], // days of the week starting at sunday
direction: 0, // -1 past, 0 past + future, 1 future
draggable: true,
months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
navigation: 1, // 0 = no nav; 1 = single nav for month; 2 = dual nav for month and year
offset: 0, // first day of the week: 0 = sunday, 1 = monday, etc..
onHideStart: Class.empty,
onHideComplete: Class.empty,
onShowStart: Class.empty,
onShowComplete: Class.empty,
pad: 1, // padding between multiple calendars
tweak: {x: 0, y: 0}, // tweak calendar positioning
permanent: false,
parentNode: false
},
// initialize: calendar constructor
// @param obj (obj) a js object containing the form elements and format strings { id: 'format', id: 'format' etc }
// @param props (obj) optional properties
initialize: function(obj, options) {
// basic error checking
if (!obj) { return false; }
this.setOptions(options);
// create our classes array
var keys = ['calendar', 'prev', 'next', 'month', 'year', 'today', 'invalid', 'valid', 'inactive', 'active', 'hover', 'hilite'];
var values = keys.map(function(key, i) {
if (this.options.classes[i]) {
if (this.options.classes[i].length) { key = this.options.classes[i]; }
}
return key;
}, this);
this.classes = values.associate(keys);
if (this.options.parentNode)
var pnode = $(this.options.parentNode);
else
var pnode = document.body;
var posStyle = 'absolute';
if (this.options.parentNode && this.options.permanent)
var posStyle = 'static';
// create cal element with css styles required for proper cal functioning
this.calendar = new Element('div', { 
'styles': { left: '-1000px', opacity: 0, position: posStyle, top: '-1000px', zIndex: 1000 }
}).addClass(this.classes.calendar).injectInside(pnode);
// ie 6 needs a transparent iframe underneath the calendar in order to not allow select elements to render through
if (window.ie6) {
this.iframe = new Element('iframe', { 
'styles': { left: '-1000px', position: 'absolute', top: '-1000px', zIndex: 999 }
}).injectInside(document.body);
this.iframe.style.filter = 'progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)';
}
// initialize fade method
this.fx = new Fx.Tween(this.calendar, {
onStart: function() { 
if (this.calendar.getStyle('opacity') == 0) { // show
if (window.ie6) { this.iframe.setStyle('display', 'block'); }
this.calendar.setStyle('display', 'block');
this.fireEvent('onShowStart', this.element);
}
else { // hide
this.fireEvent('onHideStart', this.element);
}
}.bind(this),
onComplete: function() { 
if (this.calendar.getStyle('opacity') == 0) { // hidden
this.calendar.setStyle('display', 'none');
if (window.ie6) { this.iframe.setStyle('display', 'none'); }
this.fireEvent('onHideComplete', this.element);
}
else { // shown
this.fireEvent('onShowComplete', this.element);
}
}.bind(this)
});
// initialize drag method
if (window.Drag && this.options.draggable) {
this.drag = new Drag.Move(this.calendar, { 
onDrag: function() {
if (window.ie6) { this.iframe.setStyles({ left: this.calendar.style.left, top: this.calendar.style.top }); } 
}.bind(this) 
}); 
}
// create calendars array
this.calendars = [];
var id = 0;
var d = new Date(); // today
d.setDate(d.getDate() + this.options.direction.toInt()); // correct today for directional offset
for (var i in obj) {
var cal = { 
button: new Element('button', { 'type': 'button' }),
el: $(i),
els: [],
id: id++,
month: d.getMonth(),
visible: false,
year: d.getFullYear()
};
// fix for bad element (naughty, naughty element!)
if (!this.element(i, obj[i], cal)) { continue; }
cal.el.addClass(this.classes.calendar);
// create cal button
cal.button.addClass(this.classes.calendar).addEvent('click', function(cal) { this.toggle(cal); }.pass(cal, this)).injectAfter(cal.el);
// read in default value
cal.val = this.read(cal);
$extend(cal, this.bounds(cal)); // abs bounds of calendar
$extend(cal, this.values(cal)); // valid days, months, years
this.rebuild(cal);
this.calendars.push(cal); // add to cals array	
}	
},
// blocked: returns an array of blocked days for the month / year
// @param cal (obj)
// @returns blocked days (array)
blocked: function(cal) {
var blocked = [];
var offset = new Date(cal.year, cal.month, 1).getDay(); // day of the week (offset)
var last = new Date(cal.year, cal.month + 1, 0).getDate(); // last day of this month
this.options.blocked.each(function(date){
var values = date.split(' ');
// preparation
for (var i = 0; i <= 3; i++){ 
if (!values[i]){ values[i] = (i == 3) ? '' : '*'; } // make sure blocked date contains values for at least d, m and y
values[i] = values[i].contains(',') ? values[i].split(',') : new Array(values[i]); // split multiple values
var count = values[i].length - 1;
for (var j = count; j >= 0; j--){
if (values[i][j].contains('-')){ // a range
var val = values[i][j].split('-');
for (var k = val[0]; k <= val[1]; k++){
if (!values[i].contains(k)){ values[i].push(k + ''); }
}
values[i].splice(j, 1);
}
}
}
// execution
if (values[2].contains(cal.year + '') || values[2].contains('*')){
if (values[1].contains(cal.month + 1 + '') || values[1].contains('*')){
values[0].each(function(val){ // if blocked value indicates this month / year
if (val > 0){ blocked.push(val.toInt()); } // add date to blocked array
});
if (values[3]){ // optional value for day of week
for (var i = 0; i < last; i++){
var day = (i + offset) % 7;
if (values[3].contains(day + '')){ 
blocked.push(i + 1); // add every date that corresponds to the blocked day of the week to the blocked array
}
}
}
}
}
}, this);
return blocked;
},
// bounds: returns the start / end bounds of the calendar
// @param cal (obj)
// @returns obj	
bounds: function(cal) {
// 1. first we assume the calendar has no bounds (or a thousand years in either direction)
// by default the calendar will accept a millennium in either direction
var start = new Date(1000, 0, 1); // jan 1, 1000
var end = new Date(2999, 11, 31); // dec 31, 2999
// 2. but if the cal is one directional we adjust accordingly
var date = new Date().getDate() + this.options.direction.toInt();
if (this.options.direction > 0) {
start = new Date();
start.setDate(date + this.options.pad * cal.id);
}
if (this.options.direction < 0) {
end = new Date();
end.setDate(date - this.options.pad * (this.calendars.length - cal.id - 1));
}
// 3. then we can further filter the limits by using the pre-existing values in the selects
cal.els.each(function(el) {	
if (el.get('tag') == 'select') {	
if (el.format.test('(y|Y)')) { // search for a year select
var years = [];
el.getChildren().each(function(option) { // get options
var values = this.unformat(option.value, el.format);
if (!years.contains(values[0])) { years.push(values[0]); } // add to years array
}, this);
years.sort(this.sort);
if (years[0] > start.getFullYear()) { 
d = new Date(years[0], start.getMonth() + 1, 0); // last day of new month
if (start.getDate() > d.getDate()) { start.setDate(d.getDate()); }
start.setYear(years[0]); 
}
if (years.getLast() < end.getFullYear()) { 
d = new Date(years.getLast(), end.getMonth() + 1, 0); // last day of new month
if (end.getDate() > d.getDate()) { end.setDate(d.getDate()); }
end.setYear(years.getLast());
}	
}
if (el.format.test('(F|m|M|n)')) { // search for a month select
var months_start = [];
var months_end = [];
el.getChildren().each(function(option) { // get options
var values = this.unformat(option.value, el.format);
if ($type(values[0]) != 'number' || values[0] == years[0]) { // if it's a year / month combo for curr year, or simply a month select
if (!months_start.contains(values[1])) { months_start.push(values[1]); } // add to months array
}
if ($type(values[0]) != 'number' || values[0] == years.getLast()) { // if it's a year / month combo for curr year, or simply a month select
if (!months_end.contains(values[1])) { months_end.push(values[1]); } // add to months array
}
}, this);
months_start.sort(this.sort);
months_end.sort(this.sort);
if (months_start[0] > start.getMonth()) { 
d = new Date(start.getFullYear(), months_start[0] + 1, 0); // last day of new month
if (start.getDate() > d.getDate()) { start.setDate(d.getDate()); }
start.setMonth(months_start[0]); 
}
if (months_end.getLast() < end.getMonth()) { 
d = new Date(start.getFullYear(), months_end.getLast() + 1, 0); // last day of new month
if (end.getDate() > d.getDate()) { end.setDate(d.getDate()); }
end.setMonth(months_end.getLast());
}	
}
}
}, this);
return { 'start': start, 'end': end };
},
// caption: returns the caption element with header and navigation
// @param cal (obj)
// @returns caption (element)
caption: function(cal) {
// start by assuming navigation is allowed
var navigation = {
prev: { 'month': true, 'year': true },
next: { 'month': true, 'year': true }
};
// if we're in an out of bounds year
if (cal.year == cal.start.getFullYear()) { 
navigation.prev.year = false; 
if (cal.month == cal.start.getMonth() && this.options.navigation == 1) { 
navigation.prev.month = false;
}	
}	
if (cal.year == cal.end.getFullYear()) { 
navigation.next.year = false; 
if (cal.month == cal.end.getMonth() && this.options.navigation == 1) { 
navigation.next.month = false;
}
}
// special case of improved navigation but months array with only 1 month we can disable all month navigation
if ($type(cal.months) == 'array') {
if (cal.months.length == 1 && this.options.navigation == 2) {
navigation.prev.month = navigation.next.month = false;
}
}
var caption = new Element('caption');
var prev = new Element('a').addClass(this.classes.prev).appendText('\x3c'); // <	
var next = new Element('a').addClass(this.classes.next).appendText('\x3e'); // >
if (this.options.navigation == 2) {
var month = new Element('span').addClass(this.classes.month).injectInside(caption);
if (navigation.prev.month) { prev.clone().addEvent('click', function(cal) { this.navigate(cal, 'm', -1); }.pass(cal, this)).injectInside(month); }
month.adopt(new Element('span').appendText(this.options.months[cal.month]));
if (navigation.next.month) { next.clone().addEvent('click', function(cal) { this.navigate(cal, 'm', 1); }.pass(cal, this)).injectInside(month); }
var year = new Element('span').addClass(this.classes.year).injectInside(caption);
if (navigation.prev.year) { prev.clone().addEvent('click', function(cal) { this.navigate(cal, 'y', -1); }.pass(cal, this)).injectInside(year); }
year.adopt(new Element('span').appendText(cal.year));
if (navigation.next.year) { next.clone().addEvent('click', function(cal) { this.navigate(cal, 'y', 1); }.pass(cal, this)).injectInside(year); }
}
else { // 1 or 0
if (navigation.prev.month && this.options.navigation) { prev.clone().addEvent('click', function(cal) { this.navigate(cal, 'm', -1); }.pass(cal, this)).injectInside(caption); }
caption.adopt(new Element('span').addClass(this.classes.month).appendText(this.options.months[cal.month]));
caption.adopt(new Element('span').addClass(this.classes.year).appendText(cal.year));
if (navigation.next.month && this.options.navigation) { next.clone().addEvent('click', function(cal) { this.navigate(cal, 'm', 1); }.pass(cal, this)).injectInside(caption); }
}
return caption;
},
// changed: run when a select value is changed
// @param cal (obj)
changed: function(cal) {
cal.val = this.read(cal); // update calendar val from inputs	
$extend(cal, this.values(cal)); // update bounds - based on curr month
this.rebuild(cal); // rebuild days select
if (!cal.val) { return; } // in case the same date was clicked the cal has no set date we should exit	
if (cal.val.getDate() < cal.days[0]) { cal.val.setDate(cal.days[0]); }
if (cal.val.getDate() > cal.days.getLast()) { cal.val.setDate(cal.days.getLast()); }
cal.els.each(function(el) {	// then we can set the value to the field
el.value = this.format(cal.val, el.format); 
}, this);
this.check(cal); // checks other cals
this.calendars.each(function(kal) { // update cal graphic if visible
if (kal.visible) { this.display(kal); }
}, this);
},
// check: checks other calendars to make sure no overlapping values
// @param cal (obj)
check: function(cal) {
this.calendars.each(function(kal, i) {
if (kal.val) { // if calendar has value set
var change = false;
if (i < cal.id) { // preceding calendar
var bound = new Date(Date.parse(cal.val));
bound.setDate(bound.getDate() - (this.options.pad * (cal.id - i)));
if (bound < kal.val) { change = true; }
}
if (i > cal.id) { // following calendar
var bound = new Date(Date.parse(cal.val));
bound.setDate(bound.getDate() + (this.options.pad * (i - cal.id)));
if (bound > kal.val) { change = true; }
}
if (change) {
if (kal.start > bound) { bound = kal.start; }
if (kal.end < bound) { bound = kal.end; }
kal.month = bound.getMonth();
kal.year = bound.getFullYear();	
$extend(kal, this.values(kal));	
// TODO - IN THE CASE OF SELECT MOVE TO NEAREST VALID VALUE
// IN THE CASE OF INPUT DISABLE
// if new date is not valid better unset cal value
// otherwise it would mean incrementally checking to find the nearest valid date which could be months / years away
kal.val = kal.days.contains(bound.getDate()) ? bound : null;
this.write(kal);
if (kal.visible) { this.display(kal); } // update cal graphic if visible
}
}
else {
kal.month = cal.month;
kal.year = cal.year;
}
}, this);
},
// clicked: run when a valid day is clicked in the calendar
// @param cal (obj)
clicked: function(td, day, cal) {
cal.val = (this.value(cal) == day) ? null : new Date(cal.year, cal.month, day); // set new value - if same then disable
this.write(cal); 
// ok - in the special case that it's all selects and there's always a date no matter what (at least as far as the form is concerned)
// we can't let the calendar undo a date selection - it's just not possible!!
if (!cal.val) { cal.val = this.read(cal); }
if (cal.val) {
this.check(cal); // checks other cals	
this.toggle(cal); // hide cal
} 
else { // remove active class and replace with valid
td.addClass(this.classes.valid);
td.removeClass(this.classes.active);
}
},
// display: create calendar element
// @param cal (obj)
display: function(cal) {
// 1. header and navigation
this.calendar.empty(); // init div
this.calendar.className = this.classes.calendar + ' ' + this.options.months[cal.month].toLowerCase();
var div = new Element('div').injectInside(this.calendar); // a wrapper div to help correct browser css problems with the caption element
var table = new Element('table').injectInside(div).adopt(this.caption(cal));
// 2. day names	
var thead = new Element('thead').injectInside(table);
var tr = new Element('tr').injectInside(thead);
for (var i = 0; i <= 6; i++) {
var th = this.options.days[(i + this.options.offset) % 7];
tr.adopt(new Element('th', { 'title': th }).appendText(th.substr(0, 1)));
}
// 3. day numbers
var tbody = new Element('tbody').injectInside(table);
var tr = new Element('tr').injectInside(tbody);
var d = new Date(cal.year, cal.month, 1);
var offset = ((d.getDay() - this.options.offset) + 7) % 7; // day of the week (offset)
var last = new Date(cal.year, cal.month + 1, 0).getDate(); // last day of this month
var prev = new Date(cal.year, cal.month, 0).getDate(); // last day of previous month
var active = this.value(cal); // active date (if set and within curr month)
var valid = cal.days; // valid days for curr month
var inactive = []; // active dates set by other calendars
var hilited = [];
this.calendars.each(function(kal, i) {
if (kal != cal && kal.val) {
if (cal.year == kal.val.getFullYear() && cal.month == kal.val.getMonth()) { inactive.push(kal.val.getDate()); }
if (cal.val) {
for (var day = 1; day <= last; day++) {
d.setDate(day);
if ((i < cal.id && d > kal.val && d < cal.val) || (i > cal.id && d > cal.val && d < kal.val)) { 
if (!hilited.contains(day)) { hilited.push(day); }
}
}
}
}
}, this);
var d = new Date();
var today = new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime(); // today obv 
for (var i = 1; i < 43; i++) { // 1 to 42 (6 x 7 or 6 weeks)
if ((i - 1) % 7 == 0) { tr = new Element('tr').injectInside(tbody); } // each week is it's own table row
var td = new Element('td').injectInside(tr);
var day = i - offset;
var date = new Date(cal.year, cal.month, day);
var cls = '';
if (day === active) { cls = this.classes.active; } // active
else if (inactive.contains(day)) { cls = this.classes.inactive; } // inactive
else if (valid.contains(day)) { cls = this.classes.valid; } // valid
else if (day >= 1 && day <= last) { cls = this.classes.invalid; } // invalid
if (date.getTime() == today) { cls = cls + ' ' + this.classes.today; } // adds class for today
if (hilited.contains(day)) { cls = cls + ' ' + this.classes.hilite; } // adds class if hilited
td.addClass(cls);
if (valid.contains(day) || this.options.permanent) { // if it's a valid - clickable - day we add interaction
td.setProperty('title', this.format(date, 'D M jS Y'));
td.addEvents({
'click': function(td, day, cal) { 
this.clicked(td, day, cal); 
}.pass([td, day, cal], this),
'mouseover': function(td, cls) { 
td.addClass(cls); 
}.pass([td, this.classes.hover]),
'mouseout': function(td, cls) { 
td.removeClass(cls); 
}.pass([td, this.classes.hover])
});
}
// pad calendar with last days of prev month and first days of next month
if (day < 1) { day = prev + day; }
else if (day > last) { day = day - last; }
td.appendText(day);
}
},
// element: helper function
// @param el (string) element id
// @param f (string) format string
// @param cal (obj)
element: function(el, f, cal) {
if ($type(f) == 'object') { // in the case of multiple inputs per calendar
for (var i in f) { 
if (!this.element(i, f[i], cal)) { return false; }	
}
return true;
}
el = $(el);
if (!el) { return false; }
el.format = f;
if (el.get('tag') == 'select') { // select elements allow the user to manually set the date via select option
el.addEvent('change', function(cal) { this.changed(cal); }.pass(cal, this));
}
else { // input (type text) elements restrict the user to only setting the date via the calendar
el.readOnly = true;
el.addEvent('focus', function(cal) { this.toggle(cal); }.pass(cal, this));
}
cal.els.push(el);
return true;
},
// format: formats a date object according to passed in instructions
// @param date (obj)
// @param f (string) any combination of punctuation / separators and d, j, D, l, S, m, n, F, M, y, Y
// @returns string
format: function(date, format) {
var str = '';
if (date) {
var j = date.getDate(); // 1 - 31
var w = date.getDay(); // 0 - 6
var l = this.options.days[w]; // Sunday - Saturday
var n = date.getMonth() + 1; // 1 - 12
var f = this.options.months[n - 1]; // January - December
var y = date.getFullYear() + ''; // 19xx - 20xx
for (var i = 0, len = format.length; i < len; i++) {
var cha = format.charAt(i); // format char
switch(cha) {
// year cases
case 'y': // xx - xx
y = y.substr(2);
case 'Y': // 19xx - 20xx
str += y;
break;
// month cases
case 'm': // 01 - 12
if (n < 10) { n = '0' + n; }
case 'n': // 1 - 12
str += n;
break;
case 'M': // Jan - Dec
f = f.substr(0, 3);
case 'F': // January - December
str += f;
break;
// day cases
case 'd': // 01 - 31
if (j < 10) { j = '0' + j; }
case 'j': // 1 - 31
str += j;
break;
case 'D': // Sun - Sat
l = l.substr(0, 3);
case 'l': // Sunday - Saturday
str += l;
break;
case 'N': // 1 - 7
w += 1;
case 'w': // 0 - 6
str += w;
break;
case 'S': // st, nd, rd or th (works well with j)
if (j % 10 == 1 && j != '11') { str += 'st'; }
else if (j % 10 == 2 && j != '12') { str += 'nd'; }
else if (j % 10 == 3 && j != '13') { str += 'rd'; }
else { str += 'th'; }
break;
default:
str += cha;
}
}
}
return str; // return format with values replaced
},
// navigate: calendar navigation
// @param cal (obj)
// @param type (str) m or y for month or year
// @param n (int) + or - for next or prev
navigate: function(cal, type, n) {
switch (type) {
case 'm': // month
if ($type(cal.months) == 'array') {
var i = cal.months.indexOf(cal.month) + n; // index of current month
if (i < 0 || i == cal.months.length) { // out of range
if (this.options.navigation == 1) { // if type 1 nav we'll need to increment the year
this.navigate(cal, 'y', n);	
}
i = (i < 0) ? cal.months.length - 1 : 0;
}
cal.month = cal.months[i];
}
else { 
var i = cal.month + n;
if (i < 0 || i == 12) {
if (this.options.navigation == 1) {
this.navigate(cal, 'y', n);	
}
i = (i < 0) ? 11 : 0;
}
cal.month = i;
}	
break;
case 'y': // year
if ($type(cal.years) == 'array') {
var i = cal.years.indexOf(cal.year) + n;
cal.year = cal.years[i]; 
}
else { 
cal.year += n;
}	
break;	
}
$extend(cal, this.values(cal));
if ($type(cal.months) == 'array') { // if the calendar has a months select
var i = cal.months.indexOf(cal.month); // and make sure the curr months exists for the new year
if (i < 0) { cal.month = cal.months[0]; } // otherwise we'll reset the month
}
this.display(cal);
},
// read: compiles cal value based on array of inputs passed in
// @param cal (obj)
// @returns date (obj) or (null)
read: function(cal) {
var arr = [null, null, null];
cal.els.each(function(el) {
// returns an array which may contain empty values
var values = this.unformat(el.value, el.format);
values.each(function(val, i) { 
if ($type(val) == 'number') { arr[i] = val; }
}); 
}, this);
// we can update the cals month and year values
if ($type(arr[0]) == 'number') { cal.year = arr[0]; }
if ($type(arr[1]) == 'number') { cal.month = arr[1]; }
var val = null;
if (arr.every(function(i) { return $type(i) == 'number'; })) { // if valid date
var last = new Date(arr[0], arr[1] + 1, 0).getDate(); // last day of month
if (arr[2] > last) { arr[2] = last; } // make sure we stay within the month (ex in case default day of select is 31 and month is feb)
val = new Date(arr[0], arr[1], arr[2]);
}
return (cal.val == val) ? null : val; // if new date matches old return null (same date clicked twice = disable)
},
// rebuild: rebuilds days + months selects
// @param cal (obj)
rebuild: function(cal) {
cal.els.each(function(el) {	
/*
if (el.get('tag') == 'select' && el.format.test('^(F|m|M|n)$')) { // special case for months-only select
if (!cal.options) { cal.options = el.clone(); } // clone a copy of months select
var val = (cal.val) ? cal.val.getMonth() : el.value.toInt();
el.empty(); // initialize select
cal.months.each(function(month) {
// create an option element
var option = new Element('option', {
'selected': (val == month),
'value': this.format(new Date(1, month, 1), el.format);
}).appendText(day).injectInside(el);
}, this);
}
*/
if (el.get('tag') == 'select' && el.format.test('^(d|j)$')) { // special case for days-only select
var d = this.value(cal);
if (!d) { d = el.value.toInt(); } // if the calendar doesn't have a set value, try to use value from select
el.empty(); // initialize select
cal.days.each(function(day) {
// create an option element
var option = new Element('option', {
'selected': (d == day),
'value': ((el.format == 'd' && day < 10) ? '0' + day : day)
}).appendText(day).injectInside(el);
}, this);
}
}, this); 
},
// sort: helper function for numerical sorting
sort: function(a, b) {
return a - b;
},
// toggle: show / hide calendar 
// @param cal (obj)
toggle: function(cal) {
document.removeEvent('mousedown', this.fn); // always remove the current mousedown script first
// don't remove permanent calendars
if (cal.visible) { // simply hide curr cal	
if (this.options.permanent)
return;
cal.visible = false;
cal.button.removeClass(this.classes.active); // active
this.fx.start('opacity', 1, 0);
}
else { // otherwise show (may have to hide others)
// hide cal on out-of-bounds click
this.fn = function(e, cal) { 
var e = new Event(e);
var el = e.target;
var stop = false;
while (el != document.body && el.nodeType == 1) {
if (el == this.calendar) { stop = true; }
this.calendars.each(function(kal) {
if (kal.button == el || kal.els.contains(el)) { stop = true; }
});
if (stop) { 
e.stop();
return false;
}
else { el = el.parentNode; }
}
this.toggle(cal);
}.create({ 'arguments': cal, 'bind': this, 'event': true });	
document.addEvent('mousedown', this.fn);
this.calendars.each(function(kal) {
if (kal == cal) {
kal.visible = true;
kal.button.addClass(this.classes.active); // css c-icon-active
}
else {
kal.visible = false;
kal.button.removeClass(this.classes.active); // css c-icon-active
}
}, this);
var size = window.getScrollSize();
var coord = cal.button.getCoordinates();
var x = coord.right + this.options.tweak.x;
var y = coord.top + this.options.tweak.y;
// make sure the calendar doesn't open off screen
if (!this.calendar.coord) { this.calendar.coord = this.calendar.getCoordinates(); }
if (x + this.calendar.coord.width > size.x) { x -= (x + this.calendar.coord.width - size.x); }
if (y + this.calendar.coord.height > size.y) { y -= (y + this.calendar.coord.height - size.y); }
this.calendar.setStyles({ left: x + 'px', top: y + 'px' });
if (window.ie6) { 
this.iframe.setStyles({ height: this.calendar.coord.height + 'px', left: x + 'px', top: y + 'px', width: this.calendar.coord.width + 'px' }); 
}
this.display(cal);
this.fx.start('opacity', 0, 1);
}
},
// unformat: takes a value from an input and parses the d, m and y elements
// @param val (string)
// @param f (string) any combination of punctuation / separators and d, j, D, l, S, m, n, F, M, y, Y
// @returns array
unformat: function(val, f) {
f = f.escapeRegExp();
var re = {
d: '([0-9]{2})',
j: '([0-9]{1,2})',
D: '(' + this.options.days.map(function(day) { return day.substr(0, 3); }).join('|') + ')',	
l: '(' + this.options.days.join('|') + ')',
S: '(st|nd|rd|th)',
F: '(' + this.options.months.join('|') + ')',
m: '([0-9]{2})',
M: '(' + this.options.months.map(function(month) { return month.substr(0, 3); }).join('|') + ')',	
n: '([0-9]{1,2})',
Y: '([0-9]{4})',
y: '([0-9]{2})'
}
var arr = []; // array of indexes
var g = '';
// convert our format string to regexp
for (var i = 0; i < f.length; i++) {
var c = f.charAt(i);
if (re[c]) {
arr.push(c);
g += re[c];
}
else {
g += c;
}
}
// match against date
var matches = val.match('^' + g + '$');
var dates = new Array(3);
if (matches) {
matches = matches.slice(1); // remove first match which is the date
arr.each(function(c, i) {
i = matches[i];
switch(c) {
// year cases
case 'y':
i = '19' + i; // 2 digit year assumes 19th century (same as JS)
case 'Y':
dates[0] = i.toInt();
break;
// month cases
case 'F':
i = i.substr(0, 3);
case 'M':
i = this.options.months.map(function(month) { return month.substr(0, 3); }).indexOf(i) + 1;
case 'm':
case 'n':
dates[1] = i.toInt() - 1;
break;
// day cases
case 'd':
case 'j':
dates[2] = i.toInt();
break;
}
}, this);
}
return dates;
},
// value: returns day value of calendar if set
// @param cal (obj)
// @returns day (int) or null
value: function(cal) {
var day = null;
if (cal.val) {
if (cal.year == cal.val.getFullYear() && cal.month == cal.val.getMonth()) { day = cal.val.getDate(); }
}
return day;
},
// values: returns the years, months (for curr year) and days (for curr month and year) for the calendar
// @param cal (obj)
// @returns obj	
values: function(cal) {
var years, months, days;
cal.els.each(function(el) {	
if (el.get('tag') == 'select') {	
if (el.format.test('(y|Y)')) { // search for a year select
years = [];
el.getChildren().each(function(option) { // get options
var values = this.unformat(option.value, el.format);
if (!years.contains(values[0])) { years.push(values[0]); } // add to years array
}, this);
years.sort(this.sort);
}
if (el.format.test('(F|m|M|n)')) { // search for a month select
months = []; // 0 - 11 should be
el.getChildren().each(function(option) { // get options
var values = this.unformat(option.value, el.format);
if ($type(values[0]) != 'number' || values[0] == cal.year) { // if it's a year / month combo for curr year, or simply a month select
if (!months.contains(values[1])) { months.push(values[1]); } // add to months array
}
}, this);
months.sort(this.sort);
}
if (el.format.test('(d|j)') && !el.format.test('^(d|j)$')) { // search for a day select, but NOT a days only select
days = []; // 1 - 31
el.getChildren().each(function(option) { // get options
var values = this.unformat(option.value, el.format);
// in the special case of days we dont want the value if its a days only select
// otherwise that will screw up the options rebuilding
// we will take the values if they are exact dates though
if (values[0] == cal.year && values[1] == cal.month) {
if (!days.contains(values[2])) { days.push(values[2]); } // add to days array
}
}, this);
}
}
}, this);
// we start with what would be the first and last days were there no restrictions
var first = 1;
var last = new Date(cal.year, cal.month + 1, 0).getDate(); // last day of the month
// if we're in an out of bounds year
if (cal.year == cal.start.getFullYear()) {
// in the special case of improved navigation but no months array, we'll need to construct one
if (months == null && this.options.navigation == 2) {
months = [];
for (var i = 0; i < 12; i ++) { 
if (i >= cal.start.getMonth()) { months.push(i); } 
}
}
// if we're in an out of bounds month
if (cal.month == cal.start.getMonth()) { 
first = cal.start.getDate(); // first day equals day of bound
}
}	
if (cal.year == cal.end.getFullYear()) {
// in the special case of improved navigation but no months array, we'll need to construct one
if (months == null && this.options.navigation == 2) {
months = [];
for (var i = 0; i < 12; i ++) { 
if (i <= cal.end.getMonth()) { months.push(i); } 
}
}
if (cal.month == cal.end.getMonth()) { 
last = cal.end.getDate(); // last day equals day of bound
}
}
// let's get our invalid days
var blocked = this.blocked(cal);
// finally we can prepare all the valid days in a neat little array
if ($type(days) == 'array') { // somewhere there was a days select
days = days.filter(function(day) {
if (day >= first && day <= last && !blocked.contains(day)) { return day; }
});
}
else { // no days select we'll need to construct a valid days array
days = [];
for (var i = first; i <= last; i++) { 
if (!blocked.contains(i)) { days.push(i); }
}
}	
days.sort(this.sort); // sorting our days will give us first and last of month
return { 'days': days, 'months': months, 'years': years };
},
// write: sets calendars value to form elements
// @param cal (obj)
write: function(cal) {
this.rebuild(cal);	// in the case of options, we'll need to make sure we have the correct number of days available
cal.els.each(function(el) {	// then we can set the value to the field
el.value = this.format(cal.val, el.format); 
}, this);
}
});
Calendar.implement(new Events, new Options);
// cmscript: fold
/* (c) 2009 CaribMedia */
var activeElement;
/*
* @name isTag
* @description simply checks if an element is a tag or a text
* IE sees tags+text, FF sees only tags
* @author Michiel van der Blonk
* @date Oct 18, 2005
*/
function isTag(node)
{
return (node.nodeType == 1);
}
/*
* @name fold
* @description folds/unfolds part of a page (tile)
* @param skip - the number of elements to skip after
* - in fact, skip is the Nth child from the parent
* @author Michiel van der Blonk
* @date July 11, 2005
* @updated Oct 18, 2005
*/
function fold(el, skip)
{
// the block to hide should be the first child after
// the show-hide button
var tile, node, parent;
if (!el)
return;
// find the element
parent = el.parentNode;
if (parent.hasChildNodes())
{
// init node
node = parent.childNodes[0];
var size = parent.childNodes.length;
var nCountElements = 0;
var nCountTags = 0;
// if there are any elements, continue
if (size > 0)
{
// loop until bounds
while (nCountTags < skip && nCountElements<size)
{
node = parent.childNodes[nCountElements];
nCountElements++;
// count the tags
if (isTag(node))
nCountTags++;
}
tile = node;
}
else
alert('error: list cannot display');
}
else
alert('error: list cannot display');
// now show/hide the element
var isHidden = false;
if (tile.className)
isHidden = tile.className.match(/hide/)!==null;
if (!isHidden)
{
tile.className += " hide";
el.className += " collapsed";
}
else
{
tile.className = tile.className.replace(" hide","");
el.className = el.className.replace(" collapsed","");
// also for elements with a single class name
tile.className = tile.className.replace("hide","");
el.className = el.className.replace("collapsed","");
}
return false;
}
/*
* @name collapse
* @description collapses all elements in a list by calling fold()
* @author Michiel van der Blonk
* @date Oct 18, 2005
*/
function collapse(listId)
{
var list = document.getElementById(listId);
if (!list) 
return;
var foldIcons = list.getElementsByTagName("span");
for (var i=0; i<foldIcons.length; i++)
{
if ( foldIcons[i].className.match(/fold/)!==null )
fold(foldIcons[i], 3);
}
}
/*
* @name expand
* @description expands an item by walking up the tree
* @author Michiel van der Blonk
* @date Oct 18, 2005
*/
function expand(objElement)
{
// THIS IS NOT WORKING YET.
// WE NEED TO ACTUALLY _FOLD_ HERE, SINCE THE + NEEDS TO BE SHOWN
var activeElement = objElement;
var el;
do
{
if (activeElement.tagName == "UL")
{
tile.className = tile.className.replace(" hide","");
el.className = el.className.replace(" collapsed","");
// also for elements with a single class name
tile.className = tile.className.replace("hide","");
el.className = el.className.replace("collapsed","");
}
activeElement = activeElement.parentNode;
} while (activeElement.tagName!="DIV" && activeElement.tagName!="BODY")
}
/*
* @name showHide
* @description hides an element effectively by adding the 'hide' class
* @precond the class named 'hide' should exist in the css
* @author Michiel van der Blonk
* @date Oct 18, 2005
*/
function showHide(id)
{
var isHidden;
var tile = document.getElementById(id);
showHideObject(tile);
}
/*
* @name showHide
* @description hides an element effectively by adding the 'hide' class
* @precond the class named 'hide' should exist in the css
* @author Michiel van der Blonk
* @date Oct 18, 2005
*/
function showHideObject(objElement)
{
var isHidden;
tile = objElement;
// check for existence of tile element
if (!tile)
return;
isHidden = tile.className.match(/hide/)!==null;
if (isHidden)
{
tile.className = tile.className.replace(" hide","");
// also for elements with a single class name
tile.className = tile.className.replace("hide","");
}
else
tile.className += " hide";
}
/*
* @name debug
* @description shows debug info in a 'debug' box in html
* @precond the element named 'debug' should exist in the css
* @author Michiel van der Blonk
* @date Oct 18, 2005
*/
function debug(s)
{
debugBox = document.getElementById('debug');
if (debugBox)
debugBox.innerHTML += s + "<br>";
}
/*
* @name findOwner
* @description finds the parent DIV
* @param evt - the event
* @author PPK (www.quirksmode.org)
* @date Oct 18, 2005
*/
function findOwner(element)
{
node = element;
while (node)
{
if (isTag(node) && node.nodeName == "DIV")
return node;
node = node.parentNode;
}
return null;
}
/*
* @name autoFold
* @description sets a timer to automatically hide the list
* @param selectId - the id of the faux-select
* @param listId - the id of the UL
* @param target - the element that triggered the event
* @param delay - nr of seconds to wait before closing
* @author Michiel van der Blonk
* @date Oct 18, 2005
*/
function autoFold(selectId, listId, target, delay)
{
// prevent bubbles
if (window.event)
window.event.cancelBubble = true;
// if this is not the list return
if (target.id!=listId)
return;
var isHidden;
list = document.getElementById(listId);
selectBox = document.getElementById(selectId);
isListVisible = list.className.match(/hide/)===null;
if (isListVisible)
window.setTimeout("fold(selectBox, 2)", delay*1000);
}
/*
* @name getTarget
* @description cross browser code for finding out an event target
* @param e - the event
* @author Michiel van der Blonk
* @date Oct 18, 2005
*/
function getTarget(e)
{
// in IE the event param is null
if (!e)
var e = window.event;
// IE has srcElement attr
if (e.srcElement)
target = e.srcElement;
// FF/NN has target attr
if (e.target)
target = e.target;
return target;
}
/*
* @name initSelectList
* @param selectId - the id of the faux-select box
* @param listId - the id of the actual list (expanding div)
* @param action - either 'select' (default) or 'submit'
* @param formId - the form that contains the select box
* @param fieldId - the hidden field which is used to submit the value
* @param autoHide - hide the list after 2 seconds
* @param currentNode - display the current node as the selected item
* @param onAction - javascript function string to call in addition to
* standard select/submit actions
* @description initialises a subcategory list box
* @precond the html for the subcat should be in place
* @author Michiel van der Blonk
* @date Oct 18, 2005
*/
function initSelectList(selectId, listId, action, formId, fieldId, autoHide, currentNode, onAction)
{
// set default action
if (!action)
action = 'select';
// get elements
var selectBox = $(selectId);
var list = $(listId);
if (!list)
return;
// when someone clicks anywhere on the document
// outside of the list we close it (the list)
// list.onclick = function() {event.cancelBubble = true;return false;}
if (!document.onclick) {
$(document.body).addEvent('click', function(e) {
// init
t = getTarget(e);
owner = findOwner(t);
// if this element is a child of the list
// then don't close the list
if (owner && owner.id==listId)
return;
// otherwise, if the list is currently open
// then close it now
if (t.id!=listId && t.id!=selectId )
{
if (!list.className.match(/hide/))
fold(selectBox, 2);
}
});
}
// find the list, collapse all elements
collapse(listId);
// hide the list
fold(selectBox, 2);
// create select/submit actions for all anchors in the list
var items = $(list).getElements('a');
items.each(function(item) {
var rel = item.get('rel');
// in case of submit attach function
if (item.get('rel') == currentNode)
{
selectBox.innerHTML = item.innerHTML;
activeElement = item.parentNode.parentNode;
// expand all UL's up the tree from the current node
//expand(activeElement);
}
item.addEvent('click', function() {
selectBox.set('html', this.get('html'));
fold(selectBox, 2);
var form = $(formId);
$(fieldId).set('value', this.get('rel'));
if (onAction !== null)
eval(onAction);
if (action=='submit')
form.submit();
return false;
});
});
}
// cmscript: contentxl
/* (c) 2003 CaribMedia
* these functions are used on several places.
* Please note this is an outdated file and needs major cleanup
*/
// This function sorts the entity lists
function sortBy(theForm, target) {
if (theForm.sortBy && theForm.sortDirection)
{
if (theForm.sortBy.value == target) {
if (theForm.sortDirection.value == 'ASC') {
theForm.sortDirection.value = 'DESC';
} else {
theForm.sortDirection.value = 'ASC';
}
} else {
theForm.sortDirection.value = 'ASC';
}
theForm.sortBy.value = target;
theForm.submit();
}
return false;
}
function textCounter(field, countfield, maxlimit) {
if (field.value.length > maxlimit)
{
field.value = field.value.substring(0, maxlimit);
field.blur();
field.focus();
return false;
}
else
countfield.value = maxlimit - field.value.length;
return true;
}
function getSelectedRadio(buttonGroup) {
// returns the array number of the selected radio button or -1 if no button is selected
if (buttonGroup[0]) { // if the button group is an array (one button is not an array)
for (var i=0; i<buttonGroup.length; i++) {
if (buttonGroup[i].checked) {
return i;
}
}
} else {
if (buttonGroup.checked) { return 0; } // if the one button is checked, return zero
}
// if we get to this point, no radio button is selected
return -1;
} // Ends the "getSelectedRadio" function
function getSelectedRadioValue(buttonGroup) {
// returns the value of the selected radio button or "" if no button is selected
var i = getSelectedRadio(buttonGroup);
if (i == -1) {
return "";
} else {
if (buttonGroup[i]) { // Make sure the button group is an array (not just one button)
return buttonGroup[i].value;
} else { // The button group is just the one button, and it is checked
return buttonGroup.value;
}
}
} // Ends the "getSelectedRadioValue" function
function getDate(field, format) {
var newDate = new Date();
var day, month, year;
if (format.toLowerCase() == 'yyyy-mm-dd') {
month = field.value.substring(5,7);
if (month.charAt(0) == "0") {
month = month.charAt(1);
}
day = field.value.substring(8,10);
if (day.charAt(0) == "0") {
day = day.charAt(1);
}
newDate.setMonth(parseInt(month)-1);
newDate.setDate(parseInt(day));
newDate.setYear(parseInt(field.value.substring(0,4)));
} else if (format.toLowerCase() == 'mm/dd/yyyy') {
month = field.value.substring(0,2);
if (month.charAt(0) == "0") {
month = month.charAt(1);
}
day = field.value.substring(3,5);
if (day.charAt(0) == "0") {
day = day.charAt(1);
}
newDate.setMonth(parseInt(month)-1);
newDate.setDate(parseInt(day));
newDate.setYear(parseInt(field.value.substring(6,10)));
}
return newDate;
}
// Determines the number of days between two dates.
function daysBetween(date1, date2) {
var diff;
var days;
diff = Math.abs(date1.getTime() - date2.getTime());
days = Math.floor(diff/(1000 * 60 * 60 * 24));
return days;
}
// Accepts a non-negative currency value
function isCurrency(field) {
var result;
var regexp;
result = false;
if (field.value === '' || field.value === null) {
return result;
}
//regexp = new RegExp('^[-]?([1-9]{1}[0-9]{0,}(\.[0-9]{0,2})?|0(\.[0-9]{0,2})?|\.[0-9]{1,2})$');
regexp = new RegExp('^([1-9]{1}[0-9]{0,}(\.[0-9]{0,2})?|0(\.[0-9]{0,2})?|\.[0-9]{1,2})$');
result = regexp.test(field.value);
return result;
}
function datesEqual(date1,date2) {
var result = date1.getMonth() == date2.getMonth();
result = result && date1.getDate() == date2.getDate();
result = result && date1.getYear() == date2.getYear();
return result;
}
function checkAll(field) {
for(var i = 0; i < field.length; i++)
field[i].checked = true;
}
function uncheckAll(field) {
for(var i = 0; i < field.length; i++)
field[i].checked = false;
}
function getCalBase() {
var metaTag = document.getElementsByTagName("meta");
var calendarBase = "";
for(var i=0; i<metaTag.length; i++) {
if(metaTag[i].name == "calbase") {
calendarBase = metaTag[i].content;
}
}
return calendarBase;
}
function clearFieldIfChecked(field, checkbox) {
if (checkbox.checked) field.value = '';
}
// Enable/Disable appropriate elements based on selected country
function checkCountry(myform) {
if (myform.country.value === '') {
myform.state.disabled = false;
myform.province.disabled = false;
} else if (myform.country.value == 'CA') {
myform.province.disabled = false;
myform.state.disabled = true;
myform.state.value = '';
} else if (myform.country.value == 'US') {
myform.state.disabled = false;
myform.province.disabled = true;
myform.province.value = '';
} else {
myform.state.disabled = true;
myform.state.value = '';
myform.province.disabled = true;
myform.province.value = '';
}
}
function setElementValue(element, value) {
var el = document.getElementsByName(element)[0];
el.value = value;
}
function getElementValue(element) {
var el = document.getElementsByName(element)[0];
return el.value;
}
function isChecked(element) {
var el = document.getElementsByName(element)[0];
return el.checked;
}
function setChecked(element, on) {
var el = document.getElementsByName(element)[0];
el.checked = on;
}
function setElementDisabled(element, disabled) {
var el = document.getElementsByName(element)[0];
el.disabled = disabled;
}
function setElementReadonly(element, readonly) {
var el = document.getElementsByName(element)[0];
el.readOnly = readonly;
}
function resetFirstItem(formId) {
var frm = document.getElementById(formId);
frm.firstItem.value = '0';
}
/*
function selectAllInList(listId) {
selectAllInList(listId, true);
}
*/
function selectAllInList(listId, on) {
var list = document.getElementById(listId);
var len = list.length;
for(i=0; i<len; i++) {
list.options[i].selected=on;
}
}
// Get the LI values from a UL tag and concatenate them with '|'.
// Set element 'elemId' to the concatenated value.
function getListValues(listId, prefix, elemId) {
var list = document.getElementById(listId);
var values = '';
for (var i=0; i < list.childNodes.length; i++)
{
var item = list.childNodes[i].getAttribute('value');
var id = item.substring(prefix.length,item.length);
values += id;
if (i < list.childNodes.length-1)
values += '|';
}
document.getElementById(elemId).value = values;
}
// cmscript: squeezebox
/**
* SqueezeBox - Expandable Lightbox
*
* Allows to open various content as modal,
* centered and animated box.
*
* Dependencies: MooTools 1.2
*
* Inspired by
* ... Lokesh Dhakar	- The original Lightbox v2
*
* @version	1.1 rc4
*
* @license	MIT-style license
* @author	Harald Kirschner <mail [at] digitarald.de>
* @copyright	Author
*/
var SqueezeBox = {
presets: {
onOpen: $empty,
onClose: $empty,
onUpdate: $empty,
onResize: $empty,
onMove: $empty,
onShow: $empty,
onHide: $empty,
size: {x: 600, y: 450},
sizeLoading: {x: 200, y: 150},
marginInner: {x: 20, y: 20},
marginImage: {x: 50, y: 75},
handler: false,
target: null,
closable: true,
closeBtn: true,
zIndex: 65555,
overlayOpacity: 0.7,
classWindow: '',
classOverlay: '',
overlayFx: {},
resizeFx: {},
contentFx: {},
parse: false, // 'rel'
parseSecure: false,
shadow: true,
document: null,
ajaxOptions: {}
},
initialize: function(presets) {
if (this.options) return this;
this.presets = $merge(this.presets, presets);
this.doc = this.presets.document || document;
this.options = {};
this.setOptions(this.presets).build();
this.bound = {
window: this.reposition.bind(this, [null]),
scroll: this.checkTarget.bind(this),
close: this.close.bind(this),
key: this.onKey.bind(this)
};
this.isOpen = this.isLoading = false;
return this;
},
build: function() {
this.overlay = new Element('div', {
id: 'sbox-overlay',
styles: {display: 'none', zIndex: this.options.zIndex}
});
this.win = new Element('div', {
id: 'sbox-window',
styles: {display: 'none', zIndex: this.options.zIndex + 2}
});
if (this.options.shadow) {
if (Browser.Engine.webkit420) {
this.win.setStyle('-webkit-box-shadow', '0 0 10px rgba(0, 0, 0, 0.7)');
} else if (!Browser.Engine.trident4) {
var shadow = new Element('div', {'class': 'sbox-bg-wrap'}).inject(this.win);
var relay = function(e) {
this.overlay.fireEvent('click', [e]);
}.bind(this);
['n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw'].each(function(dir) {
new Element('div', {'class': 'sbox-bg sbox-bg-' + dir}).inject(shadow).addEvent('click', relay);
});
}
}
this.content = new Element('div', {id: 'sbox-content'}).inject(this.win);
this.closeBtn = new Element('a', {id: 'sbox-btn-close', href: '#'}).inject(this.win);
this.fx = {
overlay: new Fx.Tween(this.overlay, $merge({
property: 'opacity',
onStart: Events.prototype.clearChain,
duration: 250,
link: 'cancel'
}, this.options.overlayFx)).set(0),
win: new Fx.Morph(this.win, $merge({
onStart: Events.prototype.clearChain,
unit: 'px',
duration: 750,
transition: Fx.Transitions.Quint.easeOut,
link: 'cancel',
unit: 'px'
}, this.options.resizeFx)),
content: new Fx.Tween(this.content, $merge({
property: 'opacity',
duration: 250,
link: 'cancel'
}, this.options.contentFx)).set(0)
};
$(this.doc.body).adopt(this.overlay, this.win);
},
assign: function(to, options) {
return ($(to) || $$(to)).addEvent('click', function() {
return !SqueezeBox.fromElement(this, options);
});
},
open: function(subject, options) {
this.initialize();
if (this.element != null) this.trash();
this.element = $(subject) || false;
this.setOptions($merge(this.presets, options || {}));
if (this.element && this.options.parse) {
var obj = this.element.getProperty(this.options.parse);
if (obj && (obj = JSON.decode(obj, this.options.parseSecure))) this.setOptions(obj);
}
this.url = ((this.element) ? (this.element.get('href')) : subject) || this.options.url || '';
this.assignOptions();
var handler = handler || this.options.handler;
if (handler) return this.setContent(handler, this.parsers[handler].call(this, true));
var ret = false;
return this.parsers.some(function(parser, key) {
var content = parser.call(this);
if (content) {
ret = this.setContent(key, content);
return true;
}
return false;
}, this);
},
fromElement: function(from, options) {
return this.open(from, options);
},
assignOptions: function() {
this.overlay.set('class', this.options.classOverlay);
this.win.set('class', this.options.classWindow);
if (Browser.Engine.trident4) this.win.addClass('sbox-window-ie6');
},
close: function(e) {
var stoppable = ($type(e) == 'event');
if (stoppable) e.stop();
if (!this.isOpen || (stoppable && !$lambda(this.options.closable).call(this, e))) return this;
this.fx.overlay.start(0).chain(this.toggleOverlay.bind(this));
this.win.setStyle('display', 'none');
this.fireEvent('onClose', [this.content]);
this.trash();
this.toggleListeners();
this.isOpen = false;
return this;
},
trash: function() {
this.element = this.asset = null;
this.content.empty();
this.options = {};
this.removeEvents().setOptions(this.presets).callChain();
},
onError: function() {
this.asset = null;
this.setContent('string', this.options.errorMsg || 'An error occurred');
},
setContent: function(handler, content) {
if (!this.handlers[handler]) return false;
this.content.className = 'sbox-content-' + handler;
this.applyTimer = this.applyContent.delay(this.fx.overlay.options.duration, this, this.handlers[handler].call(this, content));
if (this.overlay.retrieve('opacity')) return this;
this.toggleOverlay(true);
this.fx.overlay.start(this.options.overlayOpacity);
return this.reposition();
},
applyContent: function(content, size) {
if (!this.isOpen && !this.applyTimer) return;
this.applyTimer = $clear(this.applyTimer);
this.hideContent();
if (!content) {
this.toggleLoading(true);
} else {
if (this.isLoading) this.toggleLoading(false);
this.fireEvent('onUpdate', [this.content], 20);
}
if (content) {
if (['string', 'array'].contains($type(content))) this.content.set('html', content);
else if (!this.content.hasChild(content)) this.content.adopt(content);
}
this.callChain();
if (!this.isOpen) {
this.toggleListeners(true);
this.resize(size, true);
this.isOpen = true;
this.fireEvent('onOpen', [this.content]);
} else {
this.resize(size);
}
},
resize: function(size, instantly) {
this.showTimer = $clear(this.showTimer || null);
var box = this.doc.getSize(), scroll = this.doc.getScroll();
this.size = $merge((this.isLoading) ? this.options.sizeLoading : this.options.size, size);
var to = {
width: this.size.x,
height: this.size.y,
left: (scroll.x + (box.x - this.size.x - this.options.marginInner.x) / 2).toInt(),
top: (scroll.y + (box.y - this.size.y - this.options.marginInner.y) / 2).toInt()
};
this.hideContent();
if (!instantly) {
this.fx.win.start(to).chain(this.showContent.bind(this));
} else {
this.win.setStyles(to).setStyle('display', '');
this.showTimer = this.showContent.delay(50, this);
}
return this.reposition();
},
toggleListeners: function(state) {
var fn = (state) ? 'addEvent' : 'removeEvent';
this.closeBtn[fn]('click', this.bound.close);
this.overlay[fn]('click', this.bound.close);
this.doc[fn]('keydown', this.bound.key)[fn]('mousewheel', this.bound.scroll);
this.doc.getWindow()[fn]('resize', this.bound.window)[fn]('scroll', this.bound.window);
},
toggleLoading: function(state) {
this.isLoading = state;
this.win[(state) ? 'addClass' : 'removeClass']('sbox-loading');
if (state) this.fireEvent('onLoading', [this.win]);
},
toggleOverlay: function(state) {
var full = this.doc.getSize().x;
this.overlay.setStyle('display', (state) ? '' : 'none');
this.doc.body[(state) ? 'addClass' : 'removeClass']('body-overlayed');
if (state) {
this.scrollOffset = this.doc.getWindow().getSize().x - full;
this.doc.body.setStyle('margin-right', this.scrollOffset);
} else {
this.doc.body.setStyle('margin-right', '');
}
},
showContent: function() {
if (this.content.get('opacity')) this.fireEvent('onShow', [this.win]);
this.fx.content.start(1);
},
hideContent: function() {
if (!this.content.get('opacity')) this.fireEvent('onHide', [this.win]);
this.fx.content.cancel().set(0);
},
onKey: function(e) {
switch (e.key) {
case 'esc': this.close(e);
case 'up': case 'down': return false;
}
},
checkTarget: function(e) {
return this.content.hasChild(e.target);
},
reposition: function() {
var size = this.doc.getSize(), scroll = this.doc.getScroll(), ssize = this.doc.getScrollSize();
this.overlay.setStyles({
width: ssize.x + 'px',
height: ssize.y + 'px'
});
this.win.setStyles({
left: (scroll.x + (size.x - this.win.offsetWidth) / 2 - this.scrollOffset).toInt() + 'px',
top: (scroll.y + (size.y - this.win.offsetHeight) / 2).toInt() + 'px'
});
return this.fireEvent('onMove', [this.overlay, this.win]);
},
removeEvents: function(type){
if (!this.$events) return this;
if (!type) this.$events = null;
else if (this.$events[type]) this.$events[type] = null;
return this;
},
extend: function(properties) {
return $extend(this, properties);
},
handlers: new Hash(),
parsers: new Hash()
};
SqueezeBox.extend(new Events($empty)).extend(new Options($empty)).extend(new Chain($empty));
SqueezeBox.parsers.extend({
image: function(preset) {
return (preset || (/\.(?:jpg|png|gif)$/i).test(this.url)) ? this.url : false;
},
clone: function(preset) {
if ($(this.options.target)) return $(this.options.target);
if (this.element && !this.element.parentNode) return this.element;
var bits = this.url.match(/#([\w-]+)$/);
return (bits) ? $(bits[1]) : (preset ? this.element : false);
},
ajax: function(preset) {
return (preset || (this.url && !(/^(?:javascript|#)/i).test(this.url))) ? this.url : false;
},
iframe: function(preset) {
return (preset || this.url) ? this.url : false;
},
string: function(preset) {
return true;
}
});
SqueezeBox.handlers.extend({
image: function(url) {
var size, tmp = new Image();
this.asset = null;
tmp.onload = tmp.onabort = tmp.onerror = (function() {
tmp.onload = tmp.onabort = tmp.onerror = null;
if (!tmp.width) {
this.onError.delay(10, this);
return;
}
var box = this.doc.getSize();
box.x -= this.options.marginImage.x;
box.y -= this.options.marginImage.y;
size = {x: tmp.width, y: tmp.height};
for (var i = 2; i--;) {
if (size.x > box.x) {
size.y *= box.x / size.x;
size.x = box.x;
} else if (size.y > box.y) {
size.x *= box.y / size.y;
size.y = box.y;
}
}
size.x = size.x.toInt();
size.y = size.y.toInt();
this.asset = $(tmp);
tmp = null;
this.asset.width = size.x;
this.asset.height = size.y;
this.applyContent(this.asset, size);
}).bind(this);
tmp.src = url;
if (tmp && tmp.onload && tmp.complete) tmp.onload();
return (this.asset) ? [this.asset, size] : null;
},
clone: function(el) {
if (el) return el.clone();
return this.onError();
},
adopt: function(el) {
if (el) return el;
return this.onError();
},
ajax: function(url) {
var options = this.options.ajaxOptions || {};
this.asset = new Request.HTML($merge({
method: 'get',
evalScripts: false
}, this.options.ajaxOptions)).addEvents({
onSuccess: function(resp) {
this.applyContent(resp);
if (options.evalScripts !== null && !options.evalScripts) $exec(this.asset.response.javascript);
this.fireEvent('onAjax', [resp, this.asset]);
this.asset = null;
}.bind(this),
onFailure: this.onError.bind(this)
});
this.asset.send.delay(10, this.asset, [{url: url}]);
},
iframe: function(url) {
this.asset = new Element('iframe', $merge({
src: url,
frameBorder: 0,
width: this.options.size.x,
height: this.options.size.y
}, this.options.iframeOptions));
if (this.options.iframePreload) {
this.asset.addEvent('load', function() {
this.applyContent(this.asset.setStyle('display', ''));
}.bind(this));
this.asset.setStyle('display', 'none').inject(this.content);
return false;
}
return this.asset;
},
string: function(str) {
return str;
}
});
SqueezeBox.handlers.url = SqueezeBox.handlers.ajax;
SqueezeBox.parsers.url = SqueezeBox.parsers.ajax;
SqueezeBox.parsers.adopt = SqueezeBox.parsers.clone;
/*
Slimbox v1.71 - The ultimate lightweight Lightbox clone
(c) 2007-2009 Christophe Beyls <http://www.digitalia.be>
MIT-style license.
*/
var Slimbox=(function(){var F=window,n=Browser.Engine.trident4,u,g,G=-1,o,w,E,v,y,M,s,m={},t=new Image(),K=new Image(),I,a,h,q,J,e,H,c,A,L,x,i,d,C;F.addEvent("domready",function(){$(document.body).adopt($$(I=new Element("div",{id:"lbOverlay",events:{click:D}}),a=new Element("div",{id:"lbCenter"}),H=new Element("div",{id:"lbBottomContainer"})).setStyle("display","none"));h=new Element("div",{id:"lbImage"}).injectInside(a).adopt(q=new Element("div",{styles:{position:"relative"}}).adopt(J=new Element("a",{id:"lbPrevLink",href:"#",events:{click:B}}),e=new Element("a",{id:"lbNextLink",href:"#",events:{click:f}})));c=new Element("div",{id:"lbBottom"}).injectInside(H).adopt(new Element("a",{id:"lbCloseLink",href:"#",events:{click:D}}),A=new Element("div",{id:"lbCaption"}),L=new Element("div",{id:"lbNumber"}),new Element("div",{styles:{clear:"both"}}))});function z(){var N=F.getScroll(),O=F.getSize();$$(a,H).setStyle("left",N.x+(O.x/2));if(v){I.setStyles({left:N.x,top:N.y,width:O.x,height:O.y})}}function l(N){["object",n?"select":"embed"].forEach(function(P){Array.forEach(document.getElementsByTagName(P),function(Q){if(N){Q._slimbox=Q.style.visibility}Q.style.visibility=N?"hidden":Q._slimbox})});I.style.display=N?"":"none";var O=N?"addEvent":"removeEvent";F[O]("scroll",z)[O]("resize",z);document[O]("keydown",p)}function p(O){var N=O.code;return u.closeKeys.contains(N)?D():u.nextKeys.contains(N)?f():u.previousKeys.contains(N)?B():false}function B(){return b(w)}function f(){return b(E)}function b(N){if(N>=0){G=N;o=g[N][0];w=(G||(u.loop?g.length:0))-1;E=((G+1)%g.length)||(u.loop?0:-1);r();a.className="lbLoading";m=new Image();m.onload=k;m.src=o}return false}function k(){a.className="";d.set(0);h.setStyles({backgroundImage:"url("+o+")",display:""});q.setStyle("width",m.width);$$(q,J,e).setStyle("height",m.height);A.set("html",g[G][1]||"");L.set("html",(((g.length>1)&&u.counterText)||"").replace(/{x}/,G+1).replace(/{y}/,g.length));if(w>=0){t.src=g[w][0]}if(E>=0){K.src=g[E][0]}M=h.offsetWidth;s=h.offsetHeight;var P=Math.max(0,y-(s/2)),N=0,O;if(a.offsetHeight!=s){N=i.start({height:s,top:P})}if(a.offsetWidth!=M){N=i.start({width:M,marginLeft:-M/2})}O=function(){H.setStyles({width:M,top:P+s,marginLeft:-M/2,visibility:"hidden",display:""});d.start(1)};if(N){i.chain(O)}else{O()}}function j(){if(w>=0){J.style.display=""}if(E>=0){e.style.display=""}C.set(-c.offsetHeight).start(0);H.style.visibility=""}function r(){m.onload=$empty;m.src=t.src=K.src=o;i.cancel();d.cancel();C.cancel();$$(J,e,h,H).setStyle("display","none")}function D(){if(G>=0){r();G=w=E=-1;a.style.display="none";x.cancel().chain(l).start(0)}return false}Element.implement({slimbox:function(N,O){$$(this).slimbox(N,O);return this}});Elements.implement({slimbox:function(N,Q,P){Q=Q||function(R){return[R.href,R.title]};P=P||function(){return true};var O=this;O.removeEvents("click").addEvent("click",function(){var R=O.filter(P,this);return Slimbox.open(R.map(Q),R.indexOf(this),N)});return O}});return{open:function(P,O,N){u=$extend({loop:false,overlayOpacity:0.8,overlayFadeDuration:400,resizeDuration:400,resizeTransition:false,initialWidth:250,initialHeight:250,imageFadeDuration:400,captionAnimationDuration:400,counterText:"Image {x} of {y}",closeKeys:[27,88,67],previousKeys:[37,80],nextKeys:[39,78]},N||{});x=new Fx.Tween(I,{property:"opacity",duration:u.overlayFadeDuration});i=new Fx.Morph(a,$extend({duration:u.resizeDuration,link:"chain"},u.resizeTransition?{transition:u.resizeTransition}:{}));d=new Fx.Tween(h,{property:"opacity",duration:u.imageFadeDuration,onComplete:j});C=new Fx.Tween(c,{property:"margin-top",duration:u.captionAnimationDuration});if(typeof P=="string"){P=[[P,O]];O=0}y=F.getScrollTop()+(F.getHeight()/2);M=u.initialWidth;s=u.initialHeight;a.setStyles({top:Math.max(0,y-(s/2)),width:M,height:s,marginLeft:-M/2,display:""});v=n||(I.currentStyle&&(I.currentStyle.position!="fixed"));if(v){I.style.position="absolute"}x.set(0).start(u.overlayOpacity);z();l(1);g=P;u.loop=u.loop&&(g.length>1);return b(O)}}})();
// AUTOLOAD CODE BLOCK (MAY BE CHANGED OR REMOVED)
Slimbox.scanPage = function() {
$$("a").filter(function(el) {
return el.rel && el.rel.test(/^lightbox/i);
}).slimbox({/* Put custom options here */}, null, function(el) {
return (this == el) || ((this.rel.length > 8) && (this.rel == el.rel));
});
};
if (!/android|iphone|ipod|series60|symbian|windows ce|blackberry/i.test(navigator.userAgent)) {
window.addEvent("domready", Slimbox.scanPage);
}
// cmscript: slideitmoo 
/**
SlideItMoo v1.1 - Image slider
(c) 2007-2008 Constantin Boiangiu <http://www.php-help.ro>
MIT-style license.
Changes from version 1.0
- added continuous navigation
- changed the navigation from Fx.Scroll to Fx.Morph
- added new parameters: itemsSelector: pass the CSS class for divs
- itemWidth: for elements with margin/padding pass their width including margin/padding
Updates ( August 4'th 2009 )
- added new parameter 'elemsSlide'. When this is set to a value lower that the actual number of elements in HTML, it will slide at once that number of elements when navigation clicked. Default: null
**/
var SlideItMoo = new Class({
Implements: [Options],
options: {
overallContainer: null,
elementScrolled: null,
thumbsContainer: null,	
itemsVisible:5,
elemsSlide: null,
itemsSelector: null,
itemWidth: null,
showControls:1,
transition: Fx.Transitions.linear,
duration: 800,
direction: 1,
autoSlide: false,
mouseWheelNav: false
},
initialize: function(options){
this.setOptions(options);
/* all elements are identified on CSS selector (itemsSelector) */
this.elements = $(this.options.thumbsContainer).getElements(this.options.itemsSelector);
this.totalElements = this.elements.length;
if( this.totalElements <= this.options.itemsVisible ) return;
// width of thumbsContainer children
this.elementWidth = this.options.itemWidth || this.elements[0].getSize().x;
this.currentElement = 0;
this.direction = this.options.direction;
this.autoSlideTotal = this.options.autoSlide + this.options.duration;
if( this.options.elemsSlide == 1 ) this.options.elemsSlide = null;
this.begin();
},
begin: function(){	
// resizes the container div's according to the number of itemsVisible thumbnails
this.setContainersSize();
this.myFx = new Fx.Morph(this.options.thumbsContainer, { 
wait: true, 
transition: this.options.transition,
duration: this.options.duration
});	
/* if navigation is needed and enabled, add it */
this.addControls();
/* if autoSlide is not set, scoll on mouse wheel */
if( this.options.mouseWheelNav && !this.options.autoSlide ){
$(this.options.thumbsContainer).addEvent('mousewheel', function(ev){
new Event(ev).stop();
this.slide(-ev.wheel);	
}.bind(this));
}
if( this.options.autoSlide )
this.startAutoSlide();	
},
setContainersSize: function(){
$(this.options.overallContainer).set({
styles:{
'width': this.options.itemsVisible * this.elementWidth + 50 * this.options.showControls
}
});
$(this.options.elementScrolled).set({
styles:{
'width': this.options.itemsVisible * this.elementWidth
}
});
$(this.options.thumbsContainer).set({
styles:{
'width': this.totalElements * (this.elementWidth + 10)	
}
});
},
addControls: function(){
if( !this.options.showControls ) return;
this.fwd = new Element('div', {
'class': 'SlideItMoo_forward',
'events':{
'click':this.slide.pass(1, this)
}
});
this.bkwd = new Element('div', {
'class': 'SlideItMoo_back',
'events':{
'click': this.slide.pass(-1, this)
}
});
$(this.options.overallContainer).adopt(this.fwd, this.bkwd);	
},
slide: function( direction ){
if(this.started) return;
this.direction = direction;
var currentIndex = this.currentIndex();
if( this.options.elemsSlide && this.options.elemsSlide>1 && this.endingElem==null ){
this.endingElem = this.currentElement;	
for(var i = 0; i < this.options.elemsSlide; i++ ){
this.endingElem += direction;
if( this.endingElem >= this.totalElements ) this.endingElem = 0;
if( this.endingElem < 0 ) this.endingElem = this.totalElements-1;
}
}	
if( this.direction == -1 ){
this.rearange();
$(this.options.thumbsContainer).setStyle('margin-left', -this.elementWidth);	
}
this.started = true;
this.myFx.start({ 
'margin-left': this.direction == 1 ? -this.elementWidth : 0 
}).chain( function(){	
this.rearange(true);	
if(this.options.elemsSlide){
if( this.endingElem !== this.currentElement ) this.slide(this.direction);
else this.endingElem=null;	
}
}.bind(this) );
},
rearange: function( rerun ){
if(rerun) this.started = false;
if( rerun && this.direction == -1 ) {
return;
}
this.currentElement = this.currentIndex( this.direction );
//$('debug').innerHTML+= this.currentElement+'<br>';
$(this.options.thumbsContainer).setStyle('margin-left',0);
if( this.currentElement == 1 && this.direction == 1 ){
this.elements[0].injectAfter(this.elements[this.totalElements-1]);
return;
}
if( (this.currentElement == 0 && this.direction ==1) || (this.direction==-1 && this.currentElement == this.totalElements-1) ){
this.rearrangeElement( this.elements.getLast(), this.direction == 1 ? this.elements[this.totalElements-2] : this.elements[0]);
return;
}
if( this.direction == 1 ){
this.rearrangeElement( this.elements[this.currentElement-1], this.elements[this.currentElement-2]);
}
else{
this.rearrangeElement( this.elements[this.currentElement], this.elements[this.currentElement+1]);
}	
},
rearrangeElement: function( element , indicator ){
this.direction == 1 ? element.injectAfter(indicator) : element.injectBefore(indicator);
},
currentIndex: function(){
var elemIndex = null;
switch( this.direction ){
/* forward */
case 1:
elemIndex = this.currentElement >= this.totalElements-1 ? 0 : this.currentElement + this.direction;	
break;
/* backwards */
case -1:
elemIndex = this.currentElement == 0 ? this.totalElements - 1 : this.currentElement + this.direction;
break;
}
return elemIndex;
},
startAutoSlide: function(){
this.startIt = this.slide.bind(this).pass(this.direction||1);
this.autoSlide = this.startIt.periodical(this.autoSlideTotal, this);
this.elements.addEvents({
'mouseover':function(){
$clear(this.autoSlide);	
}.bind(this),
'mouseout':function(){
this.autoSlide = this.startIt.periodical(this.autoSlideTotal, this);
}.bind(this)
})
}
})
// cmscript: fx
/* (c) 2009 CaribMedia
* this module defines and initiates nice effects
* preconditions:
* - MooTools available
*/
var openPopup;
(function() {
var cxlFx = new Class({
Implements: [Options],
options : {
hover : true,
popup: true,
zebra: true,
linkTracking: true,
tooltips: false,
picNav: false,
loginPopup: false,
flashClips: false,
accordion: false,
slider: false,
sifr: false,
rating:false,
nosifr: '',
calendar: false,
lightbox: true,
filmstrip: false
},
initialize: function(options){
this.setOptions(options);
var opt = this.options;
if (opt.hover) this.doAddHover();
if (opt.tooltips) this.tooltips();
if (opt.zebra) this.zebraStripes();
if (opt.picNav) this.pictureNavigation();
if (opt.loginPopup) this.loginPopup();
if (opt.linkTracking) this.addLinkTracking();
if (opt.flashClips) this.flashClips();
if (opt.accordion) this.accordion();
if (opt.slider) this.slider();
if (opt.popup) this.popup();
if (opt.rating) this.rating();
if (opt.sifr)
if (window.loadFonts)
//window.addEvent('load', function() {loadFonts(opt.nosifr)});
loadFonts(opt.nosifr);
if (opt.calendar && window.eventList)
this.showCalendar(eventList);
if (opt.lightbox) this.lightbox();
if (opt.filmstrip) this.filmstrip();
},
/*
* @name sfHover
* @description gives all input elements an effect
* @author Michiel van der Blonk
* @date Apr 6, 2006
*/
sfHover : function(addFocusFx) {
// add :hover and :focus support to internet explorer 5 and 6
// remove this code as soon as most common browsers support this
if (cxlEnv.isIE5or6)
{
var tagNames = ['p','li','ul','input','button','select','img'];
tagNames.each( function(tagName) {
$$(tagName).each( function(tag)
{
tag.addEvent('mouseenter', function() {tag.addClass('over');});
tag.addEvent('mouseleave', function() {tag.removeClass('over');});
if (addFocusFx)
{
tag.addEvent('focus', function() {tag.addClass('focus');});
tag.addEvent('blur', function() {tag.removeClass('focus');});
}
});
});
}
return true;
},
/*
* @name tooltips
* @description initiate tooltips
* @author Michiel van der Blonk
* @date Apr 6, 2006
*/
tooltips : function()
{
if (window.hasTooltips)
domTT_replaceTitles(null,"'styleClass', 'niceTitle', 'offsetX', 25, 'offsetY', -20, 'type', 'velcro', 'source', 'tt' ");
},
/*
* @name popup
* @description initiate popup effect
* @author Michiel van der Blonk
* @date June 16, 2006
* @source http://www.openhosting.co.uk/articles/webdev/5918/
*/
popup : function()
{
// check to see that the browser supports the getElementsByTagName method
// if not, exit the loop
if (!document.getElementsByTagName) {
return false;
}
// create an array of objects of each link in the document
var popuplinks = document.getElementsByTagName("a");
// loop through each of these links (anchor tags)
for (var i=0; i < popuplinks.length; i++)
{
// if the link has a class of "popup"...
cName = popuplinks[i].getAttribute("class");
if (!cName)
cName = popuplinks[i].className;
re = new RegExp("popup","ig");
if (cName && re.test(cName)) {
options = null;
if (new RegExp("popup-fullscreen","ig").test(cName))
options = "fullscreen";
if (new RegExp("popup-tiny","ig").test(cName))
options = "tiny";
if (new RegExp("popup-medium","ig").test(cName))
options = "medium";
if (new RegExp("popup-picture","ig").test(cName))
options = "picture";
if (new RegExp("popup-large","ig").test(cName))
options = "large";
// add an onclick event on the fly to pass the href attribute
// of the link to our second function, openPopUp
popuplinks[i].onclick = function() {
return openPopUp(this.getAttribute("href"), options);
};
}
}
return false;
},
openPopUp : function(linkURL, options, width, height) {
// default position in options
var position = 'screenX=300, screenY=250, top=250, left=300';
var resizable = "resizable=yes";
var scrollbars = "scrollbars=1";
var defaultOptions = resizable + ',' + scrollbars + ',' + position;
// define options
var popupOptions = {
'fullscreen': '',
'tiny' : 'width=250, height=150, ' + defaultOptions,
'small' : 'width=350, height=200, ' + defaultOptions,
'medium' : 'width=450, height=225, ' + defaultOptions,
'picture' : 'width=680, height=530, ' + defaultOptions,
'large' : 'width=800, height=600, ' + resizable + ',' + scrollbars
};
// get special ops
if (!options)
{
var sOptions = '';
if (width && height)
sOptions += 'width='+width + ', height='+height + ',';
sOptions += resizable + ',' + position;
}
else
sOptions = popupOptions[options];
var handle = window.open(linkURL, 'popup', sOptions);
handle.focus();
return false;
},
doAddHover : function(){
var addFocusFx = true;
this.sfHover(addFocusFx);
},
flashClips : function()
{
var clips = {
gallerybutton : 'gallerymovie',
menubutton: 'menumovie',
guestbutton: 'guestmovie',
eventsbutton: 'eventsmovie',
barbutton: 'barmovie'
// contactbutton: 'contactmovie' not doing anything special
};
var i;
for (button in clips)
{
var oButton = $(button);
//alert(oButton.id);
if (oButton) {
oButton.addEvent("click", function() {
// first set contentPane to overflow hidden to
// fix the 'screwed up movie' bug
var contentPane = $('contentPane');
if (contentPane)
contentPane.style.overflow = 'hidden';
// now play the movie! It's.... showtime!!!!
var oMovie = $(clips[this.id]);
this.style.display="none";
cxlFx.showhide(oMovie);
});
}
}
},
showhide : function(obj)
{
if (obj.style.display == "block")
obj.style.display = "none";
else
obj.style.display = "block";
},
switchMovie : function (buttonId, movieId)
{
var clips = {
gallerybutton : 'gallerymovie',
menubutton: 'menumovie',
guestbutton: 'guestmovie',
eventsbutton: 'eventsmovie',
barbutton: 'barmovie'
// contactbutton: 'contactmovie' not doing anything special
};
cxlFx.prototype.showhide($(buttonId));
cxlFx.prototype.showhide($(movieId));
},
flashInterface : function(id, eventName)
{
var oButton = document.getElementById(button);
if (eventName == 'click')
{
if (cxlEnv.isIE)
oButton.onclick();
}
},
zebraStripes : function()
{
$$('#contentPane table tr').each(function(el, count){
if (!el.hasClass('even') && !el.hasClass('odd'))
el.className += count % 2 === 0 ? 'odd' : 'even';
});
},
/*
* @name pictureNavigation
* @description setup the previous and next buttons
* @author Michiel van der Blonk
* @date January 13, 2008
*/
pictureNavigation : function()
{
if (!window.currentThumb)
window.currentThumb = 1;
var mainPictureField = $$('.field_main_picture img');
var prev = $('previousThumb');
var next = $('nextThumb');
if (!mainPictureField || !prev || !next)
return;
if (mainPictureField.length)
{
var mainPicture = mainPictureField[0];
mainPicture.addEvent("mouseover", function() {
prev.addClass('visible');
next.addClass('visible');
});
mainPicture.addEvent("mouseout", function(evt) {
if (evt.toElement && evt.toElement.tagName=='BUTTON')
return;
if (evt.relatedTarget && evt.relatedTarget.tagName=='BUTTON')
return;
prev.removeClass('visible');
next.removeClass('visible');
});
$('previousThumb').onclick = function() {
if (!$$('.field_picture' + (currentThumb-1) + ' img').length) return;
currentThumb--;
mainPicture.src = $$('.field_picture' + currentThumb + ' img')[0].src;
};
$('nextThumb').onclick = function() {
if (!$$('.field_picture' + (currentThumb+1) + ' img').length) return;
currentThumb++;
mainPicture.src = $$('.field_picture' + currentThumb + ' img')[0].src;
};
}
},
loginPopup : function() {
if (!$('memberInfo') || !$('login'))
return true;
if (!$('memberInfo').hasClass('layer'))
return true;
$('memberInfo').addClass('loginHide');
$('login').onclick = function() {
$('memberInfo').removeClass('loginHide');
$('memberInfo').addClass('loginShow');
return false;
};
return true;
},
addLinkTracking: function()
{
//suggested by remy
var host = window.location.host;
var url;
//go thru each link
$$('a').each(function(el)
{
//if rel tag is google then track what's inside brackets
//ex: google[download/thisfile]
if(el.rel && el.rel.match(/^google/i))
{
el.addEvent('click',function()
{
// var pageTracker = cxlEnv.pageTracker;
var track_id = this.rel.match(/^google\[(.*)\]$/);
if (track_id && window.pageTracker)
pageTracker._trackPageview(track_id[1]);
});
}
// track lnkinlte codes
if (el.href.match(/lnkinlte/i))
{
el.addEvent('click',function()
{
var track_id = this.href;
track_id = track_id.replace('http://' + host, '');
track_id = track_id.replace('/cgi-bin/redirect/lnkinlte.cgi?l=.','');
track_id = track_id.replace('cgi-bin/redirect/lnkinlte.cgi?l=.','');
if (track_id && window.pageTracker)
pageTracker._trackPageview('linklite/' + track_id);
});
}
// track external links
else if(el.host != host)
{
el.addEvent('click',function()
{
var track_id = this.href.match(/^http:\/\/([^\/]+)/);
// do not track ourselves
if (track_id && window.pageTracker && track_id[1] != 'www.visitaruba.com')
pageTracker._trackPageview('outgoing/'+track_id[1]);
});
}
});
},
accordion: function() {
if (!$('sidebarNav'))
return; 
if (window.MultipleOpenAccordion)
{
var sideToggle = new MultipleOpenAccordion($('sidebarNav'), {
elements: $$('#sidebarNav>div'),
togglers: $$('#sidebarNav>h2'),
openAll: false,
opacity: false,
firstElementsOpen:[5],
onActive: function(myToggler){myToggler.addClass('open');},
onBackground: function(myToggler){myToggler.removeClass('open');}
});
$('openAccordion').onclick = function() { sideToggle.showAll.call(sideToggle); };
$('closeAccordion').onclick = function() { sideToggle.hideAll.call(sideToggle); };
if ($('faqItems')) {
var faqToggle = new MultipleOpenAccordion($('faqItems'), {
elements: $$('.answer'),
togglers: $$('.question'),
openAll: false,
opacity: false,
onActive: function(myToggler){myToggler.addClass('open');},
onBackground: function(myToggler){myToggler.removeClass('open');}
});
}
//$('openAccordion').onclick = function() { sideToggle.showAll.call(sideToggle); };
//$('closeAccordion').onclick = function() { sideToggle.hideAll.call(sideToggle); };
}
},
rating: function() {
var mySlider = new Slider('myElement', 'myKnob', {
range: [-50, 50],
wheel: true,
snap: true,
onStart: function(){
this.borderFx = this.borderFx || this.element.tween('border').start('#ccc');
},
onTick: function(pos){
this.element.setStyle('border-color', '#f00');
this.knob.setStyle(this.property, pos);
},
onComplete: function(){
this.element.tween('border').start('#000');
}
});
},
slider: function() {
var el = $('featuredArticles'); 
if (!el)
return;
new SimpleCarousel(
el.id,
$$('#' + el.id + ' .article'),
$$('#num_nav .button'),
{rotateAction: 'click'}
);
var el2 = $('rotatingArticles');
if(!el2)
return;
new SimpleCarousel(
el2.id,
$$('#' + el2.id + ' .article'),
$$('#num_nav .button'),
{rotateAction: 'click'}
);
},
lightbox: function() {
if (!window.SqueezeBox)
return false;
SqueezeBox.initialize({size: {x: 725, y: 500}});
// SqueezeBox.assign($$('a[rel=lightbox]'));
SqueezeBox.assign($$('a[rel=boxed]'));
SqueezeBox.assign($$('a[class=boxed]'), {parse: 'rel'});
$$('a').each(function(el) {
/* if (el.href.match(/getContent.do.type=contact/)) {
var url = el.href;
if (!url.match(/inline=true/))
url += '&inline=true&width=450&height=450';
el.addEvent('click', function() {SqueezeBox.open(url, {size: {x: 500, y: 500}});return false;});
} */
});
},
filmstrip: function() {
/* new SlideItMoo({
overallContainer: 'strip1-outer',
elementScrolled: 'strip1-inner',
thumbsContainer: 'strip1',
itemsVisible:1,
elemsSlide:1,
duration:300,
itemsSelector: '.GalleryPhotoItem',
itemWidth: 300,
showControls:1});
*/
if (!$('strip'))
return false;
var strip = $('strip');
var stripWidth = $('strip-inner').getStyle('width').toInt();
var numShown = 3;
var width = (stripWidth / numShown).toInt();
var s = new Fx.Move(strip, {relativeTo:strip});
var numItems = $$('#strip li').length;
var edge = -(numItems-numShown-1) * width;
function setButtonState(position) {
$('previousGalleryItem').disabled = position >= 0;
$('nextGalleryItem').disabled = position < edge;
}
function getLeft(el) {
var position = el.getStyle('left').toInt();
return isNaN(position)?0:position;
}
if ($('previousGalleryItem')) {
$('previousGalleryItem').addEvent('click', function() {
position = getLeft(strip);
s.start({offset:{x:width, y:0}});
setButtonState(position+width);
});
}
if ($('nextGalleryItem')) {
$('nextGalleryItem').addEvent('click', function() {
position = getLeft(strip);
s.start({offset:{x:-width, y:0}});
setButtonState(position-width);
});
}
// for additional strip on the same page
var strip2 = $('strip2');
var stripWidth2 = 0;
if($('strip-inner2')) {
$('strip-inner2').getStyle('width').toInt();
}
var numShown2 = 3;
var width2 = (stripWidth2 / numShown2).toInt();
var s2 = new Fx.Move(strip2, {relativeTo:strip2});
var numItems2 = $$('#strip2 li').length;
var edge2 = -(numItems2-numShown2-1) * width;
function setButtonState2(position) {
$('previousGalleryItem2').disabled = position >= 0;
$('nextGalleryItem2').disabled = position < edge2;
}
function getLeft(el) {
var position = el.getStyle('left').toInt();
return isNaN(position)?0:position;
}
if ($('previousGalleryItem2')) {
$('previousGalleryItem2').addEvent('click', function() {
position = getLeft(strip2);
s2.start({offset:{x:width, y:0}});
setButtonState2(position+width);
});
}
if ($('nextGalleryItem2')) {
$('nextGalleryItem2').addEvent('click', function() {
position = getLeft(strip2);
s2.start({offset:{x:-width, y:0}});
setButtonState2(position-width);
});
}
},
showCalendar: function(eventDates) {
var addZero = function(n) { return n<10?'0'+(1*n):(1*n);};
if (!$('dynamic-calendar'))
{
var h3 = document.createElement('h3');
h3.innerHTML = 'Calendar of Events';
var d = document.createElement('div');
d.appendChild(h3);
d.setAttribute('id', 'dynamic-calendar');
var inp = document.createElement('input');
inp.setAttribute('id', 'date-select');
inp.setAttribute('type', 'text');
var curMonth = 1+1*(currentDate.substr(0, 2));
var curDay = currentDate.substr(2, 2);
var curYear = currentDate.substr(4, 4);
var curDate = '' + addZero(curMonth) + addZero(curDay) + curYear;
inp.setAttribute('value', curDate);
d.appendChild(inp);
$('contentPane').appendChild(d);
}
if (!$('dynamic-calendar'))
return false;
// extend calendar to have class names for linked days
var cxlPage = new cxlObject();
//cxlPage.blockedDates = eventDates;
cxlPage.showEvents = function(cal) {
if (cal.dateClicked) {
var y = cal.year;
var m = addZero(cal.month);
var d = addZero(cal.day);
url = '/getDailyEventCalendar.do?currentDate='+m+d+y;
location.href = url;
}
};
var cal = cxlPage.addCalendar('date-select', '', 'events');
cal.blockedDates = eventDates;
cxlPage.blockSundays = false;
cxlPage.initCalendars();
$('date-select').setStyle('visibility', 'hidden');
$$('#dynamic-calendar button')[0].setStyle('visibility', 'hidden');
}
});
window.addEvent('domready', function() {
var fx = new cxlFx({accordion:true, slider:true, sifr:false, nosifr:'home', calendar:true, filmstrip:true});
openPopUp = fx.openPopUp;
});
})();
// cmscript: cxlobject
/*
Author: Michiel van der Blonk
Date: Somewhere in 2006
Description:
cxlObject has generic form functions
- getForm
- imageSelect
- addCalendar
- initCalendars
- validateForm
Note: this file depends on MooTools to be loaded.
*/
var cxlObject = new Class( {
getForm: function()
{
return document.forms[this.formName];
},
imageSelect: function()
{
window.open(cxlPage.imageSelection + '?dispatch=images&id=' + cxlPage.id, 'image', 'width=750, height=400, screenX=300, screenY=100, top=100,left=300, resizable=yes');
},
addCalendar: function(fieldId, buttonId, sOptions)
{
if (!this.calendars)
this.calendars = new Array();
this.calendars[fieldId] = {field:fieldId, button:buttonId, options:sOptions, object:''};
this.blockDates = false;
if (sOptions!=null)
{
if (sOptions=='startdate')
this.startCalendar = fieldId;
if (sOptions=='enddate')
this.endCalendar = fieldId;
if (new RegExp('blockDates').test(sOptions))
this.blockDates = true;
if (sOptions=='events')
this.reverseBlocked = true;
}
return this.calendars[fieldId];
},
//utility functions for the calendars
invalidDate: function(d)
{
var startDateElement = this.startCalendar;
var startDate = Date.parseDate(startDateElement.value, "%m/%d/%Y");
return (d < startDate);
},
//utility functions for the calendars
blockRange: function(d)
{
var ret = true;
var out = '';
var i;
var startDate;
var endDate;
var options;
var curDate;
if (!this.blockedDates)
return false;
if (this.blockSundays)
if (d.getDay()==0) // block all sundays
ret = true;
var blockedDates = this.blockedDates;
ret = false;
for (i=0;i<blockedDates.length;i++)
{
startDate = new Date(blockedDates[i].start);
endDate = new Date(blockedDates[i].end);
// add one day, so end date behaves properly
endDate.setDate(endDate.getDate()+1);
options = blockedDates[i].options;
curDate = new Date(d);
if (options=='yearly')
curDate.setYear(startDate.getFullYear());
if (curDate>=startDate && curDate<=endDate)
ret = true;
}
if (this.reverseBlocked)
return !ret;
else
return ret;
},
setEndDate: function (cal)
{
var startDateElement = this.startCalendar;
var endDateElement = this.endCalendar;
if (startDateElement.value !== '' && endDateElement.value === '')
endDateElement.value = startDateElement.value;
},
initCalendars: function() {
var i;
for (i in this.calendars)
{
var calendar = this.calendars[i];
if (typeof calendar == "object" && $(calendar.field))
{
var that = this;
var format={};
format[calendar.field] = 'm/d/Y';
var options = { tweak: {x:-20, y:0}, draggable:false};
switch(calendar.options)
{
case 'startdate':
this.calendars[i].object = new Calendar(format, options);
break;
case 'enddate':
this.calendars[i].object = new Calendar(format, options);
break;
case 'blockDates':
this.calendars[i].object = new Calendar(format, options);
break;
case 'events':
format[calendar.field] = 'mdY';
this.calendars[i].object = new Calendar(
format, { tweak: {x:-20, y:0}, draggable:false, permanent:true, blocked:this.calendars[i].blockedDates, parentNode: 'dynamic-calendar' });
var cal = this.calendars[i].object;
this.calendars[i].object.clicked = function(td, day, cal) {
cal.val = (this.value(cal) == day) ? null : new Date(cal.year, cal.month, day); // set new value - if same then disable
/* once Otmar fixed the month -1 problem we can use this
var date = this.format(cal.val, cal.el.format);
*/
var addZero = function(n) {	return n<10?'0'+n:n;};
var y = cal.val.getFullYear();
var m = addZero(cal.val.getMonth());
var d = addZero(cal.val.getDate());
var date = ''+m+d+y;
var url = '/getDailyEventCalendar.do?currentDate=' + date;
location.href = url;
};
cal.toggle(cal.calendars[0]);
break;
default:
this.calendars[i].object = new Calendar(format, options);
break;
}
}
}
},
initSliders:	function() {
function setupSlider(id)
{
var slider = new Element('div').set(
{
'id':id+'_slider', 
'styles': 
{
'width': '72px', 
'height':'12px', 
'background': 'url(/visitaruba/styles/member/visitaruba/bg_rating_stars2.jpg) no-repeat -60px 0',
'position':'relative',	
'left':'12em',
'font-size':'10px',
'line-height':'10px'
}
}).injectAfter($(id));
new Element('div').set(
{
'id':id+'_knob', 
'class':'knob',
'styles':{
'width': '12px', 
'height': '11px',
'position' : 'absolute',
'font-size':'10px',
'line-height':'10px',
'background':'url(/visitaruba/styles/member/visitaruba/bg_bullet.gif) no-repeat center center'
}	
}).inject(slider);	
return slider;
}
$$('form .slider').each(
function(el) {
var slider = setupSlider(el.id);
// Create the new slider instance
new Slider(slider, slider.getElement('.knob'), {
steps: 5,	// There are 5 steps
wheel: true,
snap: true,
range: [0,5],	// Minimum value is 0
onChange: function(value){
if (!$defined(value) || isNaN(value))
value = 0;
// Everytime the value changes, we change the select element
el.value = value;
var knobWidth = parseInt(slider.style.width) / (this.steps+1);
var pos = (this.steps-value) * knobWidth * -1;
$('comments').innerText += pos;
slider.setStyle('background-position', "" + (knobWidth+pos) + 'px 0');
slider.set('title', $chk(value)?'no rating':value+' stars');
}
}).set('value', el.value.toInt());
//el.hide();
}
);
},
isDate: function(d, formatted) {
var ret = false;
var date = new Date(d);
// it's at least a number
if (!isNaN(date))
{
if (formatted)
{
var day = date.getDate();
var month = date.getMonth()+1;
var year = date.getFullYear();
var dateString = '' + month + '.' + day + '.' + year;
var pattern = new RegExp(dateString);
ret = pattern.test(d);
}
else
ret = true;
}
return ret;
},
/*
* @Date: Somewhere 2006
* @Description: Validate fields based on class name
* example: class="validation-date" will be
* matched against mm/dd/yy, or a valid Date object
**/
validateForm: function(frm, target)
{
var i;
var ret = true;
var field;
var out='';
var errorFields = [];
if (target==null)
target = 'errors';
// loop through all fields
// check if they have validation class name
// and do appropriate validation
// @return true, if all validation passes
for (i=0; i<frm.elements.length; i++)
{
field = frm.elements[i];
// skip disabled fields
if (field.disabled)
continue;
// validate required fields
filter = /validation-required/;
if (filter.test(field.className))
{
if (field.type=='checkbox' && !field.checked)
{
out += 'Please check the ' + field.name + ' box<br />';
errorFields.push(field);
ret = false;
}
else
if (field.value==='')
{
out += 'Please enter a value for ' + field.name + '<br />';
errorFields.push(field);
ret = false;
}
}
// validate numeric fields
filter = /validation-number/;
if (filter.test(field.className))
{
if (field.value!=='' && !isNaN(field.value))
{
out += 'Please enter a number for ' + field.name + '<br />';
errorFields.push(field);
ret = false;
}
}
// validate digit only fields
filter = /validation-digits/;
if (filter.test(field.className))
{
var filter = /^[0-9]+$/;
if (field.value!=='' && !filter.test(field.value))
{
out += 'Please enter a number for ' + field.name + '<br />';
errorFields.push(field);
ret = false;
}
}
// validate date fields
filter = /validation-date/;
if (filter.test(field.className))
{
if (field.value!=='' && !isDate(field.value, true))
{
out += 'Please enter a valid date (mm/dd/yyyy) in ' + field.name + '<br />';
errorFields.push(field);
ret = false;
}
}
// validate email addresses
filter = /format-email/;
if (filter.test(field.className))
{
filter = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
if (field.value!=='' && !filter.test(field.value))
{
out += 'Please enter a valid email address in ' + field.name + '<br />';
errorFields.push(field);
ret = false;
}
}
// validate credit cards
// this uses Luhn validation
// which is a numeric algorithm
filter = /format-creditcard/;
if (filter.test(field.className))
{
filter = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
if (field.value!=='' && !this.isValidCreditCard(field.value))
{
out += 'Please enter a valid credit card number' + '<br />';
errorFields.push(field);
ret = false;
}
}
// validate urls
filter = /format-url/;
if (filter.test(field.className))
{
filter = /^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(([0-9]{1,5})?\/.*)?$/i;
if (field.value!=='' && !filter.test(field.value))
{
out += 'Please enter a valid url' + '<br />';
errorFields.push(field);
ret = false;
}
}
// validate verification fields
filter = /validation-match/;
if (filter.test(field.className))
{
var otherField = field.className.replace(/.*validation-match-/,'').replace(/ .*/,'');
if (field.value!=='' && field.value!=$(otherField).value)
{
out += 'The value in ' + field.name + ' does not match ' + otherField + '<br />';
errorFields.push(field);
ret = false;
}
}
$(field).removeClass('error');
}
$(target).innerHTML = out;
// indicate errors
for (i = 0; i < errorFields.length; i++)
$(errorFields[i]).addClass('error');
window.scroll(0,0);
return ret;
},
/*
* @Date: Feb 21, 2005
* @Description: This function strips defined chars from a string
* useful in validation routines
* example: stripChars(str, "()-") returns the string with any
* brackets and dashes removed
**/
stripChars : function(str, chars) {
var i;
var newstring = "";
for (i = 0; i < str.length; i++) {
mychar = str.charAt(i);
if (chars.indexOf(mychar) == -1)
newstring += mychar;
}
return newstring;
},
/**
* @Date: Feb 21, 2005
* @Description: This function extracts defined chars from a string
* useful in validation routines
* it is 'sort of' the reverse of stripChars
* example: extractChars(str, "0123456789") returns all digits from the string
**/
extractChar: function(str, chars) {
var i;
var newstring = "";
for (i = 0; i < str.length; i++) {
mychar = str.charAt(i);
if (chars.indexOf(mychar) != -1)
newstring += mychar;
}
return newstring;
},
/**
* @Date: Dec 1, 2004
* @Description: This function tests a credit card using the Luhn validation
* The sum of digits must be divisible by 10
* digits in odd positions are doubled, then sum of left+right digit is taken
**/
isValidCreditCard: function(sCreditCardNumber)
{
var nTotal = 0;
var nPosition = 0;
var bValid = true; // innocent until proven guilty
sCreditCardNumber = this.extractChars(sCreditCardNumber, "0123456789");
if (sCreditCardNumber.length < 13)
bValid = false;
else
{
for ( i = sCreditCardNumber.length; i > 0 ; i--)
{
var nDigit = 0;
// advance
nPosition++;
// get digit
nDigit= parseInt(sCreditCardNumber.charAt(i-1));
// odd position: add to total
if ((nPosition % 2) !== 0)
nTotal += parseInt(nDigit);
else
// even position: add sum of digits to total
{
// calc sum of left and right digit (use parseInt to cut off fractional parts
var nDoubled = nDigit * 2;
var nLeftDigit = parseInt(nDoubled / 10);
var nRightDigit = nDoubled % 10;
// get sum of left and right
nTotal += nLeftDigit + nRightDigit;
}
}
// if divisible by 10 it is valid
bValid = (nTotal % 10) === 0;
}
return (bValid);
},
// utility functions for the form
setDispatch: function(value, frm) {
// default to cxlPage.getForm()
if (typeof frm=="undefined")
{
if (window.cxlPage && window.cxlPage.getForm())
frm = cxlPage.getForm();
else
return false;
}
frm.dispatch.value = value;
return true;
},
submitForm: function(target) {
if (!window.cxlPage || !window.cxlPage.getForm())
return false;
this.setDispatch(target, window.cxlPage.getForm());
window.cxlPage.getForm().submit();
return false;
},
initNeverExpires: function() {
if (!window.cxlPage || !window.cxlPage.getForm())
return;
var frm = window.cxlPage.getForm();
if (frm.neverExpire)
frm.neverExpire.checked = (frm.expirationDate.value === '');
},
checkFeatured: function() {
if (!window.cxlPage || !window.cxlPage.getForm())
return;
var frm = cxlPage.getForm();
if (frm.pressRelease)
frm.pressRelease.checked = false;
},
checkPressRelease: function() {
if (!window.cxlPage || !window.cxlPage.getForm())
return;
var frm = window.cxlPage.getForm();
if (frm.featured)
frm.featured.checked = false;
},
deleteImage: function(image) {
if (!window.cxlPage || !window.cxlPage.getForm())
return;
var frm = window.cxlPage.getForm();
if (confirm(window.cxlPage.confirmDelete)) {
var theLink = window.cxlPage.imageSelection + '?dispatch=delete&id=' + image;
window.location.href = theLink;
}
}
}
);
// cmscript: map
// cxlObject.map = {
var map;
function createMarker(point, options, item)
{
var icon = new GIcon();
icon.image = 'http://gmaps-samples.googlecode.com/svn/trunk/markers/circular/greencirclemarker.png';
icon.image = '/styles/member/visitaruba/list-' + item.listId + '.png';
icon.shadow = '/styles/member/visitaruba/list-' + item.listId + '-shadow.png';
icon.iconSize = new GSize(24, 24);
icon.shadowSize = new GSize(37, 24);
icon.iconAnchor = new GPoint(24, 24);
icon.infoWindowAnchor = new GPoint(25, 7);
options.icon = icon;
options.title = item.name;
// opts = { "icon": icon,"clickable": true,"title": item.name,"labelText": item.name,"labelOffset": new GSize(-6, -10)};
//var marker = new LabeledMarker(point, opts);
var marker = new GMarker(point, options);
var itemName = item.name;
GEvent.addListener(marker, "click", function() {
// NB: below is a link to the listing item page
// var link = "/listId/" + item.listId + "/id/" + item.id + '/getListingItem.html';
if (item.readMore.substr(0,1)!='/' && item.readMore.substr(0,7)!='http://')
var link = "/" + item.readMore;
var html= '<p style="color:navy">' + itemName + '</p>';
//	html += listItem.desc;
//	html += '<img width="100" src="'+item.picture+'"/>';
if (item.readMore!='null')
html += '<a href="' + link + '">[read more]</a>'
marker.openInfoWindow(html);
});
return marker;
}
function addIcons(items)
{
// Create our "tiny" marker icon
var markerIcon = new GIcon();
// markerIcon.image = '/styles/member/visitaruba/list-' + item.listId + '.png';
//	markerIcon.shadow = '/styles/member/visitaruba/list-' + item.listId + '-shadow.png';
markerIcon.image = "http://labs.google.com/ridefinder/images/mm_20_red.png";
markerIcon.shadow = "http://labs.google.com/ridefinder/images/mm_20_shadow.png";
markerIcon.iconSize = new GSize(41, 51);
markerIcon.shadowSize = new GSize(41, 51);
markerIcon.iconAnchor = new GPoint(6, 20);
markerIcon.infoWindowAnchor = new GPoint(5, 1);
var altIcon = new GIcon(G_DEFAULT_ICON);
altIcon.image = "http://www.google.com/intl/en_us/mapfiles/ms/micons/blue-dot.png";
altIcon.iconSize = new GSize(32, 32);
// Set up our GMarkerOptions object
var markerOptions = { icon:markerIcon };
var altOptions = { icon:altIcon };
var bounds = map.getBounds();
for (var i = 0; i < items.length; i++) {
var item = items[i];
var point = new GLatLng(item.latitude,item.longitude);
map.addOverlay(createMarker(point, altOptions, item));
}
var topRight = new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(10,10));
var topRightBelow = new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(10,40));
var bottomLeftUp = new GControlPosition(G_ANCHOR_BOTTOM_LEFT, new GSize(10,40));
map.addControl(new GSmallZoomControl());
map.addControl(new GOverviewMapControl());
map.addControl(new GMapTypeControl(), topRight);
map.addControl(new GScaleControl(), bottomLeftUp);
}
function hideMap()
{
var mapTag = $('map');
var mapContainer = $('mapContainer');
mapTag.className="hide";
mapContainer.setStyle('z-index', -1);
mapContainer.setStyle('visibility', 'hidden');
}
function loadMap() {
var mapLink = this;
if ($('closeMap'))
$('closeMap').onclick = hideMap;
$('map').className = '';
var mapContainer = $('mapContainer');
if (!mapContainer)
return true;
showMap('map', listItems, listItems[0].latitude, listItems[0].longitude, 15);
mapContainer.setStyle('z-index', 10);
mapContainer.setStyle('visibility', 'visible');
mapContainer.makeDraggable();
return false;
}
function showMap(id, items, latitude, longitude, zoom) {
if (!$(id))
return;
if (!latitude)
latitude = 12.569601;
if (!longitude)
longitude = -70.043635;
if (!zoom)
zoom = 12;
if (window.GMap2) {
var mapTag = $(id);
if (GBrowserIsCompatible()) {
map = new GMap2(mapTag);
map.setCenter(new GLatLng(latitude, longitude, longitude), zoom);
addIcons(items);
}
}
else
$('contentPane').innerHTML = '<p class="alert">Maps are temporarily not available. Try again later.</p>' + $('contentPane').innerHTML ;
return false;
}
// init, should be done in calculated field
function initMap()
{
var mapLink;
window.addEvent('unload', function() {if (window.GUnload) {GUnload();}});
if ($$)
mapLink = $$('.field_map a'); // document.getElementById("mapLink");
if (mapLink && mapLink.length)
{
mapLink = mapLink[0];
mapLink.onclick = loadMap;
}
}
window.addEvent('load', initMap);
// cmscript: pictureNavigator 
/*
* @name
* @description initiate image effects
* @author Michiel van der Blonk
* @date May 13, 2008
*/
window.addEvent("load", function()
{
if (!$('strip'))
$$('#contentPane #thumbs img').each(function(thumb){
thumb.onclick = function(){$('mainPicture').src = thumb.src;};
});
}
);
// cmscript: onLoadActions
// clear menus
// if (location.pathname.match(/listing/i)==null)
//	setMenuCookie(-1);
if (typeof onLoadActions=='function')
{
if (typeof addEvent=='function')
{
if (window.MooTools)
window.addEvent("domready", onLoadActions);
else
addEvent(window, "load", onLoadActions);
}
else
window.onload = onLoadActions;
}
