var Cookie =
{
read: function (name)
{
if (typeof(document.cookie) != "string" && navigator.product == "Gecko") delete HTMLDocument.prototype.cookie;
var arrCookies = document.cookie.split ('; ');
for (var i=0; i<arrCookies.length; i++)
{
var arrCookie = arrCookies[i].split ('=');
if (arrCookie[0] == name)
{
return decodeURIComponent (arrCookie[1]);
}
}
return false;
},
write: function (name, value, expires, path)
{
if (typeof(document.cookie) != "string" && navigator.product == "Gecko") delete HTMLDocument.prototype.cookie;
if (expires)
{
var date = new Date ();
date.setTime (date.getTime () + (((((expires * 24) * 60) * 60) * 1000)));
expires = '; expires=' + date.toGMTString ();
}
else expires = '';
if (!path) path = '/';
document.cookie = name+'='+encodeURIComponent (value)+expires+'; path='+path;
},
remove: function (name)
{
this.write (name, '', -1);
}
}
function browserSupportsCookies()
{
Cookie.write('cookiesEnabled', 1);
var boolCookiesEnabled = Cookie.read('cookiesEnabled');
Cookie.remove('cookiesEnabled');
if (boolCookiesEnabled != 1)
{
return false;
}
return true;
}
function browserSupportsAjax()
{
if (typeof XMLHttpRequest == "undefined" && typeof ActiveXObject == "undefined" && window.createRequest == "undefined")
{
return false;
}
return true
}
function ActiveXEnabledOrUnnecessary ()
{
if (typeof ActiveXObject != "undefined")
{
var xhr = null;
try{
xhr=new ActiveXObject("Msxml2.XMLHTTP");
}catch (e){
try{
xhr=new ActiveXObject("Microsoft.XMLHTTP");
}catch (e2){
try{
xhr=new ActiveXObject("Msxml2.XMLHTTP.4.0");
}catch (e3){
xhr=null;
}
}
}
if (xhr == null)
{
return false
}
}
return true;
}
/**
* A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
* Digest Algorithm, as defined in RFC 1321.
*
* Extends string prototype with the following method:
* md5
*
* This extensions doesn't depend on any other code or overwrite existing methods.
*
*
* The Initial Developer of the Original Code is
* Paul Johnston
* Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
*
* Distributed under the BSD License
* See http://pajhome.org.uk/crypt/md5 for more info.
*
*
* Contributor(s):
* Harald Hanek <harald.hanek@gmail.com>
*
* Copyright (c) 2007 Harald Hanek (http://js-methods.googlecode.com)
*
* Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
* and GPL (http://www.gnu.org/licenses/gpl.html) licenses.
*
* @author Harald Hanek
* @version 0.9
* @lastchangeddate 10. October 2007 18:01:32
* @revision 876
*/
(function(){
var md5 =
{
hexcase : 0, /* hex output format. 0 - lowercase; 1 - uppercase */
b64pad : "", /* base-64 pad character. "=" for strict RFC compliance */
chrsz : 8, /* bits per input character. 8 - ASCII; 16 - Unicode */
/**
* These are the functions you'll usually want to call
* They take string arguments and return either hex or base-64 encoded strings
*/
'hex_md5' : function(s)
{
return this.binl2hex(this.core_md5(this.str2binl(s), s.length * this.chrsz));
},
'b64_md5' : function(s)
{
return this.binl2b64(this.core_md5(this.str2binl(s), s.length * this.chrsz));
},
'str_md5' : function(s)
{
return this.binl2str(this.core_md5(this.str2binl(s), s.length * this.chrsz));
},
'hex_hmac_md5' : function(key, data)
{
return this.binl2hex(this.core_hmac_md5(key, data));
},
'b64_hmac_md5' : function(key, data)
{
return this.binl2b64(this.core_hmac_md5(key, data));
},
'str_hmac_md5' : function(key, data)
{
return this.binl2str(this.core_hmac_md5(key, data));
},
/**
* Calculate the MD5 of an array of little-endian words, and a bit length.
*
*/
'core_md5' : function(x, len)
{
x[len >> 5] |= 0x80 << ((len) % 32);
x[(((len + 64) >>> 9) << 4) + 14] = len;
var a = 1732584193;
var b = -271733879;
var c = -1732584194;
var d = 271733878;
for(var i = 0; i < x.length; i += 16)
{
var olda = a;
var oldb = b;
var oldc = c;
var oldd = d;
a = this.md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
d = this.md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
c = this.md5_ff(c, d, a, b, x[i+ 2], 17, 606105819);
b = this.md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
a = this.md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
d = this.md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426);
c = this.md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
b = this.md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
a = this.md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416);
d = this.md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
c = this.md5_ff(c, d, a, b, x[i+10], 17, -42063);
b = this.md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
a = this.md5_ff(a, b, c, d, x[i+12], 7 , 1804603682);
d = this.md5_ff(d, a, b, c, x[i+13], 12, -40341101);
c = this.md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
b = this.md5_ff(b, c, d, a, x[i+15], 22, 1236535329);
a = this.md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
d = this.md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
c = this.md5_gg(c, d, a, b, x[i+11], 14, 643717713);
b = this.md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
a = this.md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
d = this.md5_gg(d, a, b, c, x[i+10], 9 , 38016083);
c = this.md5_gg(c, d, a, b, x[i+15], 14, -660478335);
b = this.md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
a = this.md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438);
d = this.md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
c = this.md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
b = this.md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501);
a = this.md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
d = this.md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
c = this.md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473);
b = this.md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
a = this.md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
d = this.md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
c = this.md5_hh(c, d, a, b, x[i+11], 16, 1839030562);
b = this.md5_hh(b, c, d, a, x[i+14], 23, -35309556);
a = this.md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
d = this.md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353);
c = this.md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
b = this.md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
a = this.md5_hh(a, b, c, d, x[i+13], 4 , 681279174);
d = this.md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
c = this.md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
b = this.md5_hh(b, c, d, a, x[i+ 6], 23, 76029189);
a = this.md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
d = this.md5_hh(d, a, b, c, x[i+12], 11, -421815835);
c = this.md5_hh(c, d, a, b, x[i+15], 16, 530742520);
b = this.md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
a = this.md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
d = this.md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415);
c = this.md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
b = this.md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
a = this.md5_ii(a, b, c, d, x[i+12], 6 , 1700485571);
d = this.md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
c = this.md5_ii(c, d, a, b, x[i+10], 15, -1051523);
b = this.md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
a = this.md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359);
d = this.md5_ii(d, a, b, c, x[i+15], 10, -30611744);
c = this.md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
b = this.md5_ii(b, c, d, a, x[i+13], 21, 1309151649);
a = this.md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
d = this.md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
c = this.md5_ii(c, d, a, b, x[i+ 2], 15, 718787259);
b = this.md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
a = this.safe_add(a, olda);
b = this.safe_add(b, oldb);
c = this.safe_add(c, oldc);
d = this.safe_add(d, oldd);
}
return Array(a, b, c, d);
},
/**
* These functions implement the four basic operations the algorithm uses.
*
*/
'md5_cmn' : function(q, a, b, x, s, t)
{
return this.safe_add(this.bit_rol(this.safe_add(this.safe_add(a, q), this.safe_add(x, t)), s),b);
},
'md5_ff' : function(a, b, c, d, x, s, t)
{
return this.md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
},
'md5_gg' : function(a, b, c, d, x, s, t)
{
return this.md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
},
'md5_hh' : function(a, b, c, d, x, s, t)
{
return this.md5_cmn(b ^ c ^ d, a, b, x, s, t);
},
'md5_ii' : function(a, b, c, d, x, s, t)
{
return this.md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
},
/**
* Calculate the HMAC-MD5, of a key and some data.
*
*/
'core_hmac_md5' : function(key, data)
{
var bkey = this.str2binl(key);
if(bkey.length > 16)
bkey = this.core_md5(bkey, key.length * this.chrsz);
var ipad = Array(16), opad = Array(16);
for(var i = 0; i < 16; i++)
{
ipad[i] = bkey[i] ^ 0x36363636;
opad[i] = bkey[i] ^ 0x5C5C5C5C;
}
var hash = this.core_md5(ipad.concat(this.str2binl(data)), 512 + data.length * this.chrsz);
return this.core_md5(opad.concat(hash), 512 + 128);
},
/**
* Add integers, wrapping at 2^32. This uses 16-bit operations internally
* to work around bugs in some JS interpreters.
*
*/
'safe_add' : function(x, y)
{
var lsw = (x & 0xFFFF) + (y & 0xFFFF);
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
return (msw << 16) | (lsw & 0xFFFF);
},
/**
* Bitwise rotate a 32-bit number to the left.
*
*/
'bit_rol' : function(num, cnt)
{
return (num << cnt) | (num >>> (32 - cnt));
},
/**
* Convert a string to an array of little-endian words.
* If this.chrsz is ASCII, characters >255 have their hi-byte silently ignored.
*
*/
'str2binl' : function(str)
{
var bin = Array();
var mask = (1 << this.chrsz) - 1;
for(var i = 0; i < str.length * this.chrsz; i += this.chrsz)
bin[i>>5] |= (str.charCodeAt(i / this.chrsz) & mask) << (i%32);
return bin;
},
/**
* Convert an array of little-endian words to a string
*
*/
'binl2str' : function(bin)
{
var str = "";
var mask = (1 << this.chrsz) - 1;
for(var i = 0; i < bin.length * 32; i += this.chrsz)
str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask);
return str;
},
/**
* Convert an array of little-endian words to a hex string.
*
*/
'binl2hex' : function(binarray)
{
var hex_tab = this.hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
var str = "";
for(var i = 0; i < binarray.length * 4; i++)
{
str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
hex_tab.charAt((binarray[i>>2] >> ((i%4)*8 )) & 0xF);
}
return str;
},
/**
* Convert an array of little-endian words to a base-64 string
*
*/
'binl2b64' : function(binarray)
{
var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var str = "";
for(var i = 0; i < binarray.length * 4; i += 3)
{
var triplet = (((binarray[i >> 2] >> 8 * ( i %4)) & 0xFF) << 16)
| (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 )
| ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF);
for(var j = 0; j < 4; j++)
{
if(i * 8 + j * 6 > binarray.length * 32)
str += this.b64pad;
else
str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
}
}
return str;
}
};
/**
* Returns the md5 hash of the given string.
*
* @example "JavaScript".md5();
* @result "686155af75a60a0f6e9d80c1f7edd3e9"
*
* @name md5
* @return String
*/
if(!String.prototype.md5)
String.prototype.md5 = function()
{
return md5.hex_md5(this);
}
})();
function setCookie(name, value, expires, path, domain, secure) {
var curCookie = name + '=' + escape(value) + ((expires) ? '; expires=' + expires.toGMTString() : '') + ((path) ? '; path=' + path : '') + ((domain) ? '; domain=' + domain : '') + ((secure) ? '; secure' : '');
document.cookie = curCookie;
}
function getCookie(name) {
var dc = document.cookie;
var prefix = name + "=";
var begin = dc.indexOf("; " + prefix);
if (begin == -1) {
begin = dc.indexOf(prefix);
if (begin != 0) return null;
}
else begin += 2;
var end = document.cookie.indexOf(";", begin);
if (end == -1) end = dc.length;
return unescape(dc.substring(begin + prefix.length, end));
}
function deleteCookie(name, path, domain) {
var value = getCookie(name);
if (value != null) document.cookie = name + '=' + ((path) ? '; path=' + path : '') + ((domain) ? '; domain=' + domain : '') + '; expires=Thu, 01-Jan-70 00:00:01 GMT';
return value;
}
function fixDate(date) {
var workingDate = date;
var base = new Date(0);
var skew = base.getTime();
if (skew > 0) workingDate.setTime(workingDate.getTime() - skew);
return workingDate;
}
function supportsCookies(rootPath) {
setCookie('checking_for_cookie_support', 'testing123', '', (rootPath != null ? rootPath : ''));
if (getCookie('checking_for_cookie_support')) return true;
else return false;
}
function preloadImages() {
if (document.images) {
for (var i = 0; i < preloadImages.arguments.length; i++) {
(new Image()).src = preloadImages.arguments[i];
}
}
}
function indexOf(array, object)
{
for (var i = 0; i < array.length; i++)
if (array[i] == object) return i;
return -1;
}
function without(array,value) {
var res = Array();
for( var i = 0 ; i < array.length; i++)
{
if (array[i] != value) res.push(array[i]);
}
return res;
}
/* Prototype JavaScript framework, version 1.6.0.2
* (c) 2005-2008 Sam Stephenson
*
* Prototype is freely distributable under the terms of an MIT-style license.
* For details, see the Prototype web site: http://www.prototypejs.org/
*
*--------------------------------------------------------------------------*/
var Prototype = {
Version: '1.6.0.2',
Browser: {
IE: !!(window.attachEvent && !window.opera),
Opera: !!window.opera,
WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
Gecko: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1,
MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/)
},
BrowserFeatures: {
XPath: !!document.evaluate,
ElementExtensions: !!window.HTMLElement,
SpecificElementExtensions:
document.createElement('div').__proto__ &&
document.createElement('div').__proto__ !==
document.createElement('form').__proto__
},
ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>',
JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/,
emptyFunction: function() { },
K: function(x) { return x }
};
if (Prototype.Browser.MobileSafari)
Prototype.BrowserFeatures.SpecificElementExtensions = false;
/* Based on Alex Arnell's inheritance implementation. */
var Class = {
create: function() {
var parent = null, properties = $A(arguments);
if (Object.isFunction(properties[0]))
parent = properties.shift();
function klass() {
this.initialize.apply(this, arguments);
}
Object.extend(klass, Class.Methods);
klass.superclass = parent;
klass.subclasses = [];
if (parent) {
var subclass = function() { };
subclass.prototype = parent.prototype;
klass.prototype = new subclass;
parent.subclasses.push(klass);
}
for (var i = 0; i < properties.length; i++)
klass.addMethods(properties[i]);
if (!klass.prototype.initialize)
klass.prototype.initialize = Prototype.emptyFunction;
klass.prototype.constructor = klass;
return klass;
}
};
Class.Methods = {
addMethods: function(source) {
var ancestor = this.superclass && this.superclass.prototype;
var properties = Object.keys(source);
if (!Object.keys({ toString: true }).length)
properties.push("toString", "valueOf");
for (var i = 0, length = properties.length; i < length; i++) {
var property = properties[i], value = source[property];
if (ancestor && Object.isFunction(value) &&
value.argumentNames().first() == "$super") {
var method = value, value = Object.extend((function(m) {
return function() { return ancestor[m].apply(this, arguments) };
})(property).wrap(method), {
valueOf: function() { return method },
toString: function() { return method.toString() }
});
}
this.prototype[property] = value;
}
return this;
}
};
var Abstract = { };
Object.extend = function(destination, source) {
for (var property in source)
destination[property] = source[property];
return destination;
};
Object.extend(Object, {
inspect: function(object) {
try {
if (Object.isUndefined(object)) return 'undefined';
if (object === null) return 'null';
return object.inspect ? object.inspect() : String(object);
} catch (e) {
if (e instanceof RangeError) return '...';
throw e;
}
},
toJSON: function(object) {
var type = typeof object;
switch (type) {
case 'undefined':
case 'function':
case 'unknown': return;
case 'boolean': return object.toString();
}
if (object === null) return 'null';
if (object.toJSON) return object.toJSON();
if (Object.isElement(object)) return;
var results = [];
for (var property in object) {
var value = Object.toJSON(object[property]);
if (!Object.isUndefined(value))
results.push(property.toJSON() + ': ' + value);
}
return '{' + results.join(', ') + '}';
},
toQueryString: function(object) {
return $H(object).toQueryString();
},
toHTML: function(object) {
return object && object.toHTML ? object.toHTML() : String.interpret(object);
},
keys: function(object) {
var keys = [];
for (var property in object)
keys.push(property);
return keys;
},
values: function(object) {
var values = [];
for (var property in object)
values.push(object[property]);
return values;
},
clone: function(object) {
return Object.extend({ }, object);
},
isElement: function(object) {
return object && object.nodeType == 1;
},
isArray: function(object) {
return object != null && typeof object == "object" &&
'splice' in object && 'join' in object;
},
isHash: function(object) {
return object instanceof Hash;
},
isFunction: function(object) {
return typeof object == "function";
},
isString: function(object) {
return typeof object == "string";
},
isNumber: function(object) {
return typeof object == "number";
},
isUndefined: function(object) {
return typeof object == "undefined";
}
});
Object.extend(Function.prototype, {
argumentNames: function() {
var names = this.toString().match(/^[\s\(]*function[^(]*\((.*?)\)/)[1].split(",").invoke("strip");
return names.length == 1 && !names[0] ? [] : names;
},
bind: function() {
if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;
var __method = this, args = $A(arguments), object = args.shift();
return function() {
return __method.apply(object, args.concat($A(arguments)));
}
},
bindAsEventListener: function() {
var __method = this, args = $A(arguments), object = args.shift();
return function(event) {
return __method.apply(object, [event || window.event].concat(args));
}
},
curry: function() {
if (!arguments.length) return this;
var __method = this, args = $A(arguments);
return function() {
return __method.apply(this, args.concat($A(arguments)));
}
},
delay: function() {
var __method = this, args = $A(arguments), timeout = args.shift() * 1000;
return window.setTimeout(function() {
return __method.apply(__method, args);
}, timeout);
},
wrap: function(wrapper) {
var __method = this;
return function() {
return wrapper.apply(this, [__method.bind(this)].concat($A(arguments)));
}
},
methodize: function() {
if (this._methodized) return this._methodized;
var __method = this;
return this._methodized = function() {
return __method.apply(null, [this].concat($A(arguments)));
};
}
});
Function.prototype.defer = Function.prototype.delay.curry(0.01);
Date.prototype.toJSON = function() {
return '"' + this.getUTCFullYear() + '-' +
(this.getUTCMonth() + 1).toPaddedString(2) + '-' +
this.getUTCDate().toPaddedString(2) + 'T' +
this.getUTCHours().toPaddedString(2) + ':' +
this.getUTCMinutes().toPaddedString(2) + ':' +
this.getUTCSeconds().toPaddedString(2) + 'Z"';
};
var Try = {
these: function() {
var returnValue;
for (var i = 0, length = arguments.length; i < length; i++) {
var lambda = arguments[i];
try {
returnValue = lambda();
break;
} catch (e) { }
}
return returnValue;
}
};
RegExp.prototype.match = RegExp.prototype.test;
RegExp.escape = function(str) {
return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
};
/*--------------------------------------------------------------------------*/
var PeriodicalExecuter = Class.create({
initialize: function(callback, frequency) {
this.callback = callback;
this.frequency = frequency;
this.currentlyExecuting = false;
this.registerCallback();
},
registerCallback: function() {
this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
},
execute: function() {
this.callback(this);
},
stop: function() {
if (!this.timer) return;
clearInterval(this.timer);
this.timer = null;
},
onTimerEvent: function() {
if (!this.currentlyExecuting) {
try {
this.currentlyExecuting = true;
this.execute();
} finally {
this.currentlyExecuting = false;
}
}
}
});
Object.extend(String, {
interpret: function(value) {
return value == null ? '' : String(value);
},
specialChar: {
'\b': '\\b',
'\t': '\\t',
'\n': '\\n',
'\f': '\\f',
'\r': '\\r',
'\\': '\\\\'
}
});
Object.extend(String.prototype, {
gsub: function(pattern, replacement) {
var result = '', source = this, match;
replacement = arguments.callee.prepareReplacement(replacement);
while (source.length > 0) {
if (match = source.match(pattern)) {
result += source.slice(0, match.index);
result += String.interpret(replacement(match));
source = source.slice(match.index + match[0].length);
} else {
result += source, source = '';
}
}
return result;
},
sub: function(pattern, replacement, count) {
replacement = this.gsub.prepareReplacement(replacement);
count = Object.isUndefined(count) ? 1 : count;
return this.gsub(pattern, function(match) {
if (--count < 0) return match[0];
return replacement(match);
});
},
scan: function(pattern, iterator) {
this.gsub(pattern, iterator);
return String(this);
},
truncate: function(length, truncation) {
length = length || 30;
truncation = Object.isUndefined(truncation) ? '...' : truncation;
return this.length > length ?
this.slice(0, length - truncation.length) + truncation : String(this);
},
strip: function() {
return this.replace(/^\s+/, '').replace(/\s+$/, '');
},
stripTags: function() {
return this.replace(/<\/?[^>]+>/gi, '');
},
stripScripts: function() {
return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
},
extractScripts: function() {
var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
return (this.match(matchAll) || []).map(function(scriptTag) {
return (scriptTag.match(matchOne) || ['', ''])[1];
});
},
evalScripts: function() {
return this.extractScripts().map(function(script) { return eval(script) });
},
escapeHTML: function() {
var self = arguments.callee;
self.text.data = this;
return self.div.innerHTML;
},
unescapeHTML: function() {
var div = new Element('div');
div.innerHTML = this.stripTags();
return div.childNodes[0] ? (div.childNodes.length > 1 ?
$A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) :
div.childNodes[0].nodeValue) : '';
},
toQueryParams: function(separator) {
var match = this.strip().match(/([^?#]*)(#.*)?$/);
if (!match) return { };
return match[1].split(separator || '&').inject({ }, function(hash, pair) {
if ((pair = pair.split('='))[0]) {
var key = decodeURIComponent(pair.shift());
var value = pair.length > 1 ? pair.join('=') : pair[0];
if (value != undefined) value = decodeURIComponent(value);
if (key in hash) {
if (!Object.isArray(hash[key])) hash[key] = [hash[key]];
hash[key].push(value);
}
else hash[key] = value;
}
return hash;
});
},
toArray: function() {
return this.split('');
},
succ: function() {
return this.slice(0, this.length - 1) +
String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
},
times: function(count) {
return count < 1 ? '' : new Array(count + 1).join(this);
},
camelize: function() {
var parts = this.split('-'), len = parts.length;
if (len == 1) return parts[0];
var camelized = this.charAt(0) == '-'
? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
: parts[0];
for (var i = 1; i < len; i++)
camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
return camelized;
},
capitalize: function() {
return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
},
underscore: function() {
return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();
},
dasherize: function() {
return this.gsub(/_/,'-');
},
inspect: function(useDoubleQuotes) {
var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) {
var character = String.specialChar[match[0]];
return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16);
});
if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
return "'" + escapedString.replace(/'/g, '\\\'') + "'";
},
toJSON: function() {
return this.inspect(true);
},
unfilterJSON: function(filter) {
return this.sub(filter || Prototype.JSONFilter, '#{1}');
},
isJSON: function() {
var str = this;
if (str.blank()) return false;
str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');
return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str);
},
evalJSON: function(sanitize) {
var json = this.unfilterJSON();
try {
if (!sanitize || json.isJSON()) return eval('(' + json + ')');
} catch (e) { }
throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
},
include: function(pattern) {
return this.indexOf(pattern) > -1;
},
startsWith: function(pattern) {
return this.indexOf(pattern) === 0;
},
endsWith: function(pattern) {
var d = this.length - pattern.length;
return d >= 0 && this.lastIndexOf(pattern) === d;
},
empty: function() {
return this == '';
},
blank: function() {
return /^\s*$/.test(this);
},
interpolate: function(object, pattern) {
return new Template(this, pattern).evaluate(object);
}
});
if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, {
escapeHTML: function() {
return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
},
unescapeHTML: function() {
return this.replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>');
}
});
String.prototype.gsub.prepareReplacement = function(replacement) {
if (Object.isFunction(replacement)) return replacement;
var template = new Template(replacement);
return function(match) { return template.evaluate(match) };
};
String.prototype.parseQuery = String.prototype.toQueryParams;
Object.extend(String.prototype.escapeHTML, {
div: document.createElement('div'),
text: document.createTextNode('')
});
with (String.prototype.escapeHTML) div.appendChild(text);
var Template = Class.create({
initialize: function(template, pattern) {
this.template = template.toString();
this.pattern = pattern || Template.Pattern;
},
evaluate: function(object) {
if (Object.isFunction(object.toTemplateReplacements))
object = object.toTemplateReplacements();
return this.template.gsub(this.pattern, function(match) {
if (object == null) return '';
var before = match[1] || '';
if (before == '\\') return match[2];
var ctx = object, expr = match[3];
var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;
match = pattern.exec(expr);
if (match == null) return before;
while (match != null) {
var comp = match[1].startsWith('[') ? match[2].gsub('\\\\]', ']') : match[1];
ctx = ctx[comp];
if (null == ctx || '' == match[3]) break;
expr = expr.substring('[' == match[3] ? match[1].length : match[0].length);
match = pattern.exec(expr);
}
return before + String.interpret(ctx);
});
}
});
Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
var $break = { };
var Enumerable = {
each: function(iterator, context) {
var index = 0;
iterator = iterator.bind(context);
try {
this._each(function(value) {
iterator(value, index++);
});
} catch (e) {
if (e != $break) throw e;
}
return this;
},
eachSlice: function(number, iterator, context) {
iterator = iterator ? iterator.bind(context) : Prototype.K;
var index = -number, slices = [], array = this.toArray();
while ((index += number) < array.length)
slices.push(array.slice(index, index+number));
return slices.collect(iterator, context);
},
all: function(iterator, context) {
iterator = iterator ? iterator.bind(context) : Prototype.K;
var result = true;
this.each(function(value, index) {
result = result && !!iterator(value, index);
if (!result) throw $break;
});
return result;
},
any: function(iterator, context) {
iterator = iterator ? iterator.bind(context) : Prototype.K;
var result = false;
this.each(function(value, index) {
if (result = !!iterator(value, index))
throw $break;
});
return result;
},
collect: function(iterator, context) {
iterator = iterator ? iterator.bind(context) : Prototype.K;
var results = [];
this.each(function(value, index) {
results.push(iterator(value, index));
});
return results;
},
detect: function(iterator, context) {
iterator = iterator.bind(context);
var result;
this.each(function(value, index) {
if (iterator(value, index)) {
result = value;
throw $break;
}
});
return result;
},
findAll: function(iterator, context) {
iterator = iterator.bind(context);
var results = [];
this.each(function(value, index) {
if (iterator(value, index))
results.push(value);
});
return results;
},
grep: function(filter, iterator, context) {
iterator = iterator ? iterator.bind(context) : Prototype.K;
var results = [];
if (Object.isString(filter))
filter = new RegExp(filter);
this.each(function(value, index) {
if (filter.match(value))
results.push(iterator(value, index));
});
return results;
},
include: function(object) {
if (Object.isFunction(this.indexOf))
if (this.indexOf(object) != -1) return true;
var found = false;
this.each(function(value) {
if (value == object) {
found = true;
throw $break;
}
});
return found;
},
inGroupsOf: function(number, fillWith) {
fillWith = Object.isUndefined(fillWith) ? null : fillWith;
return this.eachSlice(number, function(slice) {
while(slice.length < number) slice.push(fillWith);
return slice;
});
},
inject: function(memo, iterator, context) {
iterator = iterator.bind(context);
this.each(function(value, index) {
memo = iterator(memo, value, index);
});
return memo;
},
invoke: function(method) {
var args = $A(arguments).slice(1);
return this.map(function(value) {
return value[method].apply(value, args);
});
},
max: function(iterator, context) {
iterator = iterator ? iterator.bind(context) : Prototype.K;
var result;
this.each(function(value, index) {
value = iterator(value, index);
if (result == null || value >= result)
result = value;
});
return result;
},
min: function(iterator, context) {
iterator = iterator ? iterator.bind(context) : Prototype.K;
var result;
this.each(function(value, index) {
value = iterator(value, index);
if (result == null || value < result)
result = value;
});
return result;
},
partition: function(iterator, context) {
iterator = iterator ? iterator.bind(context) : Prototype.K;
var trues = [], falses = [];
this.each(function(value, index) {
(iterator(value, index) ?
trues : falses).push(value);
});
return [trues, falses];
},
pluck: function(property) {
var results = [];
this.each(function(value) {
results.push(value[property]);
});
return results;
},
reject: function(iterator, context) {
iterator = iterator.bind(context);
var results = [];
this.each(function(value, index) {
if (!iterator(value, index))
results.push(value);
});
return results;
},
sortBy: function(iterator, context) {
iterator = iterator.bind(context);
return this.map(function(value, index) {
return {value: value, criteria: iterator(value, index)};
}).sort(function(left, right) {
var a = left.criteria, b = right.criteria;
return a < b ? -1 : a > b ? 1 : 0;
}).pluck('value');
},
toArray: function() {
return this.map();
},
zip: function() {
var iterator = Prototype.K, args = $A(arguments);
if (Object.isFunction(args.last()))
iterator = args.pop();
var collections = [this].concat(args).map($A);
return this.map(function(value, index) {
return iterator(collections.pluck(index));
});
},
size: function() {
return this.toArray().length;
},
inspect: function() {
return '#<Enumerable:' + this.toArray().inspect() + '>';
}
};
Object.extend(Enumerable, {
map: Enumerable.collect,
find: Enumerable.detect,
select: Enumerable.findAll,
filter: Enumerable.findAll,
member: Enumerable.include,
entries: Enumerable.toArray,
every: Enumerable.all,
some: Enumerable.any
});
function $A(iterable) {
if (!iterable) return [];
if (iterable.toArray) return iterable.toArray();
var length = iterable.length || 0, results = new Array(length);
while (length--) results[length] = iterable[length];
return results;
}
if (Prototype.Browser.WebKit) {
$A = function(iterable) {
if (!iterable) return [];
if (!(Object.isFunction(iterable) && iterable == '[object NodeList]') &&
iterable.toArray) return iterable.toArray();
var length = iterable.length || 0, results = new Array(length);
while (length--) results[length] = iterable[length];
return results;
};
}
Array.from = $A;
Object.extend(Array.prototype, Enumerable);
if (!Array.prototype._reverse) Array.prototype._reverse = Array.prototype.reverse;
Object.extend(Array.prototype, {
_each: function(iterator) {
for (var i = 0, length = this.length; i < length; i++)
iterator(this[i]);
},
clear: function() {
this.length = 0;
return this;
},
first: function() {
return this[0];
},
last: function() {
return this[this.length - 1];
},
compact: function() {
return this.select(function(value) {
return value != null;
});
},
flatten: function() {
return this.inject([], function(array, value) {
return array.concat(Object.isArray(value) ?
value.flatten() : [value]);
});
},
without: function() {
var values = $A(arguments);
return this.select(function(value) {
return !values.include(value);
});
},
reverse: function(inline) {
return (inline !== false ? this : this.toArray())._reverse();
},
reduce: function() {
return this.length > 1 ? this : this[0];
},
uniq: function(sorted) {
return this.inject([], function(array, value, index) {
if (0 == index || (sorted ? array.last() != value : !array.include(value)))
array.push(value);
return array;
});
},
intersect: function(array) {
return this.uniq().findAll(function(item) {
return array.detect(function(value) { return item === value });
});
},
clone: function() {
return [].concat(this);
},
size: function() {
return this.length;
},
inspect: function() {
return '[' + this.map(Object.inspect).join(', ') + ']';
},
toJSON: function() {
var results = [];
this.each(function(object) {
var value = Object.toJSON(object);
if (!Object.isUndefined(value)) results.push(value);
});
return '[' + results.join(', ') + ']';
}
});
if (Object.isFunction(Array.prototype.forEach))
Array.prototype._each = Array.prototype.forEach;
if (!Array.prototype.indexOf) Array.prototype.indexOf = function(item, i) {
i || (i = 0);
var length = this.length;
if (i < 0) i = length + i;
for (; i < length; i++)
if (this[i] === item) return i;
return -1;
};
if (!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(item, i) {
i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1;
var n = this.slice(0, i).reverse().indexOf(item);
return (n < 0) ? n : i - n - 1;
};
Array.prototype.toArray = Array.prototype.clone;
function $w(string) {
if (!Object.isString(string)) return [];
string = string.strip();
return string ? string.split(/\s+/) : [];
}
if (Prototype.Browser.Opera){
Array.prototype.concat = function() {
var array = [];
for (var i = 0, length = this.length; i < length; i++) array.push(this[i]);
for (var i = 0, length = arguments.length; i < length; i++) {
if (Object.isArray(arguments[i])) {
for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
array.push(arguments[i][j]);
} else {
array.push(arguments[i]);
}
}
return array;
};
}
Object.extend(Number.prototype, {
toColorPart: function() {
return this.toPaddedString(2, 16);
},
succ: function() {
return this + 1;
},
times: function(iterator) {
$R(0, this, true).each(iterator);
return this;
},
toPaddedString: function(length, radix) {
var string = this.toString(radix || 10);
return '0'.times(length - string.length) + string;
},
toJSON: function() {
return isFinite(this) ? this.toString() : 'null';
}
});
$w('abs round ceil floor').each(function(method){
Number.prototype[method] = Math[method].methodize();
});
function $H(object) {
return new Hash(object);
};
var Hash = Class.create(Enumerable, (function() {
function toQueryPair(key, value) {
if (Object.isUndefined(value)) return key;
return key + '=' + encodeURIComponent(String.interpret(value));
}
return {
initialize: function(object) {
this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
},
_each: function(iterator) {
for (var key in this._object) {
var value = this._object[key], pair = [key, value];
pair.key = key;
pair.value = value;
iterator(pair);
}
},
set: function(key, value) {
return this._object[key] = value;
},
get: function(key) {
return this._object[key];
},
unset: function(key) {
var value = this._object[key];
delete this._object[key];
return value;
},
toObject: function() {
return Object.clone(this._object);
},
keys: function() {
return this.pluck('key');
},
values: function() {
return this.pluck('value');
},
index: function(value) {
var match = this.detect(function(pair) {
return pair.value === value;
});
return match && match.key;
},
merge: function(object) {
return this.clone().update(object);
},
update: function(object) {
return new Hash(object).inject(this, function(result, pair) {
result.set(pair.key, pair.value);
return result;
});
},
toQueryString: function() {
return this.map(function(pair) {
var key = encodeURIComponent(pair.key), values = pair.value;
if (values && typeof values == 'object') {
if (Object.isArray(values))
return values.map(toQueryPair.curry(key)).join('&');
}
return toQueryPair(key, values);
}).join('&');
},
inspect: function() {
return '#<Hash:{' + this.map(function(pair) {
return pair.map(Object.inspect).join(': ');
}).join(', ') + '}>';
},
toJSON: function() {
return Object.toJSON(this.toObject());
},
clone: function() {
return new Hash(this);
}
}
})());
Hash.prototype.toTemplateReplacements = Hash.prototype.toObject;
Hash.from = $H;
var ObjectRange = Class.create(Enumerable, {
initialize: function(start, end, exclusive) {
this.start = start;
this.end = end;
this.exclusive = exclusive;
},
_each: function(iterator) {
var value = this.start;
while (this.include(value)) {
iterator(value);
value = value.succ();
}
},
include: function(value) {
if (value < this.start)
return false;
if (this.exclusive)
return value < this.end;
return value <= this.end;
}
});
var $R = function(start, end, exclusive) {
return new ObjectRange(start, end, exclusive);
};
var Ajax = {
getTransport: function() {
return Try.these(
function() {return new XMLHttpRequest()},
function() {return new ActiveXObject('Msxml2.XMLHTTP')},
function() {return new ActiveXObject('Microsoft.XMLHTTP')}
) || false;
},
activeRequestCount: 0
};
Ajax.Responders = {
responders: [],
_each: function(iterator) {
this.responders._each(iterator);
},
register: function(responder) {
if (!this.include(responder))
this.responders.push(responder);
},
unregister: function(responder) {
this.responders = this.responders.without(responder);
},
dispatch: function(callback, request, transport, json) {
this.each(function(responder) {
if (Object.isFunction(responder[callback])) {
try {
responder[callback].apply(responder, [request, transport, json]);
} catch (e) { }
}
});
}
};
Object.extend(Ajax.Responders, Enumerable);
Ajax.Responders.register({
onCreate: function() { Ajax.activeRequestCount++ },
onComplete: function() { Ajax.activeRequestCount-- }
});
Ajax.Base = Class.create({
initialize: function(options) {
this.options = {
method: 'post',
asynchronous: true,
contentType: 'application/x-www-form-urlencoded',
encoding: 'UTF-8',
parameters: '',
evalJSON: true,
evalJS: true
};
Object.extend(this.options, options || { });
this.options.method = this.options.method.toLowerCase();
if (Object.isString(this.options.parameters))
this.options.parameters = this.options.parameters.toQueryParams();
else if (Object.isHash(this.options.parameters))
this.options.parameters = this.options.parameters.toObject();
}
});
Ajax.Request = Class.create(Ajax.Base, {
_complete: false,
initialize: function($super, url, options) {
$super(options);
this.transport = Ajax.getTransport();
this.request(url);
},
request: function(url) {
this.url = url;
this.method = this.options.method;
var params = Object.clone(this.options.parameters);
if (!['get', 'post'].include(this.method)) {
params['_method'] = this.method;
this.method = 'post';
}
this.parameters = params;
if (params = Object.toQueryString(params)) {
if (this.method == 'get')
this.url += (this.url.include('?') ? '&' : '?') + params;
else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))
params += '&_=';
}
try {
var response = new Ajax.Response(this);
if (this.options.onCreate) this.options.onCreate(response);
Ajax.Responders.dispatch('onCreate', this, response);
this.transport.open(this.method.toUpperCase(), this.url,
this.options.asynchronous);
if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1);
this.transport.onreadystatechange = this.onStateChange.bind(this);
this.setRequestHeaders();
this.body = this.method == 'post' ? (this.options.postBody || params) : null;
this.transport.send(this.body);
/* Force Firefox to handle ready state 4 for synchronous requests */
if (!this.options.asynchronous && this.transport.overrideMimeType)
this.onStateChange();
}
catch (e) {
this.dispatchException(e);
}
},
onStateChange: function() {
var readyState = this.transport.readyState;
if (readyState > 1 && !((readyState == 4) && this._complete))
this.respondToReadyState(this.transport.readyState);
},
setRequestHeaders: function() {
var headers = {
'X-Requested-With': 'XMLHttpRequest',
'X-Prototype-Version': Prototype.Version,
'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
};
if (this.method == 'post') {
headers['Content-type'] = this.options.contentType +
(this.options.encoding ? '; charset=' + this.options.encoding : '');
/* Force "Connection: close" for older Mozilla browsers to work
* around a bug where XMLHttpRequest sends an incorrect
* Content-length header. See Mozilla Bugzilla #246651.
*/
if (this.transport.overrideMimeType &&
(navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
headers['Connection'] = 'close';
}
if (typeof this.options.requestHeaders == 'object') {
var extras = this.options.requestHeaders;
if (Object.isFunction(extras.push))
for (var i = 0, length = extras.length; i < length; i += 2)
headers[extras[i]] = extras[i+1];
else
$H(extras).each(function(pair) { headers[pair.key] = pair.value });
}
for (var name in headers)
this.transport.setRequestHeader(name, headers[name]);
},
success: function() {
var status = this.getStatus();
return !status || (status >= 200 && status < 300);
},
getStatus: function() {
try {
return this.transport.status || 0;
} catch (e) { return 0 }
},
respondToReadyState: function(readyState) {
var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this);
if (state == 'Complete') {
try {
this._complete = true;
(this.options['on' + response.status]
|| this.options['on' + (this.success() ? 'Success' : 'Failure')]
|| Prototype.emptyFunction)(response, response.headerJSON);
} catch (e) {
this.dispatchException(e);
}
var contentType = response.getHeader('Content-type');
if (this.options.evalJS == 'force'
|| (this.options.evalJS && this.isSameOrigin() && contentType
&& contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))
this.evalResponse();
}
try {
(this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON);
Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON);
} catch (e) {
this.dispatchException(e);
}
if (state == 'Complete') {
this.transport.onreadystatechange = Prototype.emptyFunction;
}
},
isSameOrigin: function() {
var m = this.url.match(/^\s*https?:\/\/[^\/]*/);
return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({
protocol: location.protocol,
domain: document.domain,
port: location.port ? ':' + location.port : ''
}));
},
getHeader: function(name) {
try {
return this.transport.getResponseHeader(name) || null;
} catch (e) { return null }
},
evalResponse: function() {
try {
return eval((this.transport.responseText || '').unfilterJSON());
} catch (e) {
this.dispatchException(e);
}
},
dispatchException: function(exception) {
(this.options.onException || Prototype.emptyFunction)(this, exception);
Ajax.Responders.dispatch('onException', this, exception);
}
});
Ajax.Request.Events =
['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
Ajax.Response = Class.create({
initialize: function(request){
this.request = request;
var transport = this.transport = request.transport,
readyState = this.readyState = transport.readyState;
if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) {
this.status = this.getStatus();
this.statusText = this.getStatusText();
this.responseText = String.interpret(transport.responseText);
this.headerJSON = this._getHeaderJSON();
}
if(readyState == 4) {
var xml = transport.responseXML;
this.responseXML = Object.isUndefined(xml) ? null : xml;
this.responseJSON = this._getResponseJSON();
}
},
status: 0,
statusText: '',
getStatus: Ajax.Request.prototype.getStatus,
getStatusText: function() {
try {
return this.transport.statusText || '';
} catch (e) { return '' }
},
getHeader: Ajax.Request.prototype.getHeader,
getAllHeaders: function() {
try {
return this.getAllResponseHeaders();
} catch (e) { return null }
},
getResponseHeader: function(name) {
return this.transport.getResponseHeader(name);
},
getAllResponseHeaders: function() {
return this.transport.getAllResponseHeaders();
},
_getHeaderJSON: function() {
var json = this.getHeader('X-JSON');
if (!json) return null;
json = decodeURIComponent(escape(json));
try {
return json.evalJSON(this.request.options.sanitizeJSON ||
!this.request.isSameOrigin());
} catch (e) {
this.request.dispatchException(e);
}
},
_getResponseJSON: function() {
var options = this.request.options;
if (!options.evalJSON || (options.evalJSON != 'force' &&
!(this.getHeader('Content-type') || '').include('application/json')) ||
this.responseText.blank())
return null;
try {
return this.responseText.evalJSON(options.sanitizeJSON ||
!this.request.isSameOrigin());
} catch (e) {
this.request.dispatchException(e);
}
}
});
Ajax.Updater = Class.create(Ajax.Request, {
initialize: function($super, container, url, options) {
this.container = {
success: (container.success || container),
failure: (container.failure || (container.success ? null : container))
};
options = Object.clone(options);
var onComplete = options.onComplete;
options.onComplete = (function(response, json) {
this.updateContent(response.responseText);
if (Object.isFunction(onComplete)) onComplete(response, json);
}).bind(this);
$super(url, options);
},
updateContent: function(responseText) {
var receiver = this.container[this.success() ? 'success' : 'failure'],
options = this.options;
if (!options.evalScripts) responseText = responseText.stripScripts();
if (receiver = $(receiver)) {
if (options.insertion) {
if (Object.isString(options.insertion)) {
var insertion = { }; insertion[options.insertion] = responseText;
receiver.insert(insertion);
}
else options.insertion(receiver, responseText);
}
else receiver.update(responseText);
}
}
});
Ajax.PeriodicalUpdater = Class.create(Ajax.Base, {
initialize: function($super, container, url, options) {
$super(options);
this.onComplete = this.options.onComplete;
this.frequency = (this.options.frequency || 2);
this.decay = (this.options.decay || 1);
this.updater = { };
this.container = container;
this.url = url;
this.start();
},
start: function() {
this.options.onComplete = this.updateComplete.bind(this);
this.onTimerEvent();
},
stop: function() {
this.updater.options.onComplete = undefined;
clearTimeout(this.timer);
(this.onComplete || Prototype.emptyFunction).apply(this, arguments);
},
updateComplete: function(response) {
if (this.options.decay) {
this.decay = (response.responseText == this.lastText ?
this.decay * this.options.decay : 1);
this.lastText = response.responseText;
}
this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency);
},
onTimerEvent: function() {
this.updater = new Ajax.Updater(this.container, this.url, this.options);
}
});
function $(element) {
if (arguments.length > 1) {
for (var i = 0, elements = [], length = arguments.length; i < length; i++)
elements.push($(arguments[i]));
return elements;
}
if (Object.isString(element))
element = document.getElementById(element);
return Element.extend(element);
}
if (Prototype.BrowserFeatures.XPath) {
document._getElementsByXPath = function(expression, parentElement) {
var results = [];
var query = document.evaluate(expression, $(parentElement) || document,
null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
for (var i = 0, length = query.snapshotLength; i < length; i++)
results.push(Element.extend(query.snapshotItem(i)));
return results;
};
}
/*--------------------------------------------------------------------------*/
if (!window.Node) var Node = { };
if (!Node.ELEMENT_NODE) {
Object.extend(Node, {
ELEMENT_NODE: 1,
ATTRIBUTE_NODE: 2,
TEXT_NODE: 3,
CDATA_SECTION_NODE: 4,
ENTITY_REFERENCE_NODE: 5,
ENTITY_NODE: 6,
PROCESSING_INSTRUCTION_NODE: 7,
COMMENT_NODE: 8,
DOCUMENT_NODE: 9,
DOCUMENT_TYPE_NODE: 10,
DOCUMENT_FRAGMENT_NODE: 11,
NOTATION_NODE: 12
});
}
(function() {
var element = this.Element;
this.Element = function(tagName, attributes) {
attributes = attributes || { };
tagName = tagName.toLowerCase();
var cache = Element.cache;
if (Prototype.Browser.IE && attributes.name) {
tagName = '<' + tagName + ' name="' + attributes.name + '">';
delete attributes.name;
return Element.writeAttribute(document.createElement(tagName), attributes);
}
if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName));
return Element.writeAttribute(cache[tagName].cloneNode(false), attributes);
};
Object.extend(this.Element, element || { });
}).call(window);
Element.cache = { };
Element.Methods = {
visible: function(element) {
return $(element).style.display != 'none';
},
toggle: function(element) {
element = $(element);
Element[Element.visible(element) ? 'hide' : 'show'](element);
return element;
},
hide: function(element) {
$(element).style.display = 'none';
return element;
},
show: function(element) {
$(element).style.display = '';
return element;
},
remove: function(element) {
element = $(element);
element.parentNode.removeChild(element);
return element;
},
update: function(element, content) {
element = $(element);
if (content && content.toElement) content = content.toElement();
if (Object.isElement(content)) return element.update().insert(content);
content = Object.toHTML(content);
element.innerHTML = content.stripScripts();
content.evalScripts.bind(content).defer();
return element;
},
replace: function(element, content) {
element = $(element);
if (content && content.toElement) content = content.toElement();
else if (!Object.isElement(content)) {
content = Object.toHTML(content);
var range = element.ownerDocument.createRange();
range.selectNode(element);
content.evalScripts.bind(content).defer();
content = range.createContextualFragment(content.stripScripts());
}
element.parentNode.replaceChild(content, element);
return element;
},
insert: function(element, insertions) {
element = $(element);
if (Object.isString(insertions) || Object.isNumber(insertions) ||
Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
insertions = {bottom:insertions};
var content, insert, tagName, childNodes;
for (var position in insertions) {
content = insertions[position];
position = position.toLowerCase();
insert = Element._insertionTranslations[position];
if (content && content.toElement) content = content.toElement();
if (Object.isElement(content)) {
insert(element, content);
continue;
}
content = Object.toHTML(content);
tagName = ((position == 'before' || position == 'after')
? element.parentNode : element).tagName.toUpperCase();
childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
if (position == 'top' || position == 'after') childNodes.reverse();
childNodes.each(insert.curry(element));
content.evalScripts.bind(content).defer();
}
return element;
},
wrap: function(element, wrapper, attributes) {
element = $(element);
if (Object.isElement(wrapper))
$(wrapper).writeAttribute(attributes || { });
else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes);
else wrapper = new Element('div', wrapper);
if (element.parentNode)
element.parentNode.replaceChild(wrapper, element);
wrapper.appendChild(element);
return wrapper;
},
inspect: function(element) {
element = $(element);
var result = '<' + element.tagName.toLowerCase();
$H({'id': 'id', 'className': 'class'}).each(function(pair) {
var property = pair.first(), attribute = pair.last();
var value = (element[property] || '').toString();
if (value) result += ' ' + attribute + '=' + value.inspect(true);
});
return result + '>';
},
recursivelyCollect: function(element, property) {
element = $(element);
var elements = [];
while (element = element[property])
if (element.nodeType == 1)
elements.push(Element.extend(element));
return elements;
},
ancestors: function(element) {
return $(element).recursivelyCollect('parentNode');
},
descendants: function(element) {
return $(element).select("*");
},
firstDescendant: function(element) {
element = $(element).firstChild;
while (element && element.nodeType != 1) element = element.nextSibling;
return $(element);
},
immediateDescendants: function(element) {
if (!(element = $(element).firstChild)) return [];
while (element && element.nodeType != 1) element = element.nextSibling;
if (element) return [element].concat($(element).nextSiblings());
return [];
},
previousSiblings: function(element) {
return $(element).recursivelyCollect('previousSibling');
},
nextSiblings: function(element) {
return $(element).recursivelyCollect('nextSibling');
},
siblings: function(element) {
element = $(element);
return element.previousSiblings().reverse().concat(element.nextSiblings());
},
match: function(element, selector) {
if (Object.isString(selector))
selector = new Selector(selector);
return selector.match($(element));
},
up: function(element, expression, index) {
element = $(element);
if (arguments.length == 1) return $(element.parentNode);
var ancestors = element.ancestors();
return Object.isNumber(expression) ? ancestors[expression] :
Selector.findElement(ancestors, expression, index);
},
down: function(element, expression, index) {
element = $(element);
if (arguments.length == 1) return element.firstDescendant();
return Object.isNumber(expression) ? element.descendants()[expression] :
element.select(expression)[index || 0];
},
previous: function(element, expression, index) {
element = $(element);
if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
var previousSiblings = element.previousSiblings();
return Object.isNumber(expression) ? previousSiblings[expression] :
Selector.findElement(previousSiblings, expression, index);
},
next: function(element, expression, index) {
element = $(element);
if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
var nextSiblings = element.nextSiblings();
return Object.isNumber(expression) ? nextSiblings[expression] :
Selector.findElement(nextSiblings, expression, index);
},
select: function() {
var args = $A(arguments), element = $(args.shift());
return Selector.findChildElements(element, args);
},
adjacent: function() {
var args = $A(arguments), element = $(args.shift());
return Selector.findChildElements(element.parentNode, args).without(element);
},
identify: function(element) {
element = $(element);
var id = element.readAttribute('id'), self = arguments.callee;
if (id) return id;
do { id = 'anonymous_element_' + self.counter++ } while ($(id));
element.writeAttribute('id', id);
return id;
},
readAttribute: function(element, name) {
element = $(element);
if (Prototype.Browser.IE) {
var t = Element._attributeTranslations.read;
if (t.values[name]) return t.values[name](element, name);
if (t.names[name]) name = t.names[name];
if (name.include(':')) {
return (!element.attributes || !element.attributes[name]) ? null :
element.attributes[name].value;
}
}
return element.getAttribute(name);
},
writeAttribute: function(element, name, value) {
element = $(element);
var attributes = { }, t = Element._attributeTranslations.write;
if (typeof name == 'object') attributes = name;
else attributes[name] = Object.isUndefined(value) ? true : value;
for (var attr in attributes) {
name = t.names[attr] || attr;
value = attributes[attr];
if (t.values[attr]) name = t.values[attr](element, value);
if (value === false || value === null)
element.removeAttribute(name);
else if (value === true)
element.setAttribute(name, name);
else element.setAttribute(name, value);
}
return element;
},
getHeight: function(element) {
return $(element).getDimensions().height;
},
getWidth: function(element) {
return $(element).getDimensions().width;
},
classNames: function(element) {
return new Element.ClassNames(element);
},
hasClassName: function(element, className) {
if (!(element = $(element))) return;
var elementClassName = element.className;
return (elementClassName.length > 0 && (elementClassName == className ||
new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName)));
},
addClassName: function(element, className) {
if (!(element = $(element))) return;
if (!element.hasClassName(className))
element.className += (element.className ? ' ' : '') + className;
return element;
},
removeClassName: function(element, className) {
if (!(element = $(element))) return;
element.className = element.className.replace(
new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip();
return element;
},
toggleClassName: function(element, className) {
if (!(element = $(element))) return;
return element[element.hasClassName(className) ?
'removeClassName' : 'addClassName'](className);
},
cleanWhitespace: function(element) {
element = $(element);
var node = element.firstChild;
while (node) {
var nextNode = node.nextSibling;
if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
element.removeChild(node);
node = nextNode;
}
return element;
},
empty: function(element) {
return $(element).innerHTML.blank();
},
descendantOf: function(element, ancestor) {
element = $(element), ancestor = $(ancestor);
var originalAncestor = ancestor;
if (element.compareDocumentPosition)
return (element.compareDocumentPosition(ancestor) & 8) === 8;
if (element.sourceIndex && !Prototype.Browser.Opera) {
var e = element.sourceIndex, a = ancestor.sourceIndex,
nextAncestor = ancestor.nextSibling;
if (!nextAncestor) {
do { ancestor = ancestor.parentNode; }
while (!(nextAncestor = ancestor.nextSibling) && ancestor.parentNode);
}
if (nextAncestor && nextAncestor.sourceIndex)
return (e > a && e < nextAncestor.sourceIndex);
}
while (element = element.parentNode)
if (element == originalAncestor) return true;
return false;
},
scrollTo: function(element) {
element = $(element);
var pos = element.cumulativeOffset();
window.scrollTo(pos[0], pos[1]);
return element;
},
getStyle: function(element, style) {
element = $(element);
style = style == 'float' ? 'cssFloat' : style.camelize();
var value = element.style[style];
if (!value) {
var css = document.defaultView.getComputedStyle(element, null);
value = css ? css[style] : null;
}
if (style == 'opacity') return value ? parseFloat(value) : 1.0;
return value == 'auto' ? null : value;
},
getOpacity: function(element) {
return $(element).getStyle('opacity');
},
setStyle: function(element, styles) {
element = $(element);
var elementStyle = element.style, match;
if (Object.isString(styles)) {
element.style.cssText += ';' + styles;
return styles.include('opacity') ?
element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element;
}
for (var property in styles)
if (property == 'opacity') element.setOpacity(styles[property]);
else
elementStyle[(property == 'float' || property == 'cssFloat') ?
(Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') :
property] = styles[property];
return element;
},
setOpacity: function(element, value) {
element = $(element);
element.style.opacity = (value == 1 || value === '') ? '' :
(value < 0.00001) ? 0 : value;
return element;
},
getDimensions: function(element) {
element = $(element);
var display = $(element).getStyle('display');
if (display != 'none' && display != null)
return {width: element.offsetWidth, height: element.offsetHeight};
var els = element.style;
var originalVisibility = els.visibility;
var originalPosition = els.position;
var originalDisplay = els.display;
els.visibility = 'hidden';
els.position = 'absolute';
els.display = 'block';
var originalWidth = element.clientWidth;
var originalHeight = element.clientHeight;
els.display = originalDisplay;
els.position = originalPosition;
els.visibility = originalVisibility;
return {width: originalWidth, height: originalHeight};
},
makePositioned: function(element) {
element = $(element);
var pos = Element.getStyle(element, 'position');
if (pos == 'static' || !pos) {
element._madePositioned = true;
element.style.position = 'relative';
if (window.opera) {
element.style.top = 0;
element.style.left = 0;
}
}
return element;
},
undoPositioned: function(element) {
element = $(element);
if (element._madePositioned) {
element._madePositioned = undefined;
element.style.position =
element.style.top =
element.style.left =
element.style.bottom =
element.style.right = '';
}
return element;
},
makeClipping: function(element) {
element = $(element);
if (element._overflow) return element;
element._overflow = Element.getStyle(element, 'overflow') || 'auto';
if (element._overflow !== 'hidden')
element.style.overflow = 'hidden';
return element;
},
undoClipping: function(element) {
element = $(element);
if (!element._overflow) return element;
element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
element._overflow = null;
return element;
},
cumulativeOffset: function(element) {
var valueT = 0, valueL = 0;
do {
valueT += element.offsetTop || 0;
valueL += element.offsetLeft || 0;
element = element.offsetParent;
} while (element);
return Element._returnOffset(valueL, valueT);
},
positionedOffset: function(element) {
var valueT = 0, valueL = 0;
do {
valueT += element.offsetTop || 0;
valueL += element.offsetLeft || 0;
element = element.offsetParent;
if (element) {
if (element.tagName == 'BODY') break;
var p = Element.getStyle(element, 'position');
if (p !== 'static') break;
}
} while (element);
return Element._returnOffset(valueL, valueT);
},
absolutize: function(element) {
element = $(element);
if (element.getStyle('position') == 'absolute') return;
var offsets = element.positionedOffset();
var top = offsets[1];
var left = offsets[0];
var width = element.clientWidth;
var height = element.clientHeight;
element._originalLeft = left - parseFloat(element.style.left || 0);
element._originalTop = top - parseFloat(element.style.top || 0);
element._originalWidth = element.style.width;
element._originalHeight = element.style.height;
element.style.position = 'absolute';
element.style.top = top + 'px';
element.style.left = left + 'px';
element.style.width = width + 'px';
element.style.height = height + 'px';
return element;
},
relativize: function(element) {
element = $(element);
if (element.getStyle('position') == 'relative') return;
element.style.position = 'relative';
var top = parseFloat(element.style.top || 0) - (element._originalTop || 0);
var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
element.style.top = top + 'px';
element.style.left = left + 'px';
element.style.height = element._originalHeight;
element.style.width = element._originalWidth;
return element;
},
cumulativeScrollOffset: function(element) {
var valueT = 0, valueL = 0;
do {
valueT += element.scrollTop || 0;
valueL += element.scrollLeft || 0;
element = element.parentNode;
} while (element);
return Element._returnOffset(valueL, valueT);
},
getOffsetParent: function(element) {
if (element.offsetParent) return $(element.offsetParent);
if (element == document.body) return $(element);
while ((element = element.parentNode) && element != document.body)
if (Element.getStyle(element, 'position') != 'static')
return $(element);
return $(document.body);
},
viewportOffset: function(forElement) {
var valueT = 0, valueL = 0;
var element = forElement;
do {
valueT += element.offsetTop || 0;
valueL += element.offsetLeft || 0;
if (element.offsetParent == document.body &&
Element.getStyle(element, 'position') == 'absolute') break;
} while (element = element.offsetParent);
element = forElement;
do {
if (!Prototype.Browser.Opera || element.tagName == 'BODY') {
valueT -= element.scrollTop || 0;
valueL -= element.scrollLeft || 0;
}
} while (element = element.parentNode);
return Element._returnOffset(valueL, valueT);
},
clonePosition: function(element, source) {
var options = Object.extend({
setLeft: true,
setTop: true,
setWidth: true,
setHeight: true,
offsetTop: 0,
offsetLeft: 0
}, arguments[2] || { });
source = $(source);
var p = source.viewportOffset();
element = $(element);
var delta = [0, 0];
var parent = null;
if (Element.getStyle(element, 'position') == 'absolute') {
parent = element.getOffsetParent();
delta = parent.viewportOffset();
}
if (parent == document.body) {
delta[0] -= document.body.offsetLeft;
delta[1] -= document.body.offsetTop;
}
if (options.setLeft) element.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px';
if (options.setTop) element.style.top = (p[1] - delta[1] + options.offsetTop) + 'px';
if (options.setWidth) element.style.width = source.offsetWidth + 'px';
if (options.setHeight) element.style.height = source.offsetHeight + 'px';
return element;
}
};
Element.Methods.identify.counter = 1;
Object.extend(Element.Methods, {
getElementsBySelector: Element.Methods.select,
childElements: Element.Methods.immediateDescendants
});
Element._attributeTranslations = {
write: {
names: {
className: 'class',
htmlFor: 'for'
},
values: { }
}
};
if (Prototype.Browser.Opera) {
Element.Methods.getStyle = Element.Methods.getStyle.wrap(
function(proceed, element, style) {
switch (style) {
case 'left': case 'top': case 'right': case 'bottom':
if (proceed(element, 'position') === 'static') return null;
case 'height': case 'width':
if (!Element.visible(element)) return null;
var dim = parseInt(proceed(element, style), 10);
if (dim !== element['offset' + style.capitalize()])
return dim + 'px';
var properties;
if (style === 'height') {
properties = ['border-top-width', 'padding-top',
'padding-bottom', 'border-bottom-width'];
}
else {
properties = ['border-left-width', 'padding-left',
'padding-right', 'border-right-width'];
}
return properties.inject(dim, function(memo, property) {
var val = proceed(element, property);
return val === null ? memo : memo - parseInt(val, 10);
}) + 'px';
default: return proceed(element, style);
}
}
);
Element.Methods.readAttribute = Element.Methods.readAttribute.wrap(
function(proceed, element, attribute) {
if (attribute === 'title') return element.title;
return proceed(element, attribute);
}
);
}
else if (Prototype.Browser.IE) {
Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap(
function(proceed, element) {
element = $(element);
var position = element.getStyle('position');
if (position !== 'static') return proceed(element);
element.setStyle({ position: 'relative' });
var value = proceed(element);
element.setStyle({ position: position });
return value;
}
);
$w('positionedOffset viewportOffset').each(function(method) {
Element.Methods[method] = Element.Methods[method].wrap(
function(proceed, element) {
element = $(element);
var position = element.getStyle('position');
if (position !== 'static') return proceed(element);
var offsetParent = element.getOffsetParent();
if (offsetParent && offsetParent.getStyle('position') === 'fixed')
offsetParent.setStyle({ zoom: 1 });
element.setStyle({ position: 'relative' });
var value = proceed(element);
element.setStyle({ position: position });
return value;
}
);
});
Element.Methods.getStyle = function(element, style) {
element = $(element);
style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
var value = element.style[style];
if (!value && element.currentStyle) value = element.currentStyle[style];
if (style == 'opacity') {
if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
if (value[1]) return parseFloat(value[1]) / 100;
return 1.0;
}
if (value == 'auto') {
if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))
return element['offset' + style.capitalize()] + 'px';
return null;
}
return value;
};
Element.Methods.setOpacity = function(element, value) {
function stripAlpha(filter){
return filter.replace(/alpha\([^\)]*\)/gi,'');
}
element = $(element);
var currentStyle = element.currentStyle;
if ((currentStyle && !currentStyle.hasLayout) ||
(!currentStyle && element.style.zoom == 'normal'))
element.style.zoom = 1;
var filter = element.getStyle('filter'), style = element.style;
if (value == 1 || value === '') {
(filter = stripAlpha(filter)) ?
style.filter = filter : style.removeAttribute('filter');
return element;
} else if (value < 0.00001) value = 0;
style.filter = stripAlpha(filter) +
'alpha(opacity=' + (value * 100) + ')';
return element;
};
Element._attributeTranslations = {
read: {
names: {
'class': 'className',
'for': 'htmlFor'
},
values: {
_getAttr: function(element, attribute) {
return element.getAttribute(attribute, 2);
},
_getAttrNode: function(element, attribute) {
var node = element.getAttributeNode(attribute);
return node ? node.value : "";
},
_getEv: function(element, attribute) {
attribute = element.getAttribute(attribute);
return attribute ? attribute.toString().slice(23, -2) : null;
},
_flag: function(element, attribute) {
return $(element).hasAttribute(attribute) ? attribute : null;
},
style: function(element) {
return element.style.cssText.toLowerCase();
},
title: function(element) {
return element.title;
}
}
}
};
Element._attributeTranslations.write = {
names: Object.extend({
cellpadding: 'cellPadding',
cellspacing: 'cellSpacing'
}, Element._attributeTranslations.read.names),
values: {
checked: function(element, value) {
element.checked = !!value;
},
style: function(element, value) {
element.style.cssText = value ? value : '';
}
}
};
Element._attributeTranslations.has = {};
$w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' +
'encType maxLength readOnly longDesc').each(function(attr) {
Element._attributeTranslations.write.names[attr.toLowerCase()] = attr;
Element._attributeTranslations.has[attr.toLowerCase()] = attr;
});
(function(v) {
Object.extend(v, {
href: v._getAttr,
src: v._getAttr,
type: v._getAttr,
action: v._getAttrNode,
disabled: v._flag,
checked: v._flag,
readonly: v._flag,
multiple: v._flag,
onload: v._getEv,
onunload: v._getEv,
onclick: v._getEv,
ondblclick: v._getEv,
onmousedown: v._getEv,
onmouseup: v._getEv,
onmouseover: v._getEv,
onmousemove: v._getEv,
onmouseout: v._getEv,
onfocus: v._getEv,
onblur: v._getEv,
onkeypress: v._getEv,
onkeydown: v._getEv,
onkeyup: v._getEv,
onsubmit: v._getEv,
onreset: v._getEv,
onselect: v._getEv,
onchange: v._getEv
});
})(Element._attributeTranslations.read.values);
}
else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) {
Element.Methods.setOpacity = function(element, value) {
element = $(element);
element.style.opacity = (value == 1) ? 0.999999 :
(value === '') ? '' : (value < 0.00001) ? 0 : value;
return element;
};
}
else if (Prototype.Browser.WebKit) {
Element.Methods.setOpacity = function(element, value) {
element = $(element);
element.style.opacity = (value == 1 || value === '') ? '' :
(value < 0.00001) ? 0 : value;
if (value == 1)
if(element.tagName == 'IMG' && element.width) {
element.width++; element.width--;
} else try {
var n = document.createTextNode(' ');
element.appendChild(n);
element.removeChild(n);
} catch (e) { }
return element;
};
Element.Methods.cumulativeOffset = function(element) {
var valueT = 0, valueL = 0;
do {
valueT += element.offsetTop || 0;
valueL += element.offsetLeft || 0;
if (element.offsetParent == document.body)
if (Element.getStyle(element, 'position') == 'absolute') break;
element = element.offsetParent;
} while (element);
return Element._returnOffset(valueL, valueT);
};
}
if (Prototype.Browser.IE || Prototype.Browser.Opera) {
Element.Methods.update = function(element, content) {
element = $(element);
if (content && content.toElement) content = content.toElement();
if (Object.isElement(content)) return element.update().insert(content);
content = Object.toHTML(content);
var tagName = element.tagName.toUpperCase();
if (tagName in Element._insertionTranslations.tags) {
$A(element.childNodes).each(function(node) { element.removeChild(node) });
Element._getContentFromAnonymousElement(tagName, content.stripScripts())
.each(function(node) { element.appendChild(node) });
}
else element.innerHTML = content.stripScripts();
content.evalScripts.bind(content).defer();
return element;
};
}
if ('outerHTML' in document.createElement('div')) {
Element.Methods.replace = function(element, content) {
element = $(element);
if (content && content.toElement) content = content.toElement();
if (Object.isElement(content)) {
element.parentNode.replaceChild(content, element);
return element;
}
content = Object.toHTML(content);
var parent = element.parentNode, tagName = parent.tagName.toUpperCase();
if (Element._insertionTranslations.tags[tagName]) {
var nextSibling = element.next();
var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
parent.removeChild(element);
if (nextSibling)
fragments.each(function(node) { parent.insertBefore(node, nextSibling) });
else
fragments.each(function(node) { parent.appendChild(node) });
}
else element.outerHTML = content.stripScripts();
content.evalScripts.bind(content).defer();
return element;
};
}
Element._returnOffset = function(l, t) {
var result = [l, t];
result.left = l;
result.top = t;
return result;
};
Element._getContentFromAnonymousElement = function(tagName, html) {
var div = new Element('div'), t = Element._insertionTranslations.tags[tagName];
if (t) {
div.innerHTML = t[0] + html + t[1];
t[2].times(function() { div = div.firstChild });
} else div.innerHTML = html;
return $A(div.childNodes);
};
Element._insertionTranslations = {
before: function(element, node) {
element.parentNode.insertBefore(node, element);
},
top: function(element, node) {
element.insertBefore(node, element.firstChild);
},
bottom: function(element, node) {
element.appendChild(node);
},
after: function(element, node) {
element.parentNode.insertBefore(node, element.nextSibling);
},
tags: {
TABLE: ['<table>', '</table>', 1],
TBODY: ['<table><tbody>', '</tbody></table>', 2],
TR: ['<table><tbody><tr>', '</tr></tbody></table>', 3],
TD: ['<table><tbody><tr><td>', '</td></tr></tbody></table>', 4],
SELECT: ['<select>', '</select>', 1]
}
};
(function() {
Object.extend(this.tags, {
THEAD: this.tags.TBODY,
TFOOT: this.tags.TBODY,
TH: this.tags.TD
});
}).call(Element._insertionTranslations);
Element.Methods.Simulated = {
hasAttribute: function(element, attribute) {
attribute = Element._attributeTranslations.has[attribute] || attribute;
var node = $(element).getAttributeNode(attribute);
return node && node.specified;
}
};
Element.Methods.ByTag = { };
Object.extend(Element, Element.Methods);
if (!Prototype.BrowserFeatures.ElementExtensions &&
document.createElement('div').__proto__) {
window.HTMLElement = { };
window.HTMLElement.prototype = document.createElement('div').__proto__;
Prototype.BrowserFeatures.ElementExtensions = true;
}
Element.extend = (function() {
if (Prototype.BrowserFeatures.SpecificElementExtensions)
return Prototype.K;
var Methods = { }, ByTag = Element.Methods.ByTag;
var extend = Object.extend(function(element) {
if (!element || element._extendedByPrototype ||
element.nodeType != 1 || element == window) return element;
var methods = Object.clone(Methods),
tagName = element.tagName, property, value;
if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);
for (property in methods) {
value = methods[property];
if (Object.isFunction(value) && !(property in element))
element[property] = value.methodize();
}
element._extendedByPrototype = Prototype.emptyFunction;
return element;
}, {
refresh: function() {
if (!Prototype.BrowserFeatures.ElementExtensions) {
Object.extend(Methods, Element.Methods);
Object.extend(Methods, Element.Methods.Simulated);
}
}
});
extend.refresh();
return extend;
})();
Element.hasAttribute = function(element, attribute) {
if (element.hasAttribute) return element.hasAttribute(attribute);
return Element.Methods.Simulated.hasAttribute(element, attribute);
};
Element.addMethods = function(methods) {
var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;
if (!methods) {
Object.extend(Form, Form.Methods);
Object.extend(Form.Element, Form.Element.Methods);
Object.extend(Element.Methods.ByTag, {
"FORM": Object.clone(Form.Methods),
"INPUT": Object.clone(Form.Element.Methods),
"SELECT": Object.clone(Form.Element.Methods),
"TEXTAREA": Object.clone(Form.Element.Methods)
});
}
if (arguments.length == 2) {
var tagName = methods;
methods = arguments[1];
}
if (!tagName) Object.extend(Element.Methods, methods || { });
else {
if (Object.isArray(tagName)) tagName.each(extend);
else extend(tagName);
}
function extend(tagName) {
tagName = tagName.toUpperCase();
if (!Element.Methods.ByTag[tagName])
Element.Methods.ByTag[tagName] = { };
Object.extend(Element.Methods.ByTag[tagName], methods);
}
function copy(methods, destination, onlyIfAbsent) {
onlyIfAbsent = onlyIfAbsent || false;
for (var property in methods) {
var value = methods[property];
if (!Object.isFunction(value)) continue;
if (!onlyIfAbsent || !(property in destination))
destination[property] = value.methodize();
}
}
function findDOMClass(tagName) {
var klass;
var trans = {
"OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
"FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
"DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
"H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
"INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
"TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
"TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
"TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
"FrameSet", "IFRAME": "IFrame"
};
if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
if (window[klass]) return window[klass];
klass = 'HTML' + tagName + 'Element';
if (window[klass]) return window[klass];
klass = 'HTML' + tagName.capitalize() + 'Element';
if (window[klass]) return window[klass];
window[klass] = { };
window[klass].prototype = document.createElement(tagName).__proto__;
return window[klass];
}
if (F.ElementExtensions) {
copy(Element.Methods, HTMLElement.prototype);
copy(Element.Methods.Simulated, HTMLElement.prototype, true);
}
if (F.SpecificElementExtensions) {
for (var tag in Element.Methods.ByTag) {
var klass = findDOMClass(tag);
if (Object.isUndefined(klass)) continue;
copy(T[tag], klass.prototype);
}
}
Object.extend(Element, Element.Methods);
delete Element.ByTag;
if (Element.extend.refresh) Element.extend.refresh();
Element.cache = { };
};
document.viewport = {
getDimensions: function() {
var dimensions = { };
var B = Prototype.Browser;
$w('width height').each(function(d) {
var D = d.capitalize();
dimensions[d] = (B.WebKit && !document.evaluate) ? self['inner' + D] :
(B.Opera) ? document.body['client' + D] : document.documentElement['client' + D];
});
return dimensions;
},
getWidth: function() {
return this.getDimensions().width;
},
getHeight: function() {
return this.getDimensions().height;
},
getScrollOffsets: function() {
return Element._returnOffset(
window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop);
}
};
/* Portions of the Selector class are derived from Jack Slocum’s DomQuery,
* part of YUI-Ext version 0.40, distributed under the terms of an MIT-style
* license. Please see http://www.yui-ext.com/ for more information. */
var Selector = Class.create({
initialize: function(expression) {
this.expression = expression.strip();
this.compileMatcher();
},
shouldUseXPath: function() {
if (!Prototype.BrowserFeatures.XPath) return false;
var e = this.expression;
if (Prototype.Browser.WebKit &&
(e.include("-of-type") || e.include(":empty")))
return false;
if ((/(\[[\w-]*?:|:checked)/).test(this.expression))
return false;
return true;
},
compileMatcher: function() {
if (this.shouldUseXPath())
return this.compileXPathMatcher();
var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
c = Selector.criteria, le, p, m;
if (Selector._cache[e]) {
this.matcher = Selector._cache[e];
return;
}
this.matcher = ["this.matcher = function(root) {",
"var r = root, h = Selector.handlers, c = false, n;"];
while (e && le != e && (/\S/).test(e)) {
le = e;
for (var i in ps) {
p = ps[i];
if (m = e.match(p)) {
this.matcher.push(Object.isFunction(c[i]) ? c[i](m) :
new Template(c[i]).evaluate(m));
e = e.replace(m[0], '');
break;
}
}
}
this.matcher.push("return h.unique(n);\n}");
eval(this.matcher.join('\n'));
Selector._cache[this.expression] = this.matcher;
},
compileXPathMatcher: function() {
var e = this.expression, ps = Selector.patterns,
x = Selector.xpath, le, m;
if (Selector._cache[e]) {
this.xpath = Selector._cache[e]; return;
}
this.matcher = ['.//*'];
while (e && le != e && (/\S/).test(e)) {
le = e;
for (var i in ps) {
if (m = e.match(ps[i])) {
this.matcher.push(Object.isFunction(x[i]) ? x[i](m) :
new Template(x[i]).evaluate(m));
e = e.replace(m[0], '');
break;
}
}
}
this.xpath = this.matcher.join('');
Selector._cache[this.expression] = this.xpath;
},
findElements: function(root) {
root = root || document;
if (this.xpath) return document._getElementsByXPath(this.xpath, root);
return this.matcher(root);
},
match: function(element) {
this.tokens = [];
var e = this.expression, ps = Selector.patterns, as = Selector.assertions;
var le, p, m;
while (e && le !== e && (/\S/).test(e)) {
le = e;
for (var i in ps) {
p = ps[i];
if (m = e.match(p)) {
if (as[i]) {
this.tokens.push([i, Object.clone(m)]);
e = e.replace(m[0], '');
} else {
return this.findElements(document).include(element);
}
}
}
}
var match = true, name, matches;
for (var i = 0, token; token = this.tokens[i]; i++) {
name = token[0], matches = token[1];
if (!Selector.assertions[name](element, matches)) {
match = false; break;
}
}
return match;
},
toString: function() {
return this.expression;
},
inspect: function() {
return "#<Selector:" + this.expression.inspect() + ">";
}
});
Object.extend(Selector, {
_cache: { },
xpath: {
descendant: "//*",
child: "/*",
adjacent: "/following-sibling::*[1]",
laterSibling: '/following-sibling::*',
tagName: function(m) {
if (m[1] == '*') return '';
return "[local-name()='" + m[1].toLowerCase() +
"' or local-name()='" + m[1].toUpperCase() + "']";
},
className: "[contains(concat(' ', @class, ' '), ' #{1} ')]",
id: "[@id='#{1}']",
attrPresence: function(m) {
m[1] = m[1].toLowerCase();
return new Template("[@#{1}]").evaluate(m);
},
attr: function(m) {
m[1] = m[1].toLowerCase();
m[3] = m[5] || m[6];
return new Template(Selector.xpath.operators[m[2]]).evaluate(m);
},
pseudo: function(m) {
var h = Selector.xpath.pseudos[m[1]];
if (!h) return '';
if (Object.isFunction(h)) return h(m);
return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m);
},
operators: {
'=': "[@#{1}='#{3}']",
'!=': "[@#{1}!='#{3}']",
'^=': "[starts-with(@#{1}, '#{3}')]",
'$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']",
'*=': "[contains(@#{1}, '#{3}')]",
'~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]",
'|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]"
},
pseudos: {
'first-child': '[not(preceding-sibling::*)]',
'last-child': '[not(following-sibling::*)]',
'only-child': '[not(preceding-sibling::* or following-sibling::*)]',
'empty': "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]",
'checked': "[@checked]",
'disabled': "[@disabled]",
'enabled': "[not(@disabled)]",
'not': function(m) {
var e = m[6], p = Selector.patterns,
x = Selector.xpath, le, v;
var exclusion = [];
while (e && le != e && (/\S/).test(e)) {
le = e;
for (var i in p) {
if (m = e.match(p[i])) {
v = Object.isFunction(x[i]) ? x[i](m) : new Template(x[i]).evaluate(m);
exclusion.push("(" + v.substring(1, v.length - 1) + ")");
e = e.replace(m[0], '');
break;
}
}
}
return "[not(" + exclusion.join(" and ") + ")]";
},
'nth-child': function(m) {
return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m);
},
'nth-last-child': function(m) {
return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m);
},
'nth-of-type': function(m) {
return Selector.xpath.pseudos.nth("position() ", m);
},
'nth-last-of-type': function(m) {
return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m);
},
'first-of-type': function(m) {
m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m);
},
'last-of-type': function(m) {
m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m);
},
'only-of-type': function(m) {
var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m);
},
nth: function(fragment, m) {
var mm, formula = m[6], predicate;
if (formula == 'even') formula = '2n+0';
if (formula == 'odd') formula = '2n+1';
if (mm = formula.match(/^(\d+)$/))
return '[' + fragment + "= " + mm[1] + ']';
if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) {
if (mm[1] == "-") mm[1] = -1;
var a = mm[1] ? Number(mm[1]) : 1;
var b = mm[2] ? Number(mm[2]) : 0;
predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " +
"((#{fragment} - #{b}) div #{a} >= 0)]";
return new Template(predicate).evaluate({
fragment: fragment, a: a, b: b });
}
}
}
},
criteria: {
tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;',
className: 'n = h.className(n, r, "#{1}", c); c = false;',
id: 'n = h.id(n, r, "#{1}", c); c = false;',
attrPresence: 'n = h.attrPresence(n, r, "#{1}", c); c = false;',
attr: function(m) {
m[3] = (m[5] || m[6]);
return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(m);
},
pseudo: function(m) {
if (m[6]) m[6] = m[6].replace(/"/g, '\\"');
return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m);
},
descendant: 'c = "descendant";',
child: 'c = "child";',
adjacent: 'c = "adjacent";',
laterSibling: 'c = "laterSibling";'
},
patterns: {
laterSibling: /^\s*~\s*/,
child: /^\s*>\s*/,
adjacent: /^\s*\+\s*/,
descendant: /^\s/,
tagName: /^\s*(\*|[\w\-]+)(\b|$)?/,
id: /^#([\w\-\*]+)(\b|$)/,
className: /^\.([\w\-\*]+)(\b|$)/,
pseudo:
/^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/,
attrPresence: /^\[([\w]+)\]/,
attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/
},
assertions: {
tagName: function(element, matches) {
return matches[1].toUpperCase() == element.tagName.toUpperCase();
},
className: function(element, matches) {
return Element.hasClassName(element, matches[1]);
},
id: function(element, matches) {
return element.id === matches[1];
},
attrPresence: function(element, matches) {
return Element.hasAttribute(element, matches[1]);
},
attr: function(element, matches) {
var nodeValue = Element.readAttribute(element, matches[1]);
return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]);
}
},
handlers: {
concat: function(a, b) {
for (var i = 0, node; node = b[i]; i++)
a.push(node);
return a;
},
mark: function(nodes) {
var _true = Prototype.emptyFunction;
for (var i = 0, node; node = nodes[i]; i++)
node._countedByPrototype = _true;
return nodes;
},
unmark: function(nodes) {
for (var i = 0, node; node = nodes[i]; i++)
node._countedByPrototype = undefined;
return nodes;
},
index: function(parentNode, reverse, ofType) {
parentNode._countedByPrototype = Prototype.emptyFunction;
if (reverse) {
for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) {
var node = nodes[i];
if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;
}
} else {
for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)
if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;
}
},
unique: function(nodes) {
if (nodes.length == 0) return nodes;
var results = [], n;
for (var i = 0, l = nodes.length; i < l; i++)
if (!(n = nodes[i])._countedByPrototype) {
n._countedByPrototype = Prototype.emptyFunction;
results.push(Element.extend(n));
}
return Selector.handlers.unmark(results);
},
descendant: function(nodes) {
var h = Selector.handlers;
for (var i = 0, results = [], node; node = nodes[i]; i++)
h.concat(results, node.getElementsByTagName('*'));
return results;
},
child: function(nodes) {
var h = Selector.handlers;
for (var i = 0, results = [], node; node = nodes[i]; i++) {
for (var j = 0, child; child = node.childNodes[j]; j++)
if (child.nodeType == 1 && child.tagName != '!') results.push(child);
}
return results;
},
adjacent: function(nodes) {
for (var i = 0, results = [], node; node = nodes[i]; i++) {
var next = this.nextElementSibling(node);
if (next) results.push(next);
}
return results;
},
laterSibling: function(nodes) {
var h = Selector.handlers;
for (var i = 0, results = [], node; node = nodes[i]; i++)
h.concat(results, Element.nextSiblings(node));
return results;
},
nextElementSibling: function(node) {
while (node = node.nextSibling)
if (node.nodeType == 1) return node;
return null;
},
previousElementSibling: function(node) {
while (node = node.previousSibling)
if (node.nodeType == 1) return node;
return null;
},
tagName: function(nodes, root, tagName, combinator) {
var uTagName = tagName.toUpperCase();
var results = [], h = Selector.handlers;
if (nodes) {
if (combinator) {
if (combinator == "descendant") {
for (var i = 0, node; node = nodes[i]; i++)
h.concat(results, node.getElementsByTagName(tagName));
return results;
} else nodes = this[combinator](nodes);
if (tagName == "*") return nodes;
}
for (var i = 0, node; node = nodes[i]; i++)
if (node.tagName.toUpperCase() === uTagName) results.push(node);
return results;
} else return root.getElementsByTagName(tagName);
},
id: function(nodes, root, id, combinator) {
var targetNode = $(id), h = Selector.handlers;
if (!targetNode) return [];
if (!nodes && root == document) return [targetNode];
if (nodes) {
if (combinator) {
if (combinator == 'child') {
for (var i = 0, node; node = nodes[i]; i++)
if (targetNode.parentNode == node) return [targetNode];
} else if (combinator == 'descendant') {
for (var i = 0, node; node = nodes[i]; i++)
if (Element.descendantOf(targetNode, node)) return [targetNode];
} else if (combinator == 'adjacent') {
for (var i = 0, node; node = nodes[i]; i++)
if (Selector.handlers.previousElementSibling(targetNode) == node)
return [targetNode];
} else nodes = h[combinator](nodes);
}
for (var i = 0, node; node = nodes[i]; i++)
if (node == targetNode) return [targetNode];
return [];
}
return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : [];
},
className: function(nodes, root, className, combinator) {
if (nodes && combinator) nodes = this[combinator](nodes);
return Selector.handlers.byClassName(nodes, root, className);
},
byClassName: function(nodes, root, className) {
if (!nodes) nodes = Selector.handlers.descendant([root]);
var needle = ' ' + className + ' ';
for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) {
nodeClassName = node.className;
if (nodeClassName.length == 0) continue;
if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle))
results.push(node);
}
return results;
},
attrPresence: function(nodes, root, attr, combinator) {
if (!nodes) nodes = root.getElementsByTagName("*");
if (nodes && combinator) nodes = this[combinator](nodes);
var results = [];
for (var i = 0, node; node = nodes[i]; i++)
if (Element.hasAttribute(node, attr)) results.push(node);
return results;
},
attr: function(nodes, root, attr, value, operator, combinator) {
if (!nodes) nodes = root.getElementsByTagName("*");
if (nodes && combinator) nodes = this[combinator](nodes);
var handler = Selector.operators[operator], results = [];
for (var i = 0, node; node = nodes[i]; i++) {
var nodeValue = Element.readAttribute(node, attr);
if (nodeValue === null) continue;
if (handler(nodeValue, value)) results.push(node);
}
return results;
},
pseudo: function(nodes, name, value, root, combinator) {
if (nodes && combinator) nodes = this[combinator](nodes);
if (!nodes) nodes = root.getElementsByTagName("*");
return Selector.pseudos[name](nodes, value, root);
}
},
pseudos: {
'first-child': function(nodes, value, root) {
for (var i = 0, results = [], node; node = nodes[i]; i++) {
if (Selector.handlers.previousElementSibling(node)) continue;
results.push(node);
}
return results;
},
'last-child': function(nodes, value, root) {
for (var i = 0, results = [], node; node = nodes[i]; i++) {
if (Selector.handlers.nextElementSibling(node)) continue;
results.push(node);
}
return results;
},
'only-child': function(nodes, value, root) {
var h = Selector.handlers;
for (var i = 0, results = [], node; node = nodes[i]; i++)
if (!h.previousElementSibling(node) && !h.nextElementSibling(node))
results.push(node);
return results;
},
'nth-child': function(nodes, formula, root) {
return Selector.pseudos.nth(nodes, formula, root);
},
'nth-last-child': function(nodes, formula, root) {
return Selector.pseudos.nth(nodes, formula, root, true);
},
'nth-of-type': function(nodes, formula, root) {
return Selector.pseudos.nth(nodes, formula, root, false, true);
},
'nth-last-of-type': function(nodes, formula, root) {
return Selector.pseudos.nth(nodes, formula, root, true, true);
},
'first-of-type': function(nodes, formula, root) {
return Selector.pseudos.nth(nodes, "1", root, false, true);
},
'last-of-type': function(nodes, formula, root) {
return Selector.pseudos.nth(nodes, "1", root, true, true);
},
'only-of-type': function(nodes, formula, root) {
var p = Selector.pseudos;
return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root);
},
getIndices: function(a, b, total) {
if (a == 0) return b > 0 ? [b] : [];
return $R(1, total).inject([], function(memo, i) {
if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i);
return memo;
});
},
nth: function(nodes, formula, root, reverse, ofType) {
if (nodes.length == 0) return [];
if (formula == 'even') formula = '2n+0';
if (formula == 'odd') formula = '2n+1';
var h = Selector.handlers, results = [], indexed = [], m;
h.mark(nodes);
for (var i = 0, node; node = nodes[i]; i++) {
if (!node.parentNode._countedByPrototype) {
h.index(node.parentNode, reverse, ofType);
indexed.push(node.parentNode);
}
}
if (formula.match(/^\d+$/)) {
formula = Number(formula);
for (var i = 0, node; node = nodes[i]; i++)
if (node.nodeIndex == formula) results.push(node);
} else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) {
if (m[1] == "-") m[1] = -1;
var a = m[1] ? Number(m[1]) : 1;
var b = m[2] ? Number(m[2]) : 0;
var indices = Selector.pseudos.getIndices(a, b, nodes.length);
for (var i = 0, node, l = indices.length; node = nodes[i]; i++) {
for (var j = 0; j < l; j++)
if (node.nodeIndex == indices[j]) results.push(node);
}
}
h.unmark(nodes);
h.unmark(indexed);
return results;
},
'empty': function(nodes, value, root) {
for (var i = 0, results = [], node; node = nodes[i]; i++) {
if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue;
results.push(node);
}
return results;
},
'not': function(nodes, selector, root) {
var h = Selector.handlers, selectorType, m;
var exclusions = new Selector(selector).findElements(root);
h.mark(exclusions);
for (var i = 0, results = [], node; node = nodes[i]; i++)
if (!node._countedByPrototype) results.push(node);
h.unmark(exclusions);
return results;
},
'enabled': function(nodes, value, root) {
for (var i = 0, results = [], node; node = nodes[i]; i++)
if (!node.disabled) results.push(node);
return results;
},
'disabled': function(nodes, value, root) {
for (var i = 0, results = [], node; node = nodes[i]; i++)
if (node.disabled) results.push(node);
return results;
},
'checked': function(nodes, value, root) {
for (var i = 0, results = [], node; node = nodes[i]; i++)
if (node.checked) results.push(node);
return results;
}
},
operators: {
'=': function(nv, v) { return nv == v; },
'!=': function(nv, v) { return nv != v; },
'^=': function(nv, v) { return nv.startsWith(v); },
'$=': function(nv, v) { return nv.endsWith(v); },
'*=': function(nv, v) { return nv.include(v); },
'~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },
'|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); }
},
split: function(expression) {
var expressions = [];
expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
expressions.push(m[1].strip());
});
return expressions;
},
matchElements: function(elements, expression) {
var matches = $$(expression), h = Selector.handlers;
h.mark(matches);
for (var i = 0, results = [], element; element = elements[i]; i++)
if (element._countedByPrototype) results.push(element);
h.unmark(matches);
return results;
},
findElement: function(elements, expression, index) {
if (Object.isNumber(expression)) {
index = expression; expression = false;
}
return Selector.matchElements(elements, expression || '*')[index || 0];
},
findChildElements: function(element, expressions) {
expressions = Selector.split(expressions.join(','));
var results = [], h = Selector.handlers;
for (var i = 0, l = expressions.length, selector; i < l; i++) {
selector = new Selector(expressions[i].strip());
h.concat(results, selector.findElements(element));
}
return (l > 1) ? h.unique(results) : results;
}
});
if (Prototype.Browser.IE) {
Object.extend(Selector.handlers, {
concat: function(a, b) {
for (var i = 0, node; node = b[i]; i++)
if (node.tagName !== "!") a.push(node);
return a;
},
unmark: function(nodes) {
for (var i = 0, node; node = nodes[i]; i++)
node.removeAttribute('_countedByPrototype');
return nodes;
}
});
}
function $$() {
return Selector.findChildElements(document, $A(arguments));
}
var Form = {
reset: function(form) {
$(form).reset();
return form;
},
serializeElements: function(elements, options) {
if (typeof options != 'object') options = { hash: !!options };
else if (Object.isUndefined(options.hash)) options.hash = true;
var key, value, submitted = false, submit = options.submit;
var data = elements.inject({ }, function(result, element) {
if (!element.disabled && element.name) {
key = element.name; value = $(element).getValue();
if (value != null && (element.type != 'submit' || (!submitted &&
submit !== false && (!submit || key == submit) && (submitted = true)))) {
if (key in result) {
if (!Object.isArray(result[key])) result[key] = [result[key]];
result[key].push(value);
}
else result[key] = value;
}
}
return result;
});
return options.hash ? data : Object.toQueryString(data);
}
};
Form.Methods = {
serialize: function(form, options) {
return Form.serializeElements(Form.getElements(form), options);
},
getElements: function(form) {
return $A($(form).getElementsByTagName('*')).inject([],
function(elements, child) {
if (Form.Element.Serializers[child.tagName.toLowerCase()])
elements.push(Element.extend(child));
return elements;
}
);
},
getInputs: function(form, typeName, name) {
form = $(form);
var inputs = form.getElementsByTagName('input');
if (!typeName && !name) return $A(inputs).map(Element.extend);
for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
var input = inputs[i];
if ((typeName && input.type != typeName) || (name && input.name != name))
continue;
matchingInputs.push(Element.extend(input));
}
return matchingInputs;
},
disable: function(form) {
form = $(form);
Form.getElements(form).invoke('disable');
return form;
},
enable: function(form) {
form = $(form);
Form.getElements(form).invoke('enable');
return form;
},
findFirstElement: function(form) {
var elements = $(form).getElements().findAll(function(element) {
return 'hidden' != element.type && !element.disabled;
});
var firstByIndex = elements.findAll(function(element) {
return element.hasAttribute('tabIndex') && element.tabIndex >= 0;
}).sortBy(function(element) { return element.tabIndex }).first();
return firstByIndex ? firstByIndex : elements.find(function(element) {
return ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
});
},
focusFirstElement: function(form) {
form = $(form);
form.findFirstElement().activate();
return form;
},
request: function(form, options) {
form = $(form), options = Object.clone(options || { });
var params = options.parameters, action = form.readAttribute('action') || '';
if (action.blank()) action = window.location.href;
options.parameters = form.serialize(true);
if (params) {
if (Object.isString(params)) params = params.toQueryParams();
Object.extend(options.parameters, params);
}
if (form.hasAttribute('method') && !options.method)
options.method = form.method;
return new Ajax.Request(action, options);
}
};
/*--------------------------------------------------------------------------*/
Form.Element = {
focus: function(element) {
$(element).focus();
return element;
},
select: function(element) {
$(element).select();
return element;
}
};
Form.Element.Methods = {
serialize: function(element) {
element = $(element);
if (!element.disabled && element.name) {
var value = element.getValue();
if (value != undefined) {
var pair = { };
pair[element.name] = value;
return Object.toQueryString(pair);
}
}
return '';
},
getValue: function(element) {
element = $(element);
var method = element.tagName.toLowerCase();
return Form.Element.Serializers[method](element);
},
setValue: function(element, value) {
element = $(element);
var method = element.tagName.toLowerCase();
Form.Element.Serializers[method](element, value);
return element;
},
clear: function(element) {
$(element).value = '';
return element;
},
present: function(element) {
return $(element).value != '';
},
activate: function(element) {
element = $(element);
try {
element.focus();
if (element.select && (element.tagName.toLowerCase() != 'input' ||
!['button', 'reset', 'submit'].include(element.type)))
element.select();
} catch (e) { }
return element;
},
disable: function(element) {
element = $(element);
element.blur();
element.disabled = true;
return element;
},
enable: function(element) {
element = $(element);
element.disabled = false;
return element;
}
};
/*--------------------------------------------------------------------------*/
var Field = Form.Element;
var $F = Form.Element.Methods.getValue;
/*--------------------------------------------------------------------------*/
Form.Element.Serializers = {
input: function(element, value) {
switch (element.type.toLowerCase()) {
case 'checkbox':
case 'radio':
return Form.Element.Serializers.inputSelector(element, value);
default:
return Form.Element.Serializers.textarea(element, value);
}
},
inputSelector: function(element, value) {
if (Object.isUndefined(value)) return element.checked ? element.value : null;
else element.checked = !!value;
},
textarea: function(element, value) {
if (Object.isUndefined(value)) return element.value;
else element.value = value;
},
select: function(element, index) {
if (Object.isUndefined(index))
return this[element.type == 'select-one' ?
'selectOne' : 'selectMany'](element);
else {
var opt, value, single = !Object.isArray(index);
for (var i = 0, length = element.length; i < length; i++) {
opt = element.options[i];
value = this.optionValue(opt);
if (single) {
if (value == index) {
opt.selected = true;
return;
}
}
else opt.selected = index.include(value);
}
}
},
selectOne: function(element) {
var index = element.selectedIndex;
return index >= 0 ? this.optionValue(element.options[index]) : null;
},
selectMany: function(element) {
var values, length = element.length;
if (!length) return null;
for (var i = 0, values = []; i < length; i++) {
var opt = element.options[i];
if (opt.selected) values.push(this.optionValue(opt));
}
return values;
},
optionValue: function(opt) {
return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
}
};
/*--------------------------------------------------------------------------*/
Abstract.TimedObserver = Class.create(PeriodicalExecuter, {
initialize: function($super, element, frequency, callback) {
$super(callback, frequency);
this.element = $(element);
this.lastValue = this.getValue();
},
execute: function() {
var value = this.getValue();
if (Object.isString(this.lastValue) && Object.isString(value) ?
this.lastValue != value : String(this.lastValue) != String(value)) {
this.callback(this.element, value);
this.lastValue = value;
}
}
});
Form.Element.Observer = Class.create(Abstract.TimedObserver, {
getValue: function() {
return Form.Element.getValue(this.element);
}
});
Form.Observer = Class.create(Abstract.TimedObserver, {
getValue: function() {
return Form.serialize(this.element);
}
});
/*--------------------------------------------------------------------------*/
Abstract.EventObserver = Class.create({
initialize: function(element, callback) {
this.element = $(element);
this.callback = callback;
this.lastValue = this.getValue();
if (this.element.tagName.toLowerCase() == 'form')
this.registerFormCallbacks();
else
this.registerCallback(this.element);
},
onElementEvent: function() {
var value = this.getValue();
if (this.lastValue != value) {
this.callback(this.element, value);
this.lastValue = value;
}
},
registerFormCallbacks: function() {
Form.getElements(this.element).each(this.registerCallback, this);
},
registerCallback: function(element) {
if (element.type) {
switch (element.type.toLowerCase()) {
case 'checkbox':
case 'radio':
Event.observe(element, 'click', this.onElementEvent.bind(this));
break;
default:
Event.observe(element, 'change', this.onElementEvent.bind(this));
break;
}
}
}
});
Form.Element.EventObserver = Class.create(Abstract.EventObserver, {
getValue: function() {
return Form.Element.getValue(this.element);
}
});
Form.EventObserver = Class.create(Abstract.EventObserver, {
getValue: function() {
return Form.serialize(this.element);
}
});
if (!window.Event) var Event = { };
Object.extend(Event, {
KEY_BACKSPACE: 8,
KEY_TAB: 9,
KEY_RETURN: 13,
KEY_ESC: 27,
KEY_LEFT: 37,
KEY_UP: 38,
KEY_RIGHT: 39,
KEY_DOWN: 40,
KEY_DELETE: 46,
KEY_HOME: 36,
KEY_END: 35,
KEY_PAGEUP: 33,
KEY_PAGEDOWN: 34,
KEY_INSERT: 45,
cache: { },
relatedTarget: function(event) {
var element;
switch(event.type) {
case 'mouseover': element = event.fromElement; break;
case 'mouseout': element = event.toElement; break;
default: return null;
}
return Element.extend(element);
}
});
Event.Methods = (function() {
var isButton;
if (Prototype.Browser.IE) {
var buttonMap = { 0: 1, 1: 4, 2: 2 };
isButton = function(event, code) {
return event.button == buttonMap[code];
};
} else if (Prototype.Browser.WebKit) {
isButton = function(event, code) {
switch (code) {
case 0: return event.which == 1 && !event.metaKey;
case 1: return event.which == 1 && event.metaKey;
default: return false;
}
};
} else {
isButton = function(event, code) {
return event.which ? (event.which === code + 1) : (event.button === code);
};
}
return {
isLeftClick: function(event) { return isButton(event, 0) },
isMiddleClick: function(event) { return isButton(event, 1) },
isRightClick: function(event) { return isButton(event, 2) },
element: function(event) {
var node = Event.extend(event).target;
return Element.extend(node.nodeType == Node.TEXT_NODE ? node.parentNode : node);
},
findElement: function(event, expression) {
var element = Event.element(event);
if (!expression) return element;
var elements = [element].concat(element.ancestors());
return Selector.findElement(elements, expression, 0);
},
pointer: function(event) {
return {
x: event.pageX || (event.clientX +
(document.documentElement.scrollLeft || document.body.scrollLeft)),
y: event.pageY || (event.clientY +
(document.documentElement.scrollTop || document.body.scrollTop))
};
},
pointerX: function(event) { return Event.pointer(event).x },
pointerY: function(event) { return Event.pointer(event).y },
stop: function(event) {
Event.extend(event);
event.preventDefault();
event.stopPropagation();
event.stopped = true;
}
};
})();
Event.extend = (function() {
var methods = Object.keys(Event.Methods).inject({ }, function(m, name) {
m[name] = Event.Methods[name].methodize();
return m;
});
if (Prototype.Browser.IE) {
Object.extend(methods, {
stopPropagation: function() { this.cancelBubble = true },
preventDefault: function() { this.returnValue = false },
inspect: function() { return "[object Event]" }
});
return function(event) {
if (!event) return false;
if (event._extendedByPrototype) return event;
event._extendedByPrototype = Prototype.emptyFunction;
var pointer = Event.pointer(event);
Object.extend(event, {
target: event.srcElement,
relatedTarget: Event.relatedTarget(event),
pageX: pointer.x,
pageY: pointer.y
});
return Object.extend(event, methods);
};
} else {
Event.prototype = Event.prototype || document.createEvent("HTMLEvents").__proto__;
Object.extend(Event.prototype, methods);
return Prototype.K;
}
})();
Object.extend(Event, (function() {
var cache = Event.cache;
function getEventID(element) {
if (element._prototypeEventID) return element._prototypeEventID[0];
arguments.callee.id = arguments.callee.id || 1;
return element._prototypeEventID = [++arguments.callee.id];
}
function getDOMEventName(eventName) {
if (eventName && eventName.include(':')) return "dataavailable";
return eventName;
}
function getCacheForID(id) {
return cache[id] = cache[id] || { };
}
function getWrappersForEventName(id, eventName) {
var c = getCacheForID(id);
return c[eventName] = c[eventName] || [];
}
function createWrapper(element, eventName, handler) {
var id = getEventID(element);
var c = getWrappersForEventName(id, eventName);
if (c.pluck("handler").include(handler)) return false;
var wrapper = function(event) {
if (!Event || !Event.extend ||
(event.eventName && event.eventName != eventName))
return false;
Event.extend(event);
handler.call(element, event);
};
wrapper.handler = handler;
c.push(wrapper);
return wrapper;
}
function findWrapper(id, eventName, handler) {
var c = getWrappersForEventName(id, eventName);
return c.find(function(wrapper) { return wrapper.handler == handler });
}
function destroyWrapper(id, eventName, handler) {
var c = getCacheForID(id);
if (!c[eventName]) return false;
c[eventName] = c[eventName].without(findWrapper(id, eventName, handler));
}
function destroyCache() {
for (var id in cache)
for (var eventName in cache[id])
cache[id][eventName] = null;
}
if (window.attachEvent) {
window.attachEvent("onunload", destroyCache);
}
return {
observe: function(element, eventName, handler) {
element = $(element);
var name = getDOMEventName(eventName);
var wrapper = createWrapper(element, eventName, handler);
if (!wrapper) return element;
if (element.addEventListener) {
element.addEventListener(name, wrapper, false);
} else {
element.attachEvent("on" + name, wrapper);
}
return element;
},
stopObserving: function(element, eventName, handler) {
element = $(element);
var id = getEventID(element), name = getDOMEventName(eventName);
if (!handler && eventName) {
getWrappersForEventName(id, eventName).each(function(wrapper) {
element.stopObserving(eventName, wrapper.handler);
});
return element;
} else if (!eventName) {
Object.keys(getCacheForID(id)).each(function(eventName) {
element.stopObserving(eventName);
});
return element;
}
var wrapper = findWrapper(id, eventName, handler);
if (!wrapper) return element;
if (element.removeEventListener) {
element.removeEventListener(name, wrapper, false);
} else {
element.detachEvent("on" + name, wrapper);
}
destroyWrapper(id, eventName, handler);
return element;
},
fire: function(element, eventName, memo) {
element = $(element);
if (element == document && document.createEvent && !element.dispatchEvent)
element = document.documentElement;
var event;
if (document.createEvent) {
event = document.createEvent("HTMLEvents");
event.initEvent("dataavailable", true, true);
} else {
event = document.createEventObject();
event.eventType = "ondataavailable";
}
event.eventName = eventName;
event.memo = memo || { };
if (document.createEvent) {
element.dispatchEvent(event);
} else {
element.fireEvent(event.eventType, event);
}
return Event.extend(event);
}
};
})());
Object.extend(Event, Event.Methods);
Element.addMethods({
fire: Event.fire,
observe: Event.observe,
stopObserving: Event.stopObserving
});
Object.extend(document, {
fire: Element.Methods.fire.methodize(),
observe: Element.Methods.observe.methodize(),
stopObserving: Element.Methods.stopObserving.methodize(),
loaded: false
});
(function() {
/* Support for the DOMContentLoaded event is based on work by Dan Webb,
Matthias Miller, Dean Edwards and John Resig. */
var timer;
function fireContentLoadedEvent() {
if (document.loaded) return;
if (timer) window.clearInterval(timer);
document.fire("dom:loaded");
document.loaded = true;
}
if (document.addEventListener) {
if (Prototype.Browser.WebKit) {
timer = window.setInterval(function() {
if (/loaded|complete/.test(document.readyState))
fireContentLoadedEvent();
}, 0);
Event.observe(window, "load", fireContentLoadedEvent);
} else {
document.addEventListener("DOMContentLoaded",
fireContentLoadedEvent, false);
}
} else {
document.write("<script id=__onDOMContentLoaded defer src=//:><\/script>");
$("__onDOMContentLoaded").onreadystatechange = function() {
if (this.readyState == "complete") {
this.onreadystatechange = null;
fireContentLoadedEvent();
}
};
}
})();
/*------------------------------- DEPRECATED -------------------------------*/
Hash.toQueryString = Object.toQueryString;
var Toggle = { display: Element.toggle };
Element.Methods.childOf = Element.Methods.descendantOf;
var Insertion = {
Before: function(element, content) {
return Element.insert(element, {before:content});
},
Top: function(element, content) {
return Element.insert(element, {top:content});
},
Bottom: function(element, content) {
return Element.insert(element, {bottom:content});
},
After: function(element, content) {
return Element.insert(element, {after:content});
}
};
var $continue = new Error('"throw $continue" is deprecated, use "return" instead');
var Position = {
includeScrollOffsets: false,
prepare: function() {
this.deltaX = window.pageXOffset
|| document.documentElement.scrollLeft
|| document.body.scrollLeft
|| 0;
this.deltaY = window.pageYOffset
|| document.documentElement.scrollTop
|| document.body.scrollTop
|| 0;
},
within: function(element, x, y) {
if (this.includeScrollOffsets)
return this.withinIncludingScrolloffsets(element, x, y);
this.xcomp = x;
this.ycomp = y;
this.offset = Element.cumulativeOffset(element);
return (y >= this.offset[1] &&
y < this.offset[1] + element.offsetHeight &&
x >= this.offset[0] &&
x < this.offset[0] + element.offsetWidth);
},
withinIncludingScrolloffsets: function(element, x, y) {
var offsetcache = Element.cumulativeScrollOffset(element);
this.xcomp = x + offsetcache[0] - this.deltaX;
this.ycomp = y + offsetcache[1] - this.deltaY;
this.offset = Element.cumulativeOffset(element);
return (this.ycomp >= this.offset[1] &&
this.ycomp < this.offset[1] + element.offsetHeight &&
this.xcomp >= this.offset[0] &&
this.xcomp < this.offset[0] + element.offsetWidth);
},
overlap: function(mode, element) {
if (!mode) return 0;
if (mode == 'vertical')
return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
element.offsetHeight;
if (mode == 'horizontal')
return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
element.offsetWidth;
},
cumulativeOffset: Element.Methods.cumulativeOffset,
positionedOffset: Element.Methods.positionedOffset,
absolutize: function(element) {
Position.prepare();
return Element.absolutize(element);
},
relativize: function(element) {
Position.prepare();
return Element.relativize(element);
},
realOffset: Element.Methods.cumulativeScrollOffset,
offsetParent: Element.Methods.getOffsetParent,
page: Element.Methods.viewportOffset,
clone: function(source, target, options) {
options = options || { };
return Element.clonePosition(target, source, options);
}
};
/*--------------------------------------------------------------------------*/
if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){
function iter(name) {
return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]";
}
instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ?
function(element, className) {
className = className.toString().strip();
var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className);
return cond ? document._getElementsByXPath('.//*' + cond, element) : [];
} : function(element, className) {
className = className.toString().strip();
var elements = [], classNames = (/\s/.test(className) ? $w(className) : null);
if (!classNames && !className) return elements;
var nodes = $(element).getElementsByTagName('*');
className = ' ' + className + ' ';
for (var i = 0, child, cn; child = nodes[i]; i++) {
if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) ||
(classNames && classNames.all(function(name) {
return !name.toString().blank() && cn.include(' ' + name + ' ');
}))))
elements.push(Element.extend(child));
}
return elements;
};
return function(className, parentElement) {
return $(parentElement || document.body).getElementsByClassName(className);
};
}(Element.Methods);
/*--------------------------------------------------------------------------*/
Element.ClassNames = Class.create();
Element.ClassNames.prototype = {
initialize: function(element) {
this.element = $(element);
},
_each: function(iterator) {
this.element.className.split(/\s+/).select(function(name) {
return name.length > 0;
})._each(iterator);
},
set: function(className) {
this.element.className = className;
},
add: function(classNameToAdd) {
if (this.include(classNameToAdd)) return;
this.set($A(this).concat(classNameToAdd).join(' '));
},
remove: function(classNameToRemove) {
if (!this.include(classNameToRemove)) return;
this.set($A(this).without(classNameToRemove).join(' '));
},
toString: function() {
return $A(this).join(' ');
}
};
Object.extend(Element.ClassNames.prototype, Enumerable);
/*--------------------------------------------------------------------------*/
Element.addMethods();
RegExp.escape = function(text) {
if (!arguments.callee.sRE) {
var specials = [
'/', '.', '*', '+', '?', '|', '$', '^',
'(', ')', '[', ']', '{', '}', '\\'
];
arguments.callee.sRE = new RegExp(
'(\\' + specials.join('|\\') + ')', 'g'
);
}
return text.replace(arguments.callee.sRE, '\\$1');
}
function _to_utf8(s) {
var c, d = "";
for (var i = 0; i < s.length; i++) {
c = s.charCodeAt(i);
if (c <= 0x7f) {
d += s.charAt(i);
} else if (c >= 0x80 && c <= 0x7ff) {
d += String.fromCharCode(((c >> 6) & 0x1f) | 0xc0);
d += String.fromCharCode((c & 0x3f) | 0x80);
} else {
d += String.fromCharCode((c >> 12) | 0xe0);
d += String.fromCharCode(((c >> 6) & 0x3f) | 0x80);
d += String.fromCharCode((c & 0x3f) | 0x80);
}
}
return d;
}
function _from_utf8(s) {
var c, d = "", flag = 0, tmp;
for (var i = 0; i < s.length; i++) {
c = s.charCodeAt(i);
if (flag == 0) {
if ((c & 0xe0) == 0xe0) {
flag = 2;
tmp = (c & 0x0f) << 12;
} else if ((c & 0xc0) == 0xc0) {
flag = 1;
tmp = (c & 0x1f) << 6;
} else if ((c & 0x80) == 0) {
d += s.charAt(i);
} else {
flag = 0;
}
} else if (flag == 1) {
flag = 0;
d += String.fromCharCode(tmp | (c & 0x3f));
} else if (flag == 2) {
flag = 3;
tmp |= (c & 0x3f) << 6;
} else if (flag == 3) {
flag = 0;
d += String.fromCharCode(tmp | (c & 0x3f));
} else {
flag = 0;
}
}
return d;
}
function sprintf2(arg) {
if( arg.length < 2 ) {
return arg[0];
}
var data = arg[ 0 ];
for( var k=1; k<arg.length; ++k ) {
switch( typeof( arg[ k ] ) )
{
case 'string':
data = data.replace( /%s/, arg[ k ] );
break;
case 'number':
data = data.replace( /%d/, arg[ k ] );
break;
case 'boolean':
data = data.replace( /%b/, arg[ k ] ? 'true' : 'false' );
break;
default:
break;
}
}
return( data );
}
if( !String.sprintf2 ) {
String.sprintf2 = sprintf2;
}
var DetectActivity = Class.create();
DetectActivity.prototype = {
initialize: function(subject)
{
this.onunactivate = function() {};
this.onactivate = function() {};
this.subject = subject;
this.isactive = true;
Event.observe(subject, 'mousemove', this._OnFocus.bindAsEventListener(this), false);
Event.observe(subject, 'mouseout', this._OnBlur.bindAsEventListener(this), false);
},
_OnFocus: function(e)
{
this.isactive = true;
if (this.onactivate) this.onactivate();
},
_OnBlur: function(e)
{
this.isactive = false;
if (this.onunactivate) this.onunactivate();
},
isActive: function()
{
return this.isactive;
}
}
/*
_launchTimeout: function(myself)
{
var oldisactive = this.isactive;
if (this.oldposx == this.posx &&
this.oldposy == this.posy)
this.isactive = false;
else
this.isactive = true;
this.oldposx = this.posx;
this.oldposy = this.posy;
if (oldisactive != this.isactive) alert("switch");
setTimeout(function() { myself._launchTimeout(myself); }, 1000);
},
_OnMouseMove: function(e)
{
var posx = 0;
var posy = 0;
if (!e) var e = window.event;
if (e.pageX || e.pageY)
{
posx = e.pageX;
posy = e.pageY;
}
else if (e.clientX || e.clientY)
{
posx = e.clientX + document.body.scrollLeft
+ document.documentElement.scrollLeft;
posy = e.clientY + document.body.scrollTop
+ document.documentElement.scrollTop;
}
this.posx = posx;
this.posy = posy;
},
*/
function mousePosX(e) {
var posx = 0;
if (!e) var e = window.event;
if (e.pageX) {
posx = e.pageX;
}
else if (e.clientX) {
posx = e.clientX + document.body.scrollLeft
+ document.documentElement.scrollLeft;
}
return posx;
}
function mousePosY(e) {
var posy = 0;
if (!e) var e = window.event;
if (e.pageY) {
posy = e.pageY;
}
else if (e.clientY) {
posy = e.clientY + document.body.scrollTop
+ document.documentElement.scrollTop;
}
return posy;
}
var pfcCSS = Class.create();
pfcCSS.prototype = {
initialize: function()
{
if (!document.getElementsByTagName ||
!(document.createElement || document.createElementNS)) return;
var agt = navigator.userAgent.toLowerCase();
this.is_ie = ((agt.indexOf("msie") != -1) && (agt.indexOf("opera") == -1));
this.is_iewin = (is_ie && (agt.indexOf("win") != -1));
this.is_iemac = (is_ie && (agt.indexOf("mac") != -1));
if (this.is_iemac) return;
var head = document.getElementsByTagName("head")[0];
this.style = (typeof document.createElementNS != "undefined") ?
document.createElementNS("http://www.w3.org/1999/xhtml", "style") :
document.createElement("style");
this.style.setAttribute("type", "text/css");
this.style.setAttribute("media", "screen");
head.appendChild(this.style);
this.lastStyle = document.styleSheets[document.styleSheets.length - 1];
},
applyRule: function(selector, declaration)
{
selector = selector.split(',');
for ( var i = 0; i < selector.length; i++)
{
if (!this.is_iewin) {
var styleRule = document.createTextNode(selector[i] + " {" + declaration + "}");
this.style.appendChild(styleRule);
}
if (this.is_iewin && document.styleSheets && document.styleSheets.length > 0) {
this.lastStyle.addRule(selector[i], declaration);
}
}
}
}
var is_ie = !!(window.attachEvent && !window.opera);
var is_khtml = !!(navigator.appName.match("Konqueror") || navigator.appVersion.match("KHTML"));
var is_gecko = navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1;
var is_ie7 = navigator.userAgent.indexOf('MSIE 7') > 0;
var is_opera = !!window.opera;
var is_webkit = navigator.userAgent.indexOf('AppleWebKit/') > -1;
/**
* This class is the client part of phpFreeChat
* (depends on prototype library)
* @author Stephane Gully
*/
var pfcClient = Class.create();
pfcClient.prototype = {
initialize: function()
{
this.gui = new pfcGui();
this.res = new pfcResource();
this.nickname = pfc_nickname;
this.nickid = pfc_nickid;
this.usermeta = $H();
this.chanmeta = $H();
this.nickwhoisbox = $H();
this.cmdhistory = Array();
this.cmdhistoryid = -1;
this.cmdhistoryissearching = false;
/*
this.channels = Array();
this.channelids = Array();
*/
this.privmsgs = Array();
this.privmsgids = Array();
this.timeout = null;
this.timeout_time = new Date().getTime();
this.refresh_delay = pfc_refresh_delay;
this.refresh_delay_steps = pfc_refresh_delay_steps;
this.last_response_time = new Date().getTime();
this.last_request_time = new Date().getTime();
this.last_activity_time = new Date().getTime();
/* unique client id for each windows used to identify a open window
* this id is passed every time the JS communicate with server
* (2 clients can use the same session: then only the nickname is shared) */
this.clientid = pfc_clientid;
this.isconnected = false;
this.nicklist = $H();
this.nickcolor = Array();
this.colorlist = Array();
this.blinktmp = Array();
this.blinkloop = Array();
this.blinktimeout = Array();
},
loadChat: function() {
new Ajax.Request(pfc_server_script_url, {
method: 'get',
parameters: {pfc_ajax: 1, f: 'loadChat'},
onSuccess: function(transport) {
eval( transport.responseText );
}
});
},
connectListener: function()
{
this.el_words = $('pfc_words');
this.el_handle = $('pfc_handle');
this.el_container = $('pfc_container');
this.el_errors = $('pfc_errors');
this.detectactivity = new DetectActivity(this.el_container);
if (pfc_notify_window) this.detectactivity.onunactivate = this.gui.unnotifyWindow.bindAsEventListener(this.gui);
/* the events callbacks */
this.el_words.onkeypress = this.callbackWords_OnKeypress.bindAsEventListener(this);
Event.observe(this.el_words, 'keydown', this.callbackWords_OnKeydown.bindAsEventListener(this), false);
Event.observe(this.el_words, 'keyup', this.callbackWords_OnKeyup.bindAsEventListener(this), false);
Event.observe(this.el_words, 'mouseup', this.callbackWords_OnMouseup.bindAsEventListener(this), false);
Event.observe(this.el_words, 'focus', this.callbackWords_OnFocus.bindAsEventListener(this), false);
Event.observe(document.body, 'unload', this.callback_OnUnload.bindAsEventListener(this), false);
},
refreshGUI: function()
{
this.minmax_status = pfc_start_minimized;
var cookie = getCookie('pfc_minmax_status');
if (cookie != null)
this.minmax_status = (cookie == 'true');
cookie = getCookie('pfc_nickmarker');
this.nickmarker = (cookie == 'true');
if (cookie == '' || cookie == null)
this.nickmarker = pfc_nickmarker;
cookie = getCookie('pfc_clock');
this.clock = (cookie == 'true');
if (cookie == '' || cookie == null)
this.clock = pfc_clock;
cookie = getCookie('pfc_showsmileys');
this.showsmileys = (cookie == 'true');
if (cookie == '' || cookie == null)
this.showsmileys = pfc_showsmileys;
cookie = getCookie('pfc_showwhosonline');
this.showwhosonline = (cookie == 'true');
if (cookie == '' || cookie == null)
this.showwhosonline = pfc_showwhosonline;
this.current_text_color = '';
cookie = getCookie('pfc_current_text_color');
if (cookie != null)
this.switch_text_color(cookie);
cookie = getCookie('pfc_issoundenable');
this.issoundenable = (cookie == 'true');
if (cookie == '' || cookie == null)
this.issoundenable = pfc_startwithsound;
this.refresh_loginlogout();
this.refresh_minimize_maximize();
this.refresh_Smileys();
this.refresh_sound();
this.refresh_nickmarker();
},
/**
* Show a popup dialog to ask user to choose a nickname
*/
askNick: function(nickname,error_text)
{
if (nickname == '' || nickname == undefined) nickname = this.nickname;
var pfcp = this.getPrompt();//new pfcPrompt($('pfc_container'));
pfcp.callback = function(v) { pfc.askNickResponse(v); }
pfcp.prompt((error_text != undefined ? '<span style="color:red">'+error_text+'</span><br/>' : '')+this.res.getLabel('Please enter your nickname'), nickname);
pfcp.focus();
},
askNickResponse: function(newnick)
{
if (newnick)
{
if (this.isconnected)
this.sendRequest('/nick "'+newnick+'"');
else
this.sendRequest('/connect "'+newnick+'"');
}
},
/**
* Reacte to the server response
*/
handleResponse: function(cmd, resp, param)
{
if (pfc_debug)
if (cmd != "update")
{
var param2 = param;
if (cmd == "who" || cmd == "who2")
{
param2 = $H(param2);
param2.set('meta', $H(param2.get('meta')));
param2.get('meta').set('users', $H(param2.get('meta').get('users')));
trace('handleResponse: '+cmd + "-"+resp+"-"+param2.inspect());
}
else
if (cmd == "whois" || cmd == "whois2")
{
param2 = $H(param2);
trace('handleResponse: '+cmd + "-"+resp+"-"+param2.inspect());
}
else
if (cmd == "getnewmsg" || cmd == "join")
{
param2 = $A(param2);
trace('handleResponse: '+cmd + "-"+resp+"-"+param2.inspect());
}
else
trace('handleResponse: '+cmd + "-"+resp+"-"+param);
}
if (cmd != "update")
{
this.last_activity_time = new Date().getTime();
var delay = this.calcDelay();
if (this.timeout_time - new Date().getTime() > delay)
{
clearTimeout(this.timeout);
this.timeout = setTimeout('pfc.updateChat(true)', delay);
this.timeout_time = new Date().getTime() + delay;
}
}
if (cmd == "connect")
{
if (resp == "ok")
{
this.nickname = param[0];
this.isconnected = true;
this.updateChat(true);
}
else
this.isconnected = false;
this.refresh_loginlogout();
}
else if (cmd == "quit")
{
if (resp =="ok")
{
this.updateChat(false);
this.isconnected = false;
this.refresh_loginlogout();
}
}
else if (cmd == "join" || cmd == "join2")
{
if (resp =="ok")
{
var tabid = param[0];
var name = param[1];
this.gui.createTab(name, tabid, "ch");
if (cmd != "join2" || this.gui.tabs.length == 1) this.gui.setTabById(tabid);
this.refresh_Smileys();
this.refresh_WhosOnline();
}
else if (resp == "max_channels")
{
this.displayMsg( cmd, this.res.getLabel('Maximum number of joined channels has been reached') );
}
else
alert(cmd + "-"+resp+"-"+param);
}
else if (cmd == "leave")
{
if (resp =="ok")
{
var tabid = param;
this.gui.removeTabById(tabid);
/*
var index = -1;
index = this.channelids.indexOf(tabid);
this.channelids = this.channelids.without(tabid);
this.channels = this.channels.without(this.channels[index]);
*/
index = -1;
index = indexOf(this.privmsgids, tabid);
this.privmsgids = without(this.privmsgids, tabid);
this.privmsgs = without(this.privmsgs, this.privmsgs[index]);
}
}
else if (cmd == "privmsg" || cmd == "privmsg2")
{
if (resp == "ok")
{
var tabid = param[0];
var name = param[1];
this.gui.createTab(name, tabid, "pv");
if (cmd != "privmsg2" || this.gui.tabs.length == 1) this.gui.setTabById(tabid);
this.privmsgs.push(name);
this.privmsgids.push(tabid);
}
else if (resp == "max_privmsg")
{
this.displayMsg( cmd, this.res.getLabel('Maximum number of private chat has been reached') );
}
else if (resp == "unknown")
{
this.displayMsg( cmd, this.res.getLabel('You are trying to speak to a unknown (or not connected) user') );
}
else if (resp == "speak_to_myself")
{
this.displayMsg( cmd, this.res.getLabel('You are not allowed to speak to yourself') );
}
else
alert(cmd + "-"+resp+"-"+param);
}
else if (cmd == "nick")
{
if (pfc_focus_on_connect) this.el_words.focus();
if (resp == "connected" || resp == "notchanged")
{
cmd = '';
}
if (resp == "ok" || resp == "notchanged" || resp == "changed" || resp == "connected")
{
this.setUserMeta(this.nickid, 'nick', param);
this.el_handle.innerHTML = this.getUserMeta(this.nickid, 'nick').escapeHTML();
this.nickname = this.getUserMeta(this.nickid, 'nick');
this.updateNickBox(this.nickid);
this.clearError(Array(this.el_words));
}
else if (resp == "isused")
{
this.setError(this.res.getLabel('Chosen nickname is already used'), Array());
this.askNick(param,this.res.getLabel('Chosen nickname is already used'));
}
else if (resp == "notallowed")
{
this.setError(this.res.getLabel('Chosen nickname is not allowed'), Array());
this.updateChat(false);
this.isconnected = false;
this.refresh_loginlogout();
}
}
else if (cmd == "update")
{
}
else if (cmd == "version")
{
if (resp == "ok")
{
this.displayMsg( cmd, this.res.getLabel('phpfreechat current version is %s',param) );
}
}
else if (cmd == "help")
{
if (resp == "ok")
{
this.displayMsg( cmd, param);
}
}
else if (cmd == "rehash")
{
if (resp == "ok")
{
this.displayMsg( cmd, this.res.getLabel('Configuration has been rehashed') );
}
else if (resp == "ko")
{
this.displayMsg( cmd, this.res.getLabel('A problem occurs during rehash') );
}
}
else if (cmd == "banlist")
{
if (resp == "ok" || resp == "ko")
{
this.displayMsg( cmd, param );
}
}
else if (cmd == "unban")
{
if (resp == "ok" || resp == "ko")
{
this.displayMsg( cmd, param );
}
}
else if (cmd == "auth")
{
if (resp == "ban")
{
alert(param);
}
if (resp == "frozen")
{
alert(param);
}
else if (resp == "nick")
{
this.displayMsg( cmd, param );
}
}
else if (cmd == "debug")
{
if (resp == "ok" || resp == "ko")
{
this.displayMsg( cmd, param );
}
}
else if (cmd == "clear")
{
var tabid = this.gui.getTabId();
var container = this.gui.getChatContentFromTabId(tabid);
container.innerHTML = "";
}
else if (cmd == "identify")
{
this.displayMsg( cmd, param );
}
else if (cmd == "checknickchange")
{
this.displayMsg( cmd, param );
}
else if (cmd == "whois" || cmd == "whois2")
{
param = $H(param);
var nickid = param.get('nickid');
if (resp == "ok")
{
this.setUserMeta(nickid, param);
this.updateNickBox(nickid);
this.updateNickWhoisBox(nickid);
}
if (cmd == "whois")
{
var um = this.getAllUserMeta(nickid);
var um_keys = um.keys();
var msg = '';
for (var i=0; i<um_keys.length; i++)
{
var k = um_keys[i];
var v = um.get(k);
if (v &&
k != 'nickid' &&
k != 'floodtime' &&
k != 'flood_nbmsg' &&
k != 'flood_nbchar')
msg = msg + '<strong>' + k + '</strong>: ' + v + '<br/>';
}
this.displayMsg( cmd, msg );
}
}
else if (cmd == "who" || cmd == "who2")
{
param = $H(param);
var chan = param.get('chan');
var chanid = param.get('chanid');
var meta = $H(param.get('meta'));
meta.set('users', $H(meta.get('users')));
if (resp == "ok")
{
this.setChanMeta(chanid,meta);
for (var i=0; i<meta.get('users').get('nickid').length; i++)
{
var nickid = meta.get('users').get('nickid')[i];
var nick = meta.get('users').get('nick')[i];
var um = this.getAllUserMeta(nickid);
if (!um) this.sendRequest('/whois2 "'+nickid+'"');
}
this.updateNickListBox(chanid);
}
if (cmd == "who")
{
var cm = this.getAllChanMeta(chanid);
var cm_keys = cm.keys();
var msg = '';
for (var i=0; i<cm_keys.length; i++)
{
var k = cm_keys[i];
var v = cm[k];
if (k != 'users')
{
msg = msg + '<strong>' + k + '</strong>: ' + v + '<br/>';
}
}
this.displayMsg( cmd, msg );
}
}
else if (cmd == "getnewmsg")
{
if (resp == "ok")
{
this.handleComingRequest(param);
}
}
else if (cmd == "send")
{
}
else
alert(cmd + "-"+resp+"-"+param);
},
getAllUserMeta: function(nickid)
{
if (nickid && this.usermeta.get(nickid))
return this.usermeta.get(nickid);
else
return null;
},
getUserMeta: function(nickid, key)
{
if (nickid && key && this.usermeta.get(nickid) && this.usermeta.get(nickid).get(key))
return this.usermeta.get(nickid).get(key);
else
return '';
},
setUserMeta: function(nickid, key, value)
{
if (nickid && key)
{
if (!this.usermeta.get(nickid)) this.usermeta.set(nickid, $H());
if (value)
this.usermeta.get(nickid).set(key, value);
else
this.usermeta.set(nickid, $H(key));
}
},
getAllChanMeta: function(chanid)
{
if (chanid && this.chanmeta.get(chanid))
return this.chanmeta.get(chanid);
else
return null;
},
getChanMeta: function(chanid, key)
{
if (chanid && key && this.chanmeta.get(chanid) && this.chanmeta.get(chanid).get(key))
return this.chanmeta.get(chanid).get(key);
else
return '';
},
setChanMeta: function(chanid, key, value)
{
if (chanid && key)
{
if (!this.chanmeta.get(chanid)) this.chanmeta.set(chanid, $H());
if (value)
this.chanmeta.get(chanid).set(key,value);
else
this.chanmeta.set(chanid, $H(key));
}
},
doSendMessage: function()
{
var w = this.el_words;
var wval = w.value;
this.cmdhistory.push(wval);
this.cmdhistoryid = this.cmdhistory.length;
this.cmdhistoryissearching = false;
re = new RegExp("^(\/[a-zA-Z0-9]+)( (.*)|)");
if (wval.match(re))
{
cmd = wval.replace(re, '$1');
param = wval.replace(re, '$3');
this.sendRequest(cmd +' '+ param.substr(0, pfc_max_text_len + 2*this.clientid.length));
}
else
{
rx = new RegExp('^[ ]*$','g');
wval = wval.replace(rx,'');
wval = wval.substr(0,pfc_max_text_len);
if (this.current_text_color != '' && wval.length != '')
wval = '[color=#' + this.current_text_color + '] ' + wval + ' [/color]';
this.sendRequest('/send '+ wval);
}
w.value = '';
return false;
},
/**
* Try to complete a nickname like on IRC when pressing the TAB key.
* Nicks with spaces may not work under certain circumstances.
* Replacing spaces with alternate spaces (e.g., &nbsp;) helps.
* Gecko browsers convert the &nbsp; to regular spaces, so no help for these browsers.
* Note: IRC does not allow nicks with spaces, so it's much easier for those clients. :)
* @author Gerard Pinzone
*/
completeNick: function()
{
var w = this.el_words;
var selStart = w.value.length;
var selEnd = selStart;
if (w.setSelectionRange)
{
selStart = w.selectionStart;
selEnd = w.selectionEnd;
}
else if (w.createTextRange && document.selection)
{
selStart = (w.selStart != null) ? w.selStart : w.value.length;
selEnd = (w.selEnd != null) ? w.selEnd : w.value.length;
}
var begin = w.value.lastIndexOf(' ', selStart - 1) + 1;
var end = (w.value.indexOf(' ', selStart) >= 0) ? w.value.indexOf(' ', selStart) : w.value.length;
var nick_src = w.value.substring(begin, end);
var non_nick_begin = w.value.substring(0, begin);
var non_nick_end = w.value.substring(end, w.value.length);
if (nick_src != '')
{
var tabid = this.gui.getTabId();
var n_list = this.getChanMeta(tabid, 'users')['nick'];
var nick_match = false;
for (var i = 0; i < n_list.length; i++)
{
var nick_tmp = n_list[i];
nick_tmp = nick_tmp.replace(/ /g, '\240');
if (nick_tmp.indexOf(nick_src) == 0)
{
if (! nick_match)
{
nick_match = true;
nick_replace = nick_tmp;
}
else
{
var nick_len = Math.min(nick_tmp.length, nick_replace.length);
var j = 0;
for (j = 0; j < nick_len; j++)
if (nick_tmp.charAt(j) != nick_replace.charAt(j))
break;
nick_replace = nick_replace.substr(0, j);
}
}
}
if (nick_match)
{
w.value = non_nick_begin + nick_replace + non_nick_end;
w.selStart = w.selEnd = non_nick_begin.length + nick_replace.length;
if (w.setSelectionRange)
w.setSelectionRange(w.selEnd, w.selEnd);
else
this.setSelection(w);
}
}
},
/**
* Cycle to older entry in history
*/
historyUp: function()
{
if (this.cmdhistory.length > 0)
{
var w = this.el_words;
if (this.cmdhistoryissearching == false && w.value != "")
this.cmdhistory.push(w.value);
this.cmdhistoryissearching = true;
this.cmdhistoryid = this.cmdhistoryid - 1;
if (this.cmdhistoryid < 0)
this.cmdhistoryid = 0;
w.value = this.cmdhistory[this.cmdhistoryid];
}
},
/**
* Cycle to newer entry in history
*/
historyDown: function()
{
if (this.cmdhistory.length > 0)
{
var w = this.el_words;
if (this.cmdhistoryissearching == false && w.value != "")
this.cmdhistory.push(w.value);
this.cmdhistoryissearching = true;
this.cmdhistoryid = this.cmdhistoryid + 1;
if (this.cmdhistoryid >= this.cmdhistory.length)
{
this.cmdhistoryid = this.cmdhistory.length;
w.value = "";
}
else
w.value = this.cmdhistory[this.cmdhistoryid];
}
},
/**
* Handle the pressed keys.
* see also callbackWords_OnKeydown
*/
callbackWords_OnKeypress: function(evt)
{
var code = (evt.which) ? evt.which : evt.keyCode;
if (code == Event.KEY_RETURN) /* ENTER key */
{
return this.doSendMessage();
}
else
{
return true;
}
},
/**
* Handle the pressed keys.
* see also callbackWords_OnKeypress
* WARNING: Suppressing defaults on the keydown event
* may prevent keypress and/or keyup events
* from firing.
*/
callbackWords_OnKeydown: function(evt)
{
if (!this.isconnected) return false;
this.clearError(Array(this.el_words));
var code = (evt.which) ? evt.which : evt.keyCode
if (code == 38 && (is_gecko || is_ie || is_opera || is_webkit))
{
/* TODO: Fix up arrow issue in Opera - may be a bug in Opera. See TAB handler comments below. */
/* Konqueror cannot use this feature due to keycode conflicts. */
this.historyUp();
if (evt.returnValue)
evt.returnValue = false;
if (evt.preventDefault)
evt.preventDefault();
return false;
}
else if (code == 40 && (is_gecko || is_ie || is_opera || is_webkit))
{
/* Konqueror cannot use this feature due to keycode conflicts. */
this.historyDown();
if (evt.returnValue)
evt.returnValue = false;
if (evt.preventDefault)
evt.preventDefault();
return false;
}
else if (code == 9) /* TAB key */
{
this.completeNick();
if (is_opera)
{
evt.target.onblur = function() { this.focus(); this.onblur = null; };
}
if (evt.returnValue)
evt.returnValue = false;
if (evt.preventDefault)
evt.preventDefault();
return false;
}
else
{
return true;
}
},
callbackWords_OnKeyup: function(evt)
{
this.storeSelectionPos(this.el_words);
},
callbackWords_OnMouseup: function(evt)
{
this.storeSelectionPos(this.el_words);
},
callbackWords_OnFocus: function(evt)
{
this.setSelection(this.el_words);
},
callback_OnUnload: function(evt)
{
/* don't disconnect users when they reload the window
* this event doesn't only occurs when the page is closed but also when the page is reloaded */
if (pfc_quit_on_closedwindow)
{
if (!this.isconnected) return false;
this.sendRequest('/quit');
}
},
/**
* hide error area and stop blinking fields
*/
clearError: function(ids)
{
this.el_errors.style.display = 'none';
for (var i=0; i<ids.length; i++)
this.blink(ids[i].id, 'stop');
},
/**
* show error area and assign to it an error message and start the blinking of given fields
*/
setError: function(str, ids)
{
this.el_errors.innerHTML = str;
this.el_errors.style.display = 'block';
for (var i=0; i<ids.length; i++)
this.blink(ids[i].id, 'start');
},
/**
* blink routines used by Error functions
*/
blink: function(id, action)
{
clearTimeout(this.blinktimeout[id]);
if ($(id) == null) return;
if (action == 'start')
{
this.blinktmp[id] = $(id).style.backgroundColor;
clearTimeout(this.blinktimeout[id]);
this.blinktimeout[id] = setTimeout('pfc.blink(\'' + id + '\',\'loop\')', 500);
}
if (action == 'stop')
{
$(id).style.backgroundColor = this.blinktmp[id];
}
if (action == 'loop')
{
if (this.blinkloop[id] == 1)
{
$(id).style.backgroundColor = '#FFDFC0';
this.blinkloop[id] = 2;
}
else
{
$(id).style.backgroundColor = '#FFFFFF';
this.blinkloop[id] = 1;
}
this.blinktimeout[id] = setTimeout('pfc.blink(\'' + id + '\',\'loop\')', 500);
}
},
displayMsg: function( cmd, msg )
{
this.setError(msg, Array());
/*
var tabid = this.gui.getTabId();
var container = this.gui.getChatContentFromTabId(tabid);
div = document.createElement('div');
div.innerHTML = '<div class="pfc_info pfc_info_'+cmd+'" style="margin:5px">'+msg+'</div>';
container.appendChild(div);
this.gui.scrollDown(tabid, div);
*/
},
handleComingRequest: function( cmds )
{
var msg_html = $H();
var max_msgid = $H();
for(var mid = 0; mid < cmds.length ; mid++)
{
var id = cmds[mid][0];
var date = cmds[mid][1];
var time = cmds[mid][2];
var sender = cmds[mid][3];
var recipientid = cmds[mid][4];
var cmd = cmds[mid][5];
var param = cmds[mid][6];
var fromtoday = cmds[mid][7];
var oldmsg = cmds[mid][8];
var line = '';
line += '<div id="pfc_msg_'+recipientid+'_'+id+'" class="pfc_cmd_'+ cmd +' pfc_message';
line += (id % 2 == 0) ? ' pfc_evenmsg' : ' pfc_oddmsg';
if (oldmsg == 1) line += ' pfc_oldmsg';
line += '">';
line += '<span class="pfc_date';
if (fromtoday == 1) line += ' pfc_invisible';
line += '">'+ date +'</span> ';
line += '<span class="pfc_heure">'+ time +'</span> ';
if (cmd == 'send')
{
line += ' <span class="pfc_nick">';
line += '&#x2039;';
line += '<span ';
line += 'onclick="pfc.insert_text(\'' + sender.escapeHTML().replace("'", '\\\'') + ', \',\'\',false)" ';
line += 'class="pfc_nickmarker pfc_nick_'+ _to_utf8(sender).md5() +'">';
line += sender.escapeHTML();
line += '</span>';
line += '&#x203A;';
line += '</span> ';
}
if (cmd == 'notice' || cmd == 'me')
line += '<span class="pfc_words">* '+ this.parseMessage(param) +'</span> ';
else
line += '<span class="pfc_words">'+ this.parseMessage(param) +'</span> ';
line += '</div>';
if (oldmsg == 0)
if (cmd == 'send' || cmd == 'me')
{
var tabid = recipientid;
if (this.gui.getTabId() != tabid)
this.gui.notifyTab(tabid);
if (!this.detectactivity.isActive() && pfc_notify_window)
this.gui.notifyWindow();
}
if (msg_html.get(recipientid) == null)
msg_html.set(recipientid, line);
else
msg_html.set(recipientid, msg_html.get(recipientid) + line);
if (!max_msgid.get(recipientid)) max_msgid.set(recipientid, 0);
if (max_msgid.get(recipientid) < id) max_msgid.set(recipientid, id);
}
var keys = msg_html.keys();
for( var i=0; i<keys.length; i++)
{
var recipientid = keys[i];
var tabid = recipientid;
var recipientdiv = this.gui.getChatContentFromTabId(tabid);
var m = document.createElement('div');
m.innerHTML = msg_html.get(recipientid);
this.colorizeNicks(m);
this.refresh_clock(m);
recipientdiv.appendChild(m);
this.gui.scrollDown(tabid, m);
var limit_msgid = max_msgid.get(recipientid) - pfc_max_displayed_lines;
var elt = $('pfc_msg_'+recipientid+'_'+limit_msgid);
while (elt)
{
if(elt.parentNode)
elt.parentNode.removeChild(elt);
else if(elt.parentElement)
elt.parentElement.removeChild(elt);
else
elt.innerHTML = '';
limit_msgid--;
elt = $('pfc_msg_'+recipientid+'_'+limit_msgid);
}
}
},
calcDelay: function()
{
var lastact = new Date().getTime() - this.last_activity_time;
var dlist = this.refresh_delay_steps.slice();
var delay = dlist.shift();
if (this.refresh_delay > delay) delay = this.refresh_delay;
var limit;
while (typeof (limit = dlist.shift()) != "undefined")
{
var d = dlist.shift();
if (d < delay) continue;
if (lastact > limit) delay = d;
}
return delay;
},
/**
* Call the ajax request function
* Will query the server
*/
sendRequest: function(cmd, recipientid)
{
if (cmd == '/update' && this.pfc_ajax_connected) return;
var delay = this.calcDelay();
if (cmd != "/update")
{
clearTimeout(this.timeout);
this.timeout = setTimeout('pfc.updateChat(true)', delay);
this.timeout_time = new Date().getTime() + delay;
if (pfc_debug)
trace('sendRequest: '+cmd);
}
var rx = new RegExp('(^\/[^ ]+) *(.*)','ig');
if (!recipientid) recipientid = this.gui.getTabId();
cmd = cmd.replace(rx, '$1 '+this.clientid+' '+(recipientid==''?'0':recipientid)+' $2');
var url = pfc_server_script_url;
new Ajax.Request(url, {
method: 'post',
parameters: {'pfc_ajax':1, 'f':'handleRequest', 'cmd': cmd },
onCreate: function(transport) {
this.pfc_ajax_connected = true;
this.last_request_time = new Date().getTime();
}.bind(this),
onSuccess: function(transport) {
if (!transport.status) return;
this.last_response_time = new Date().getTime();
eval( transport.responseText );
}.bind(this),
onComplete: function(transport) {
this.pfc_ajax_connected = false;
this.ping = Math.abs(this.last_response_time - this.last_request_time);
if ($('pfc_ping')) $('pfc_ping').innerHTML = this.ping+'ms'+' ['+parseInt(this.calcDelay() / 1000)+'s]';
}.bind(this)
});
},
/**
* update function to poll the server each 'refresh_delay' time
*/
updateChat: function(start)
{
clearTimeout(this.timeout);
if (start)
{
this.sendRequest('/update');
var delay = this.calcDelay();
this.timeout = setTimeout('pfc.updateChat(true)', delay);
this.timeout_time = new Date().getTime() + delay;
}
},
/**
* Stores the caret/selection position for IE 6.x and 7.x
* Returns true if text range start and end values were updated.
* Code based on: http://www.bazon.net/mishoo/articles.epl?art_id=1292
*/
storeSelectionPos: function(obj)
{
/* WARNING: Do not use this for textareas. They require a more
complex algorithm. */
if (obj.setSelectionRange)
{
obj.selStart = obj.selectionStart;
obj.selEnd = obj.selectionEnd;
return true;
}
else if (obj.createTextRange && document.selection)
{
var range = document.selection.createRange();
var isCollapsed = range.compareEndPoints("StartToEnd", range) == 0;
if (!isCollapsed)
range.collapse(true);
var b = range.getBookmark();
obj.selStart = b.charCodeAt(2) - b.charCodeAt(0) - 1;
range = document.selection.createRange();
isCollapsed = range.compareEndPoints("StartToEnd", range) == 0;
if (!isCollapsed)
range.collapse(false);
b = range.getBookmark();
obj.selEnd = b.charCodeAt(2) - b.charCodeAt(0) - 1;
return true;
}
else
return false;
},
/**
* Sets the selection/caret in the object based on the
* object's selStart and selEnd parameters.
* This should only be needed for IE only.
*/
setSelection: function(obj)
{
/* WARNING: Do not attempt to use this function as
a wrapper for the Gekco based setSelectionRange.
It causes problems in Opera when executed from
the event trigger onFocus. */
if (obj.setSelectionRange)
{
return null;
}
else if (obj.createTextRange)
{
var range = obj.createTextRange();
range.collapse(true);
range.moveStart("character", obj.selStart);
range.moveEnd("character", obj.selEnd - obj.selStart);
range.select();
return range;
}
else
return null;
},
/**
* insert a smiley
*/
insertSmiley: function(smiley)
{
var w = this.el_words;
if (w.setSelectionRange)
{
var s = w.selectionStart;
var e = w.selectionEnd;
w.value = w.value.substring(0, s) + smiley + w.value.substr(e);
w.setSelectionRange(s + smiley.length, s + smiley.length);
w.focus();
}
else if (w.createTextRange)
{
w.focus();
var range = this.setSelection(w);
range.text = smiley;
w.selStart = (w.selStart) ? w.selStart + smiley.length : smiley.length;
w.selEnd = w.selStart;
}
else
{
w.value += smiley;
w.focus();
}
},
updateNickBox: function(nickid)
{
var chanids = this.chanmeta.keys();
for(var i = 0; chanids.length > i; i++)
{
this.updateNickListBox(chanids[i]);
}
},
/**
* fill the nickname list with connected nicknames
*/
updateNickListBox: function(chanid)
{
var className = (! is_ie) ? 'class' : 'className';
var nickidlst = this.getChanMeta(chanid,'users').get('nickid');
var nickdiv = this.gui.getOnlineContentFromTabId(chanid);
var ul = document.createElement('ul');
ul.setAttribute(className, 'pfc_nicklist');
for (var i=0; i<nickidlst.length; i++)
{
var nickid = nickidlst[i];
var li = this.buildNickItem(nickid);
li.setAttribute(className, 'pfc_nickitem_'+nickid);
ul.appendChild(li);
}
var fc = nickdiv.firstChild;
if (fc)
nickdiv.replaceChild(ul,fc);
else
nickdiv.appendChild(ul,fc);
this.colorizeNicks(nickdiv);
},
getNickWhoisBox: function(nickid)
{
if (!this.nickwhoisbox.get(nickid))
this.updateNickWhoisBox(nickid);
return this.nickwhoisbox.get(nickid);
},
updateNickWhoisBox: function(nickid)
{
var className = (! is_ie) ? 'class' : 'className';
var usermeta = this.getAllUserMeta(nickid);
var div = document.createElement('div');
div.setAttribute(className, 'pfc_nickwhois');
var p = document.createElement('p');
p.setAttribute(className, 'pfc_nickwhois_header');
div.appendChild(p);
var img = document.createElement('img');
img.setAttribute(className, 'pfc_nickwhois_close');
img.pfc_parent = div;
img.onclick = function(evt){
this.pfc_parent.style.display = 'none';
return false;
}
img.setAttribute('src', this.res.getFileUrl('images/close-whoisbox.gif'));
img.alt = this.res.getLabel('Close');
p.appendChild(img);
p.appendChild(document.createTextNode(usermeta.get('nick')));
var table = document.createElement('table');
var tbody = document.createElement('tbody');
table.appendChild(tbody);
var um_keys = usermeta.keys();
var msg = '';
for (var i=0; i<um_keys.length; i++)
{
var k = um_keys[i];
var v = usermeta.get(k);
if (v && k != 'nickid'
&& k != 'nick'
&& k != 'isadmin'
&& k != 'floodtime'
&& k != 'flood_nbmsg'
&& k != 'flood_nbchar'
)
{
var tr = document.createElement('tr');
if (pfc_nickmeta_key_to_hide.indexOf(k) != -1)
{
var td2 = document.createElement('td');
td2.setAttribute(className, 'pfc_nickwhois_c2');
td2.setAttribute('colspan', 2);
td2.innerHTML = v;
tr.appendChild(td2);
}
else
{
var td1 = document.createElement('td');
td1.setAttribute(className, 'pfc_nickwhois_c1');
var td2 = document.createElement('td');
td2.setAttribute(className, 'pfc_nickwhois_c2');
td1.innerHTML = k;
td2.innerHTML = v;
tr.appendChild(td1);
tr.appendChild(td2);
}
tbody.appendChild(tr);
}
}
div.appendChild(table);
if (pfc.getUserMeta(nickid,'nick') != this.nickname)
{
var p = document.createElement('p');
p.setAttribute(className, 'pfc_nickwhois_pv');
var a = document.createElement('a');
a.setAttribute('href', '');
a.pfc_nickid = nickid;
a.pfc_parent = div;
a.onclick = function(evt){
var nick = pfc.getUserMeta(this.pfc_nickid,'nick');
pfc.sendRequest('/privmsg "'+nick+'"');
this.pfc_parent.style.display = 'none';
return false;
}
var img = document.createElement('img');
img.setAttribute('src', this.res.getFileUrl('images/openpv.gif'));
img.alt = document.createTextNode(this.res.getLabel('Private message'));
a.appendChild(img);
a.appendChild(document.createTextNode(this.res.getLabel('Private message')));
p.appendChild(a);
div.appendChild(p);
}
this.nickwhoisbox.set(nickid, div);
},
buildNickItem: function(nickid)
{
var className = (! is_ie) ? 'class' : 'className';
var nick = this.getUserMeta(nickid, 'nick');
var isadmin = this.getUserMeta(nickid, 'isadmin');
if (isadmin == '') isadmin = false;
var li = document.createElement('li');
var a = document.createElement('a');
a.setAttribute('href','#');
a.pfc_nick = nick;
a.pfc_nickid = nickid;
a.onclick = function(evt){
var d = pfc.getNickWhoisBox(this.pfc_nickid);
document.body.appendChild(d);
d.style.display = 'block';
d.style.zIndex = '400';
d.style.position = 'absolute';
d.style.left = (mousePosX(evt)-7)+'px';
d.style.top = (mousePosY(evt)-7)+'px';
return false;
}
li.appendChild(a);
var img = document.createElement('img');
if (isadmin)
img.setAttribute('src', this.res.getFileUrl('images/user-admin.gif'));
else
img.setAttribute('src', this.res.getFileUrl('images/user.gif'));
img.style.marginRight = '5px';
img.setAttribute(className, 'pfc_nickbutton');
a.appendChild(img);
var nobr = document.createElement('nobr');
var span = document.createElement('span');
span.setAttribute(className, 'pfc_nickmarker pfc_nick_'+nickid);
span.innerHTML = nick.escapeHTML();
nobr.appendChild(span);
a.appendChild(nobr);
return li;
},
/**
* clear the nickname list
*/
clearNickList: function()
{
/*
var nickdiv = this.el_online;
var fc = nickdiv.firstChild;
if (fc) nickdiv.removeChild(fc);
*/
},
/**
* clear the message list history
*/
clearMessages: function()
{
},
/**
* parse the message
*/
parseMessage: function(msg)
{
var rx = null;
/*
var rx_url = new RegExp('(^|[^\\"])([a-z]+\:\/\/[a-z0-9.\\~\\/\\?\\=\\&\\-\\_\\#:;%,@]*[a-z0-9\\/\\?\\=\\&\\-\\_\\#])([^\\"]|$)','ig');
var ttt = msg.split(rx_url);
if (ttt.length > 1 &&
!navigator.appName.match("Explorer|Konqueror") &&
!navigator.appVersion.match("KHTML"))
{
msg = '';
for( var i = 0; i<ttt.length; i++)
{
var offset = (ttt[i].length - 7) / 2;
var delta = (ttt[i].length - 7 - 60);
var range1 = 7+offset-delta;
var range2 = 7+offset+delta;
if (ttt[i].match(rx_url))
{
msg = msg + '<a href="' + ttt[i] + '"';
if (pfc_openlinknewwindow)
msg = msg + ' onclick="window.open(this.href,\'_blank\');return false;"';
msg = msg + '>' + (delta>0 ? ttt[i].substring(7,range1)+ ' ... ' + ttt[i].substring(range2,ttt[i].length) : ttt[i]) + '</a>';
}
else
{
msg = msg + ttt[i];
}
}
}
else
{
replace = '$1<a href="$2"';
if (pfc_openlinknewwindow)
replace = replace + ' onclick="window.open(this.href,\'_blank\');return false;"';
replace = replace + '>$2</a>$3';
msg = msg.replace(rx_url, replace);
}
*/
if ( false )
{
rx = new RegExp('<a href="mailto:(.*?)".*?>.*?<\/a>','ig');
msg = msg.replace(rx, '$1');
rx = new RegExp('<a href="(.*?)".*?>.*?<\/a>','ig');
msg = msg.replace(rx, '$1');
}
rx = new RegExp(' (?= )(?![^<]*>)','g');
msg = msg.replace(rx, '&nbsp;');
rx = new RegExp('\\[b\\](.+?)\\[\/b\\]','ig');
msg = msg.replace(rx, '<span style="font-weight: bold">$1</span>');
rx = new RegExp('\\[i\\](.+?)\\[\/i\\]','ig');
msg = msg.replace(rx, '<span style="font-style: italic">$1</span>');
rx = new RegExp('\\[u\\](.+?)\\[\/u\\]','ig');
msg = msg.replace(rx, '<span style="text-decoration: underline">$1</span>');
rx = new RegExp('\\[s\\](.+?)\\[\/s\\]','ig');
msg = msg.replace(rx, '<span style="text-decoration: line-through">$1</span>');
/*
rx = new RegExp('\\[email\\]([A-z0-9][\\w.-]*@[A-z0-9][\\w\\-\\.]+\\.[A-z0-9]{2,6})\\[\/email\\]','ig');
msg = msg.replace(rx, '<a href="mailto: $1">$1</a>');
rx = new RegExp('\\[email=([A-z0-9][\\w.-]*@[A-z0-9][\\w\\-\\.]+\\.[A-z0-9]{2,6})\\](.+?)\\[\/email\\]','ig');
msg = msg.replace(rx, '<a href="mailto: $1">$2</a>');
*/
rx = new RegExp('\\[color=([a-zA-Z]+|\\#?[0-9a-fA-F]{6}|\\#?[0-9a-fA-F]{3})](.+?)\\[\/color\\]','ig');
msg = msg.replace(rx, '<span style="color: $1">$2</span>');
rx = new RegExp('\\[color=([a-zA-Z]+|\\#?[0-9a-fA-F]{6}|\\#?[0-9a-fA-F]{3})](.+?)\\[\/color\\]','ig');
msg = msg.replace(rx, '<span style="color: $1">$2</span>');
var smileys = this.res.getSmileyHash();
var sl = this.res.getSmileyKeys();
for(var i = 0; i < sl.length; i++)
{
rx = new RegExp(RegExp.escape(sl[i]) + '(?![^<]*>)','g');
msg = msg.replace(rx, '<img src="'+ smileys.get(sl[i]) +'" alt="' + sl[i] + '" title="' + sl[i] + '" />');
}
rx = new RegExp('(^|[ :,;])'+RegExp.escape(this.nickname)+'([ :,;]|$)','gi');
msg = msg.replace(rx, '$1<strong>'+ this.nickname +'</strong>$2');
/*
rx = new RegExp('([^ \\:\\<\\>\\/\\&\\;]{60})','ig');
var ttt = msg.split(rx);
if (ttt.length > 1 &&
!navigator.appName.match("Explorer|Konqueror") &&
!navigator.appVersion.match("KHTML"))
{
msg = '';
for( var i = 0; i<ttt.length; i++)
{
msg = msg + ttt[i] + ' ';
}
}
*/
return msg;
},
/**
* apply nicknames color to the root childs
*/
colorizeNicks: function(root)
{
if (this.nickmarker)
{
var nicklist = this.getElementsByClassName(root, 'pfc_nickmarker', '');
for(var i = 0; i < nicklist.length; i++)
{
var cur_nick = nicklist[i].innerHTML;
var cur_color = this.getAndAssignNickColor(cur_nick);
nicklist[i].style.color = cur_color;
}
}
},
/**
* Initialize the color array used to colirize the nicknames
*/
reloadColorList: function()
{
this.colorlist = $A(pfc_nickname_color_list);
},
/**
* get the corresponding nickname color
*/
getAndAssignNickColor: function(nick)
{
/* check the nickname is colorized or not */
var already_colorized = false;
var nc = '';
for(var j = 0; j < this.nickcolor.length && !already_colorized; j++)
{
if (this.nickcolor[j][0] == nick)
{
already_colorized = true;
nc = this.nickcolor[j][1];
}
}
if (!already_colorized)
{
/* reload the color stack if it's empty */
if (this.colorlist.length == 0) this.reloadColorList();
/* take the next color from the list and colorize this nickname */
var cid = Math.round(Math.random()*(this.colorlist.length-1));
nc = this.colorlist[cid];
this.colorlist.splice(cid,1);
this.nickcolor.push(new Array(nick, nc));
}
return nc;
},
/**
* Colorize with 'color' all the nicknames found as a 'root' child
*/
applyNickColor: function(root, nick, color)
{
var nicktochange = this.getElementsByClassName(root, 'pfc_nick_'+ _to_utf8(nick).md5(), '');
for(var i = 0; nicktochange.length > i; i++)
nicktochange[i].style.color = color;
},
/**
* Returns a list of elements which have a clsName class
*/
getElementsByClassName: function( root, clsName, clsIgnore )
{
var i, matches = new Array();
var els = root.getElementsByTagName('*');
var rx1 = new RegExp('.*'+clsName+'.*');
var rx2 = new RegExp('.*'+clsIgnore+'.*');
for(i=0; i<els.length; i++) {
if(els.item(i).className.match(rx1) &&
(clsIgnore == '' || !els.item(i).className.match(rx2)) )
{
matches.push(els.item(i));
}
}
return matches;
},
showClass: function(root, clsName, clsIgnore, show)
{
var elts = this.getElementsByClassName(root, clsName, clsIgnore);
for(var i = 0; elts.length > i; i++)
if (show)
elts[i].style.display = 'inline';
else
elts[i].style.display = 'none';
},
/**
* Nickname marker show/hide
*/
nickmarker_swap: function()
{
if (this.nickmarker) {
this.nickmarker = false;
} else {
this.nickmarker = true;
}
this.refresh_nickmarker()
setCookie('pfc_nickmarker', this.nickmarker);
},
refresh_nickmarker: function(root)
{
var nickmarker_icon = $('pfc_nickmarker');
if (!root) root = $('pfc_channels_content');
if (this.nickmarker)
{
nickmarker_icon.src = this.res.getFileUrl('images/color-on.gif');
nickmarker_icon.alt = this.res.getLabel("Hide nickname marker");
nickmarker_icon.title = nickmarker_icon.alt;
this.colorizeNicks(root);
}
else
{
nickmarker_icon.src = this.res.getFileUrl('images/color-off.gif');
nickmarker_icon.alt = this.res.getLabel("Show nickname marker");
nickmarker_icon.title = nickmarker_icon.alt;
var elts = this.getElementsByClassName(root, 'pfc_nickmarker', '');
for(var i = 0; elts.length > i; i++)
{
elts[i].style.color = '';
}
}
},
/**
* Date/Hour show/hide
*/
clock_swap: function()
{
if (this.clock) {
this.clock = false;
} else {
this.clock = true;
}
this.refresh_clock();
setCookie('pfc_clock', this.clock);
},
refresh_clock: function( root )
{
var clock_icon = $('pfc_clock');
if (!root) root = $('pfc_channels_content');
if (this.clock)
{
clock_icon.src = this.res.getFileUrl('images/clock-on.gif');
clock_icon.alt = this.res.getLabel('Hide dates and hours');
clock_icon.title = clock_icon.alt;
this.showClass(root, 'pfc_date', 'pfc_invisible', true);
this.showClass(root, 'pfc_heure', 'pfc_invisible', true);
}
else
{
clock_icon.src = this.res.getFileUrl('images/clock-off.gif');
clock_icon.alt = this.res.getLabel('Show dates and hours');
clock_icon.title = clock_icon.alt;
this.showClass(root, 'pfc_date', 'pfc_invisible', false);
this.showClass(root, 'pfc_heure', 'pfc_invisible', false);
}
},
/**
* Sound button
*/
sound_swap: function()
{
if (this.issoundenable) {
this.issoundenable = false;
} else {
this.issoundenable = true;
}
this.refresh_sound();
setCookie('pfc_issoundenable', this.issoundenable);
},
refresh_sound: function( root )
{
var snd_icon = $('pfc_sound');
if (this.issoundenable)
{
snd_icon.src = this.res.getFileUrl('images/sound-on.gif');
snd_icon.alt = this.res.getLabel('Disable sound notifications');
snd_icon.title = snd_icon.alt;
}
else
{
snd_icon.src = this.res.getFileUrl('images/sound-off.gif');
snd_icon.alt = this.res.getLabel('Enable sound notifications');
snd_icon.title = snd_icon.alt;
}
},
/**
* Connect/disconnect button
*/
connect_disconnect: function()
{
if (this.isconnected)
this.sendRequest('/quit');
else
{
if (this.nickname == '')
this.askNick();
else
this.sendRequest('/connect "'+this.nickname+'"');
}
},
refresh_loginlogout: function()
{
var loginlogout_icon = $('pfc_loginlogout');
if (this.isconnected)
{
loginlogout_icon.src = this.res.getFileUrl('images/logout.gif');
loginlogout_icon.alt = this.res.getLabel('Disconnect');
loginlogout_icon.title = loginlogout_icon.alt;
}
else
{
this.clearMessages();
this.clearNickList();
loginlogout_icon.src = this.res.getFileUrl('images/login.gif');
loginlogout_icon.alt = this.res.getLabel('Connect');
loginlogout_icon.title = loginlogout_icon.alt;
}
},
/**
* Minimize/Maximized the chat zone
*/
swap_minimize_maximize: function()
{
if (this.minmax_status) {
this.minmax_status = false;
} else {
this.minmax_status = true;
}
setCookie('pfc_minmax_status', this.minmax_status);
this.refresh_minimize_maximize();
},
refresh_minimize_maximize: function()
{
var content = $('pfc_content_expandable');
var btn = $('pfc_minmax');
if (this.minmax_status)
{
btn.src = this.res.getFileUrl('images/maximize.gif');
btn.alt = this.res.getLabel('Magnify');
btn.title = btn.alt;
content.style.display = 'none';
}
else
{
btn.src = this.res.getFileUrl('images/minimize.gif');
btn.alt = this.res.getLabel('Cut down');
btn.title = btn.alt;
content.style.display = 'block';
}
},
/**
* BBcode ToolBar
*/
insert_text: function(open, close, promptifselempty)
{
var msgfield = $('pfc_words');
var pfcp = this.getPrompt();
pfcp.msgfield = msgfield;
pfcp.open = open;
pfcp.close = close;
pfcp.promptifselempty = promptifselempty;
pfcp.callback = this.insert_text_callback;
/* Always check for Gecko selection processing commands
first. This is needed for Opera. */
if (msgfield.selectionStart || msgfield.selectionStart == '0')
{
var startPos = msgfield.selectionStart;
var endPos = msgfield.selectionEnd;
var text = msgfield.value.substring(startPos, endPos);
if (startPos == endPos && promptifselempty)
{
pfcp.prompt(this.res.getLabel('Enter the text to format'), '');
pfcp.focus();
}
else
this.insert_text_callback(text, pfcp);
}
else if (document.selection && document.selection.createRange)
{
msgfield.focus();
pfcp.range = this.setSelection(msgfield);
var text = pfcp.range.text;
if (text == "" && promptifselempty)
{
pfcp.prompt(this.res.getLabel('Enter the text to format'), '');
pfcp.focus();
}
else
this.insert_text_callback(text, pfcp);
}
else
{
pfcp.prompt(this.res.getLabel('Enter the text to format'), '');
pfcp.focus();
}
return;
},
insert_text_callback: function(text, pfcp)
{
var open = pfcp.open;
var close = pfcp.close;
var promptifselempty = pfcp.promptifselempty;
var msgfield = pfcp.msgfield;
var range = pfcp.range;
/* Always check for Gecko selection processing commands
first. This is needed for Opera. */
if (msgfield.selectionStart || msgfield.selectionStart == '0')
{
var startPos = msgfield.selectionStart;
var endPos = msgfield.selectionEnd;
var extralength = 0;
if (startPos == endPos && promptifselempty)
{
if (text == null) text = "";
extralength = text.length;
}
if (text.length > 0 || !promptifselempty)
{
msgfield.value = msgfield.value.substring(0, startPos) + open + text + close + msgfield.value.substring(endPos, msgfield.value.length);
var caretPos = endPos + open.length + extralength + close.length;
msgfield.setSelectionRange(caretPos, caretPos);
msgfield.focus();
}
}
else if (document.selection && document.selection.createRange)
{
if (text == null) text = "";
if (text.length > 0 || !promptifselempty)
{
msgfield.focus();
range.text = open + text + close;
msgfield.selStart = (msgfield.selStart) ? msgfield.selStart + open.length + text.length + close.length : open.length + text.length + close.length;
msgfield.selEnd = msgfield.selStart;
msgfield.focus();
}
}
else
{
if (text == null) text = "";
if (text.length > 0 || !promptifselempty)
{
msgfield.value += open + text + close;
msgfield.focus();
}
}
},
/**
* Minimize/Maximize none/inline
*/
minimize_maximize: function(idname, type)
{
var element = $(idname);
if(element.style)
{
if(element.style.display == type )
{
element.style.display = 'none';
}
else
{
element.style.display = type;
}
}
},
switch_text_color: function(color)
{
/* clear any existing borders on the color buttons */
var colorbtn = this.getElementsByClassName($('pfc_colorlist'), 'pfc_color', '');
for(var i = 0; colorbtn.length > i; i++)
{
colorbtn[i].style.border = 'none';
colorbtn[i].style.padding = '0';
}
/* assign the new border style to the selected button */
this.current_text_color = color;
setCookie('pfc_current_text_color', this.current_text_color);
var idname = 'pfc_color_' + color;
$(idname).style.border = '1px solid #555';
$(idname).style.padding = '1px';
this.el_words.style.color = '#'+color;
this.el_words.focus();
},
/**
* Smiley show/hide
*/
showHideSmileys: function()
{
if (this.showsmileys)
{
this.showsmileys = false;
}
else
{
this.showsmileys = true;
}
setCookie('pfc_showsmileys', this.showsmileys);
this.refresh_Smileys();
},
refresh_Smileys: function()
{
var content = $('pfc_smileys');
if (this.showsmileys)
content.style.display = 'block';
else
content.style.display = 'none';
var btn = $('pfc_showHideSmileysbtn');
if (this.showsmileys)
{
if (btn)
{
btn.src = this.res.getFileUrl('images/smiley-on.gif');
btn.alt = this.res.getLabel('Hide smiley box');
btn.title = btn.alt;
}
}
else
{
if (btn)
{
btn.src = this.res.getFileUrl('images/smiley-off.gif');
btn.alt = this.res.getLabel('Show smiley box');
btn.title = btn.alt;
}
}
},
/**
* Show Hide who's online
*/
showHideWhosOnline: function()
{
if (this.showwhosonline)
{
this.showwhosonline = false;
}
else
{
this.showwhosonline = true;
}
setCookie('pfc_showwhosonline', this.showwhosonline);
this.refresh_WhosOnline();
},
refresh_WhosOnline: function()
{
var root = $('pfc_channels_content');
var contentlist = this.getElementsByClassName(root, 'pfc_online', '');
for(var i = 0; i < contentlist.length; i++)
{
var content = contentlist[i];
if (this.showwhosonline)
content.style.display = 'block';
else
content.style.display = 'none';
content.style.zIndex = '100';
}
var btn = $('pfc_showHideWhosOnlineBtn');
if (!btn) return;
if (this.showwhosonline)
{
btn.src = this.res.getFileUrl('images/online-on.gif');
btn.alt = this.res.getLabel('Hide online users box');
btn.title = btn.alt;
}
else
{
btn.src = this.res.getFileUrl('images/online-off.gif');
btn.alt = this.res.getLabel('Show online users box');
btn.title = btn.alt;
}
this.refresh_Chat();
},
/**
* Resize chat
*/
refresh_Chat: function()
{
var root = $('pfc_channels_content');
var contentlist = this.getElementsByClassName(root, 'pfc_chat', '');
for(var i = 0; i < contentlist.length; i++)
{
var chatdiv = contentlist[i];
if (!this.showwhosonline)
{
chatdiv.style.width = '100%';
}
else
{
chatdiv.style.width = '';
}
}
},
getPrompt: function()
{
if (!this.pfc)
this.pfc = new pfcPrompt($('pfc_container'));
return this.pfc;
}
};
/**
* This class centralize the pfc' Graphic User Interface manipulations
* (depends on prototype library)
* @author Stephane Gully
*/
var pfcGui = Class.create();
pfcGui.prototype = {
initialize: function()
{
this.current_tab = '';
this.current_tab_id = '';
this.tabs = Array();
this.tabids = Array();
this.tabtypes = Array();
this.chatcontent = $H();
this.onlinecontent = $H();
this.scrollpos = $H();
this.elttoscroll = $H();
this.windownotifynb = 0;
},
/**
* Scroll down the message list area by elttoscroll height
* - elttoscroll is a message DOM element which has been appended to the tabid's message list
* - this.elttoscroll is an array containing the list of messages that will be scrolled
* when the corresponding tab will be shown (see setTabById bellow).
* It is necessary to keep in cache the list of hidden (because the tab is inactive) messages
* because the 'scrollTop' javascript attribute
* will not work if the element (tab content) is hidden.
*/
scrollDown: function(tabid, elttoscroll)
{
if (this.getTabId() != tabid)
{
if (!this.elttoscroll.get(tabid)) this.elttoscroll.set(tabid, Array());
this.elttoscroll.get(tabid).push(elttoscroll);
return;
}
var content = this.getChatContentFromTabId(tabid);
var dudVar = content.scrollTop;
content.scrollTop += elttoscroll.offsetHeight+2;
this.scrollpos.set(tabid, content.scrollTop);
},
isCreated: function(tabid)
{
/*
for (var i = 0; i < this.tabids.length ; i++)
{
if (this.tabids[i] == tabid) return true;
}
return false;
*/
return (indexOf(this.tabids, tabid) >= 0);
},
setTabById: function(tabid)
{
var className = (! is_ie) ? 'class' : 'className';
var content = this.getChatContentFromTabId(this.current_tab_id);
this.scrollpos.set(this.current_tab_id, content.scrollTop);
this.current_tab = '';
this.current_tab_id = '';
var tab_to_show = null;
for (var i=0; i<this.tabids.length; i++)
{
var tabtitle = $('pfc_channel_title'+this.tabids[i]);
var tabcontent = $('pfc_channel_content'+this.tabids[i]);
if (this.tabids[i] == tabid)
{
tabtitle.setAttribute(className, 'selected');
tab_to_show = tabcontent;
this.current_tab = this.tabs[i];
this.current_tab_id = tabid;
}
else
{
tabtitle.setAttribute(className, '');
tabcontent.style.display = 'none';
}
}
tab_to_show.style.display = 'block';
var content = this.getChatContentFromTabId(tabid);
content.scrollTop = this.scrollpos.get(tabid);
if (this.elttoscroll.get(tabid) &&
this.elttoscroll.get(tabid).length > 0)
{
for (var i=0; i<this.elttoscroll.get(tabid).length; i++)
this.scrollDown(tabid,this.elttoscroll.get(tabid)[i]);
this.elttoscroll.set(tabid, Array());
}
this.unnotifyTab(tabid);
},
getTabId: function()
{
return this.current_tab_id;
},
getChatContentFromTabId: function(tabid)
{
var className = (! is_ie) ? 'class' : 'className';
var cc = this.chatcontent.get(tabid);
if (cc) return cc;
cc = document.createElement('div');
cc.setAttribute('id', 'pfc_chat_'+tabid);
cc.setAttribute(className, 'pfc_chat');
cc.style.display = "block";
this.chatcontent.set(tabid,cc);
return cc;
},
getOnlineContentFromTabId: function(tabid)
{
var className = (! is_ie) ? 'class' : 'className';
var oc = this.onlinecontent.get(tabid);
if (oc) return oc;
oc = document.createElement('div');
oc.setAttribute('id', 'pfc_online_'+tabid);
oc.setAttribute(className, 'pfc_online');
oc.style.display = "block";
this.onlinecontent.set(tabid,oc);
return oc;
},
removeTabById: function(tabid)
{
var tabparent_t = $('pfc_channels_list');
var tabparent_c = $('pfc_channels_content');
var tab_t = $('pfc_channel_title'+tabid);
var tab_c = $('pfc_channel_content'+tabid);
tabparent_t.removeChild(tab_t);
tabparent_c.removeChild(tab_c);
var div_chat = this.getChatContentFromTabId(tabid);
div_chat.innerHTML = '';
var tabpos = indexOf(this.tabids, tabid);
var name = this.tabs[tabpos];
this.tabids = without(this.tabids, this.tabids[tabpos]);
this.tabs = without(this.tabs, this.tabs[tabpos]);
this.tabtypes = without(this.tabtypes, this.tabtypes[tabpos]);
tabpos = indexOf(this.tabids, this.getTabId());
if (tabpos<0) tabpos = 0;
if (this.tabids[tabpos])
this.setTabById(this.tabids[tabpos]);
return name;
},
/*
removeTabByName: function(name)
{
var tabid = _to_utf8(name).md5();
var ret = this.removeTabById(tabid);
if (ret == name)
return tabid;
else
return 0;
},
*/
createTab: function(name, tabid, type)
{
var className = (! is_ie) ? 'class' : 'className';
if(name == '') return;
if(tabid == '') return;
if (this.isCreated(tabid)) return;
this.tabs.push(name);
this.tabids.push(tabid);
this.tabtypes.push(type);
var li_title = document.createElement('li');
li_title.setAttribute('id', 'pfc_channel_title'+tabid);
var li_div = document.createElement('div');
li_div.setAttribute('id', 'pfc_tabdiv'+tabid);
li_title.appendChild(li_div);
var a1 = document.createElement('a');
a1.setAttribute(className, 'pfc_tabtitle');
a1.setAttribute('href', '#');
a1.pfc_tabid = tabid;
a1.onclick = function(){pfc.gui.setTabById(this.pfc_tabid); return false;}
li_div.appendChild(a1);
if (pfc_displaytabimage)
{
var img = document.createElement('img');
img.setAttribute('id', 'pfc_tabimg'+tabid);
if (type == 'ch')
img.setAttribute('src', pfc.res.getFileUrl('images/ch.gif'));
if (type == 'pv')
img.setAttribute('src', pfc.res.getFileUrl('images/pv.gif'));
a1.appendChild(img);
}
a1.appendChild(document.createTextNode(name));
if (pfc_displaytabclosebutton || type == 'pv')
{
var a2 = document.createElement('a');
a2.pfc_tabid = tabid;
a2.pfc_tabname = name;
a2.pfc_tabtype = type;
a2.onclick = function(){
var msg = (type == 'pv' ? 'Are you sure you want to close this tab ?' :
'Do you really want to leave this room ?');
var res = confirm(pfc.res.getLabel(msg));
if (res == true)
pfc.sendRequest('/leave',this.pfc_tabid);
return false;
}
a2.alt = pfc.res.getLabel('Close this tab');
a2.title = a2.alt;
a2.setAttribute(className, 'pfc_tabclose');
var img = document.createElement('img');
img.setAttribute('src', pfc.res.getFileUrl('images/tab_remove.gif'));
a2.appendChild(img);
li_div.appendChild(a2);
}
var div_content = document.createElement('div');
div_content.setAttribute('id', 'pfc_channel_content'+tabid);
div_content.setAttribute(className, 'pfc_content');
div_content.style.display = 'none';
var div_chat = this.getChatContentFromTabId(tabid);
var div_online = this.getOnlineContentFromTabId(tabid);
div_content.appendChild(div_chat);
div_content.appendChild(div_online);
$('pfc_channels_list').appendChild(li_title);
$('pfc_channels_content').appendChild(div_content);
div_chat.style.height = ($('pfc_channels_content').offsetHeight-1)+'px';
div_online.style.height = ($('pfc_channels_content').offsetHeight-1)+'px';
return tabid;
},
/**
* This function change the window title in order to catch the attention
*/
notifyWindow: function()
{
this.windownotifynb += 1;
var rx = new RegExp('^\\[[0-9]+\\](.*)','ig');
document.title = document.title.replace(rx,'$1');
document.title = '['+this.windownotifynb+']'+document.title;
var soundcontainer = document.getElementById('pfc_sound_container');
if (pfc.issoundenable)
{
var flash = '<object style="visibility:hidden" classid="clsid:D27CDB6E-AE6D-11CF-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" width="0" height="0">';
flash += '<param name="movie" value="' + pfc.res.getFileUrl('sound.swf') + '">';
flash += '<param name="quality" value="High">';
flash += '<embed style="visibility:hidden" src="' + pfc.res.getFileUrl('sound.swf') + '" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" width="0" height="0" />';
flash += '</object>';
soundcontainer.innerHTML = flash;
}
},
unnotifyWindow: function()
{
this.windownotifynb = 0;
var rx = new RegExp('^\\[[0-9]+\\](.*)','ig');
document.title = document.title.replace(rx,'$1');
var soundcontainer = document.getElementById('pfc_sound_container');
if (pfc.issoundenable)
soundcontainer.innerHTML = '';
},
/**
* This function change the tab icon in order to catch the attention
*/
notifyTab: function(tabid)
{
var className = (! is_ie) ? 'class' : 'className';
this.unnotifyTab(tabid);
var tabpos = indexOf(this.tabids, tabid);
var tabtype = this.tabtypes[tabpos];
var img = $('pfc_tabimg'+tabid);
if (img)
{
if (tabtype == 'ch')
img.src = pfc.res.getFileUrl('images/ch-active.gif');
if (tabtype == 'pv')
img.src = pfc.res.getFileUrl('images/pv-active.gif');
}
var div = $('pfc_tabdiv'+tabid);
if (div)
{
if (div.blinkstat == true)
{
div.setAttribute(className, 'pfc_tabblink1');
}
else
{
div.setAttribute(className, 'pfc_tabblink2');
}
div.blinkstat = !div.blinkstat;
div.blinktimeout = setTimeout('pfc.gui.notifyTab(\''+tabid+'\');', 500);
}
},
/**
* This function restore the tab icon to its default value
*/
unnotifyTab: function(tabid)
{
var className = (! is_ie) ? 'class' : 'className';
var tabpos = indexOf(this.tabids, tabid);
var tabtype = this.tabtypes[tabpos];
var img = $('pfc_tabimg'+tabid);
if (img)
{
if (tabtype == 'ch')
img.src = pfc.res.getFileUrl('images/ch.gif');
if (tabtype == 'pv')
img.src = pfc.res.getFileUrl('images/pv.gif');
}
var div = $('pfc_tabdiv'+tabid);
if (div)
{
div.removeAttribute(className);
clearTimeout(div.blinktimeout);
}
},
loadSmileyBox: function()
{
var container = $('pfc_smileys');
var smileys = pfc.res.getSmileyReverseHash();//getSmileyHash();
var sl = smileys.keys();
pfc.res.sortSmileyKeys();
for(var i = 0; i < sl.length; i++)
{
s_url = sl[i];
s_symbol = smileys.get(sl[i]);
s_symbol = s_symbol.unescapeHTML();
if (is_ie || is_webkit)
s_symbol = s_symbol.replace(/&quot;/g,'"');
var img = document.createElement('img');
img.setAttribute('src', s_url);
img.setAttribute('alt', s_symbol);
img.setAttribute('title', s_symbol);
img.s_symbol = s_symbol;
img.onclick = function(){ pfc.insertSmiley(this.s_symbol); }
container.appendChild(img);
container.appendChild(document.createTextNode(' '));
}
},
loadBBCodeColorList: function()
{
var className = (! is_ie) ? 'class' : 'className';
var clist = $('pfc_colorlist');
var clist_v = pfc_bbcode_color_list;
for (var i=0 ; i<clist_v.length ; i++)
{
var bbc = clist_v[i];
var elt = document.createElement('img');
elt.bbc = bbc;
elt.setAttribute(className, 'pfc_color');
elt.setAttribute('id', 'pfc_color_'+bbc);
elt.style.backgroundColor = '#'+bbc;
elt.setAttribute('src', pfc.res.getFileUrl('images/color_transparent.gif'));
elt.setAttribute('alt', bbc);
elt.onclick = function(){ pfc.switch_text_color(this.bbc); }
clist.appendChild(elt);
}
}
};
/**
* This class centralize the pfc resources (translated messages, images, themes ...)
* (depends on prototype library)
* @author Stephane Gully
*/
var pfcResource = Class.create();
pfcResource.prototype = {
initialize: function()
{
this.labels = $H();
this.fileurl = $H();
this.smileys = $H();
this.smileysreverse = $H();
this.smileyskeys = new Array();
},
setLabel: function(key, value)
{
this.labels.set(key,value);
},
getLabel: function()
{
var key = this.getLabel.arguments[0];
if (this.labels.get(key))
{
this.getLabel.arguments[0] = this.labels.get(key);
return String.sprintf2(this.getLabel.arguments);
}
else
return '_'+key+'_';
},
setFileUrl: function(key, value)
{
this.fileurl.set(key,value);
},
getFileUrl: function(key)
{
if (this.fileurl.get(key))
return this.fileurl.get(key);
else
return "";
},
setSmiley: function(key, value)
{
this.smileys.set(key, value);
this.smileysreverse.set(value,key);
this.smileyskeys.push(key);
},
getSmiley: function(key)
{
if (this.smileys.get(key))
return this.smileys.get(key);
else
return "";
},
getSmileyHash: function()
{
return this.smileys;
},
getSmileyReverseHash: function()
{
return this.smileysreverse;
},
getSmileyKeys: function()
{
return this.smileyskeys;
},
sortSmileyKeys: function()
{
return this.smileyskeys.sort(
function (a,b)
{
var x = a.unescapeHTML();
var y = b.unescapeHTML();
if (is_ie || is_webkit)
{
x = x.replace(/&quot;/g,'"');
y = y.replace(/&quot;/g,'"');
}
return (y.length - x.length);
}
);
}
};
var pfcPrompt = Class.create();
pfcPrompt.prototype = {
initialize: function(container)
{
if (container == undefined || (is_ie && !is_ie7))
container = document.getElementsByTagName('body')[0];
this.container = container;
this.box = $('pfc_promptbox');
this.bgbox = $('pfc_promptbgbox');
this.prompt_field = $('pfc_promptbox_field');
this.prompt_title = $('pfc_promptbox_title');
this.buildBox();
this.buildBgBox();
},
buildBox: function()
{
if (!this.box)
{
this.box = document.createElement('div');
this.box.id = 'pfc_promptbox';
this.box.style.position = 'absolute';
this.box.style.zIndex = 100;
this.box.style.display = 'none';
if (is_gecko) {
this.box.style.overflow = 'auto';
}
var div = document.createElement('h2');
div.appendChild(document.createTextNode(pfc.res.getLabel('Input Required')));
this.box.appendChild(div);
this.prompt_title = document.createElement('p');
this.prompt_title.id = 'pfc_promptbox_title';
this.box.appendChild(this.prompt_title);
var form = document.createElement('form');
form.pfc_prompt = this;
form.onsubmit = function(evt) { return this.pfc_prompt._doSubmit(); };
this.box.appendChild(form);
this.prompt_field = document.createElement('input');
this.prompt_field.id = 'pfc_promptbox_field';
this.prompt_field.type = 'text';
this.prompt_field.value = '';
form.appendChild(this.prompt_field);
var br = document.createElement('br');
form.appendChild(br);
var cancel = document.createElement('input');
cancel.id = 'pfc_promptbox_cancel';
cancel.type = 'button';
cancel.value = pfc.res.getLabel('Cancel');
cancel.pfc_prompt = this;
cancel.onclick = function(evt) { return this.pfc_prompt._doSubmit(true); };
form.appendChild(cancel);
var submit = document.createElement('input');
submit.id = 'pfc_promptbox_submit';
submit.type = 'submit';
submit.value = pfc.res.getLabel('OK');
form.appendChild(submit);
var ct = document.getElementsByTagName('body')[0];
ct.appendChild(this.box);
}
},
buildBgBox: function()
{
if (!this.bgbox)
{
this.bgbox = document.createElement('div');
this.bgbox.id = 'pfc_promptbgbox';
this.bgbox.style.opacity = '.7';
this.bgbox.style.position = 'absolute';
this.bgbox.style.backgroundColor = '#555';
this.bgbox.style.filter = 'alpha(opacity=70)';
this.bgbox.style.display = 'none';
this.bgbox.style.zIndex = 50;
var ct = document.getElementsByTagName('body')[0];
ct.appendChild(this.bgbox);
}
},
prompt: function(text,def)
{
if (def==undefined) { def=''; }
var pos = this._findPos(this.container);
this.bgbox.style.top = pos[1]+'px';
this.bgbox.style.left = pos[0]+'px';
/* Some older IE browsers (e.g., IE 5.5) need scrollHeight/scrollWidth.
See: http://www.quirksmode.org/viewport/compatibility.html */
if (this.container.scrollHeight > this.container.offsetHeight
|| this.container.scrollWidth > this.container.offsetWidth)
{
this.bgbox.style.height = this.container.scrollHeight+'px';
this.bgbox.style.width = this.container.scrollWidth+'px';
}
else
{
this.bgbox.style.height = this.container.offsetHeight+'px';
this.bgbox.style.width = this.container.offsetWidth+'px';
}
this.bgbox.style.display = 'block';
this.box.style.display = 'block';
this.box.style.top = parseInt(pos[1]+(this.bgbox.offsetHeight-this.box.offsetHeight)/2)+'px';
this.box.style.left = parseInt(pos[0]+(this.bgbox.offsetWidth-this.box.offsetWidth)/2)+'px';
this.prompt_field.value = def;
this.prompt_field.focus();
this.prompt_title.innerHTML = text;
},
_doSubmit: function(canceled)
{
var val = this.prompt_field.value;
if (is_gecko) this.box.focus();
this.box.style.display = 'none';
this.bgbox.style.display = 'none';
this.prompt_field.value = '';
if (canceled) { val = '' }
this.callback(val,this);
return false;
},
_findPos: function(obj)
{
var curleft = curtop = 0;
if (obj.offsetParent) {
curleft = obj.offsetLeft;
curtop = obj.offsetTop;
while (obj = obj.offsetParent) {
curleft += obj.offsetLeft;
curtop += obj.offsetTop;
}
}
return [curleft,curtop];
},
focus: function()
{
this.prompt_field.focus();
},
callback: function(v,pfcp)
{
}
}

