[Phpfreechat-svn] SF.net SVN: phpfreechat: [1215] trunk
Status: Beta
Brought to you by:
kerphi
From: <ke...@us...> - 2007-11-22 16:50:33
|
Revision: 1215 http://phpfreechat.svn.sourceforge.net/phpfreechat/?rev=1215&view=rev Author: kerphi Date: 2007-11-22 08:50:37 -0800 (Thu, 22 Nov 2007) Log Message: ----------- - Upgrade to prototype 1.6 - Bug fix: whoisbox was broken in IE7 - Window onload event is now handled only by prototype Modified Paths: -------------- trunk/data/public/js/md5.js trunk/data/public/js/pfcclient.js trunk/data/public/js/pfcgui.js trunk/data/public/js/pfcresource.js trunk/data/public/js/prototype.js trunk/src/phpfreechat.class.php trunk/themes/default/chat.js.tpl.php Modified: trunk/data/public/js/md5.js =================================================================== --- trunk/data/public/js/md5.js 2007-11-22 16:45:25 UTC (rev 1214) +++ trunk/data/public/js/md5.js 2007-11-22 16:50:37 UTC (rev 1215) @@ -1,256 +1,327 @@ -/* - * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message - * Digest Algorithm, as defined in RFC 1321. - * 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. - */ +/** +* 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 <har...@gm...> +* +* 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 +*/ -/* - * Configurable variables. You may need to tweak these to be compatible with - * the server-side, but the defaults work in most cases. - */ -var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */ -var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */ -var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */ +(function(){ -/* - * These are the functions you'll usually want to call - * They take string arguments and return either hex or base-64 encoded strings - */ -function hex_md5(s){ return binl2hex(core_md5(str2binl(s), s.length * chrsz));} -function b64_md5(s){ return binl2b64(core_md5(str2binl(s), s.length * chrsz));} -function str_md5(s){ return binl2str(core_md5(str2binl(s), s.length * chrsz));} -function hex_hmac_md5(key, data) { return binl2hex(core_hmac_md5(key, data)); } -function b64_hmac_md5(key, data) { return binl2b64(core_hmac_md5(key, data)); } -function str_hmac_md5(key, data) { return binl2str(core_hmac_md5(key, data)); } + 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 */ -/* - * Perform a simple self-test to see if the VM is working - */ -function md5_vm_test() -{ - return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72"; -} + /** + * 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); + }, -/* - * Calculate the MD5 of an array of little-endian words, and a bit length - */ -function core_md5(x, len) -{ - /* append padding */ - x[len >> 5] |= 0x80 << ((len) % 32); - x[(((len + 64) >>> 9) << 4) + 14] = len; + /** + * 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); + }, - var a = 1732584193; - var b = -271733879; - var c = -1732584194; - var d = 271733878; + /** + * 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); + }, - for(var i = 0; i < x.length; i += 16) - { - var olda = a; - var oldb = b; - var oldc = c; - var oldd = d; - a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936); - d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586); - c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819); - b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330); - a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897); - d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426); - c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341); - b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983); - a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416); - d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417); - c = md5_ff(c, d, a, b, x[i+10], 17, -42063); - b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162); - a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682); - d = md5_ff(d, a, b, c, x[i+13], 12, -40341101); - c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290); - b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329); + /** + * 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; + } + }; - a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510); - d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632); - c = md5_gg(c, d, a, b, x[i+11], 14, 643717713); - b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302); - a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691); - d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083); - c = md5_gg(c, d, a, b, x[i+15], 14, -660478335); - b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848); - a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438); - d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690); - c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961); - b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501); - a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467); - d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784); - c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473); - b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734); - - a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558); - d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463); - c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562); - b = md5_hh(b, c, d, a, x[i+14], 23, -35309556); - a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060); - d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353); - c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632); - b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640); - a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174); - d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222); - c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979); - b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189); - a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487); - d = md5_hh(d, a, b, c, x[i+12], 11, -421815835); - c = md5_hh(c, d, a, b, x[i+15], 16, 530742520); - b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651); - - a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844); - d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415); - c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905); - b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055); - a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571); - d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606); - c = md5_ii(c, d, a, b, x[i+10], 15, -1051523); - b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799); - a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359); - d = md5_ii(d, a, b, c, x[i+15], 10, -30611744); - c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380); - b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649); - a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070); - d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379); - c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259); - b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551); - - a = safe_add(a, olda); - b = safe_add(b, oldb); - c = safe_add(c, oldc); - d = safe_add(d, oldd); - } - return Array(a, b, c, d); - -} - -/* - * These functions implement the four basic operations the algorithm uses. - */ -function md5_cmn(q, a, b, x, s, t) -{ - return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b); -} -function md5_ff(a, b, c, d, x, s, t) -{ - return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t); -} -function md5_gg(a, b, c, d, x, s, t) -{ - return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t); -} -function md5_hh(a, b, c, d, x, s, t) -{ - return md5_cmn(b ^ c ^ d, a, b, x, s, t); -} -function md5_ii(a, b, c, d, x, s, t) -{ - return md5_cmn(c ^ (b | (~d)), a, b, x, s, t); -} - -/* - * Calculate the HMAC-MD5, of a key and some data - */ -function core_hmac_md5(key, data) -{ - var bkey = str2binl(key); - if(bkey.length > 16) bkey = core_md5(bkey, key.length * 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 = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz); - return 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. - */ -function safe_add(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. - */ -function bit_rol(num, cnt) -{ - return (num << cnt) | (num >>> (32 - cnt)); -} - -/* - * Convert a string to an array of little-endian words - * If chrsz is ASCII, characters >255 have their hi-byte silently ignored. - */ -function str2binl(str) -{ - var bin = Array(); - var mask = (1 << chrsz) - 1; - for(var i = 0; i < str.length * chrsz; i += chrsz) - bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32); - return bin; -} - -/* - * Convert an array of little-endian words to a string - */ -function binl2str(bin) -{ - var str = ""; - var mask = (1 << chrsz) - 1; - for(var i = 0; i < bin.length * 32; i += chrsz) - str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask); - return str; -} - -/* - * Convert an array of little-endian words to a hex string. - */ -function binl2hex(binarray) -{ - var hex_tab = 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 - */ -function binl2b64(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 += 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); + } +})(); \ No newline at end of file Modified: trunk/data/public/js/pfcclient.js =================================================================== --- trunk/data/public/js/pfcclient.js 2007-11-22 16:45:25 UTC (rev 1214) +++ trunk/data/public/js/pfcclient.js 2007-11-22 16:50:37 UTC (rev 1215) @@ -62,6 +62,16 @@ 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'); @@ -170,8 +180,8 @@ if (cmd == "who" || cmd == "who2") { param2 = $H(param2); - param2['meta'] = $H(param2['meta']); - param2['meta']['users'] = $H(param2['meta']['users']); + 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 @@ -407,7 +417,8 @@ } else if (cmd == "whois" || cmd == "whois2") { - var nickid = param['nickid']; + param = $H(param); + var nickid = param.get('nickid'); if (resp == "ok") { this.setUserMeta(nickid, param); @@ -423,7 +434,7 @@ for (var i=0; i<um_keys.length; i++) { var k = um_keys[i]; - var v = um[k]; + var v = um.get(k); if (v && // these parameter are used internaly (don't display it) k != 'nickid' && @@ -437,18 +448,19 @@ } else if (cmd == "who" || cmd == "who2") { - var chan = param['chan']; - var chanid = param['chanid']; - var meta = $H(param['meta']); - meta['users'] = $H(meta['users']); + 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); // send /whois commands for unknown users - for (var i=0; i<meta['users']['nickid'].length; i++) + for (var i=0; i<meta.get('users').get('nickid').length; i++) { - var nickid = meta['users']['nickid'][i]; - var nick = meta['users']['nick'][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+'"'); } @@ -490,16 +502,16 @@ getAllUserMeta: function(nickid) { - if (nickid && this.usermeta[nickid]) - return this.usermeta[nickid]; + if (nickid && this.usermeta.get(nickid)) + return this.usermeta.get(nickid); else return null; }, getUserMeta: function(nickid, key) { - if (nickid && key && this.usermeta[nickid] && this.usermeta[nickid][key]) - return this.usermeta[nickid][key]; + if (nickid && key && this.usermeta.get(nickid) && this.usermeta.get(nickid).get(key)) + return this.usermeta.get(nickid).get(key); else return ''; }, @@ -508,26 +520,26 @@ { if (nickid && key) { - if (!this.usermeta[nickid]) this.usermeta[nickid] = $H(); + if (!this.usermeta.get(nickid)) this.usermeta.set(nickid, $H()); if (value) - this.usermeta[nickid][key] = value; + this.usermeta.get(nickid).set(key, value); else - this.usermeta[nickid] = $H(key); + this.usermeta.set(nickid, $H(key)); } }, getAllChanMeta: function(chanid) { - if (chanid && this.chanmeta[chanid]) - return this.chanmeta[chanid]; + if (chanid && this.chanmeta.get(chanid)) + return this.chanmeta.get(chanid); else return null; }, getChanMeta: function(chanid, key) { - if (chanid && key && this.chanmeta[chanid] && this.chanmeta[chanid][key]) - return this.chanmeta[chanid][key]; + if (chanid && key && this.chanmeta.get(chanid) && this.chanmeta.get(chanid).get(key)) + return this.chanmeta.get(chanid).get(key); else return ''; }, @@ -536,11 +548,11 @@ { if (chanid && key) { - if (!this.chanmeta[chanid]) this.chanmeta[chanid] = $H(); + if (!this.chanmeta.get(chanid)) this.chanmeta.set(chanid, $H()); if (value) - this.chanmeta[chanid][key] = value; + this.chanmeta.get(chanid).set(key,value); else - this.chanmeta[chanid] = $H(key); + this.chanmeta.set(chanid, $H(key)); } }, @@ -909,9 +921,8 @@ var msg_html = $H(); var max_msgid = $H(); - //alert(cmds.inspect()); +//alert(cmds.inspect()); - // var html = ''; for(var mid = 0; mid < cmds.length ; mid++) { var id = cmds[mid][0]; @@ -923,7 +934,7 @@ var param = cmds[mid][6]; var fromtoday = cmds[mid][7]; var oldmsg = cmds[mid][8]; - + // format and post message var line = ''; line += '<div id="pfc_msg_'+recipientid+'_'+id+'" class="pfc_cmd_'+ cmd +' pfc_message'; @@ -940,7 +951,7 @@ line += '‹'; line += '<span '; line += 'onclick="pfc.insert_text(\'' + sender.replace("'", '\\\'') + ', \',\'\',false)" '; - line += 'class="pfc_nickmarker pfc_nick_'+ hex_md5(_to_utf8(sender)) +'">'; + line += 'class="pfc_nickmarker pfc_nick_'+ _to_utf8(sender).md5() +'">'; line += sender; line += '</span>'; line += '›'; @@ -965,14 +976,14 @@ this.gui.notifyWindow(); } - if (msg_html[recipientid] == null) - msg_html[recipientid] = line; + if (msg_html.get(recipientid) == null) + msg_html.set(recipientid, line); else - msg_html[recipientid] += line; - + msg_html.set(recipientid, msg_html.get(recipientid) + line); + // remember the max message id in order to clean old lines - if (!max_msgid[recipientid]) max_msgid[recipientid] = 0; - if (max_msgid[recipientid] < id) max_msgid[recipientid] = id; + if (!max_msgid.get(recipientid)) max_msgid.set(recipientid, 0); + if (max_msgid.get(recipientid) < id) max_msgid.set(recipientid, id); } // loop on all recipients and post messages @@ -981,13 +992,12 @@ { var recipientid = keys[i]; var tabid = recipientid; - // create the tab if it doesn't exists yet var recipientdiv = this.gui.getChatContentFromTabId(tabid); - + // create a dummy div to avoid konqueror bug when setting nickmarkers var m = document.createElement('div'); // do not setup a inline element (ex: span) because the element height will be wrong on FF2 -> scrollDown(..) will be broken - m.innerHTML = msg_html[recipientid]; + m.innerHTML = msg_html.get(recipientid); this.colorizeNicks(m); this.refresh_clock(m); // finaly append this to the message list @@ -995,7 +1005,7 @@ this.gui.scrollDown(tabid, m); // delete the old messages from the client (save some memory) - var limit_msgid = max_msgid[recipientid] - pfc_max_displayed_lines; + var limit_msgid = max_msgid.get(recipientid) - pfc_max_displayed_lines; var elt = $('pfc_msg_'+recipientid+'_'+limit_msgid); while (elt) { @@ -1009,8 +1019,7 @@ limit_msgid--; elt = $('pfc_msg_'+recipientid+'_'+limit_msgid); } - } - + } }, /** @@ -1039,13 +1048,9 @@ // send the real ajax request var url = pfc_server_script_url; - var params = $H(); - params['pfc_ajax'] = 1; - params['f'] = 'handleRequest'; - params['cmd'] = cmd; new Ajax.Request(url, { method: 'post', - parameters: params, + parameters: {'pfc_ajax':1, 'f':'handleRequest', 'cmd': cmd }, onCreate: function(transport) { this.pfc_ajax_connected = true; // request time counter used by ping indicator @@ -1221,7 +1226,7 @@ { var className = (! is_ie) ? 'class' : 'className'; - var nickidlst = this.getChanMeta(chanid,'users')['nickid']; + var nickidlst = this.getChanMeta(chanid,'users').get('nickid'); var nickdiv = this.gui.getOnlineContentFromTabId(chanid); var ul = document.createElement('ul'); ul.setAttribute(className, 'pfc_nicklist'); @@ -1242,9 +1247,9 @@ getNickWhoisBox: function(nickid) { - if (!this.nickwhoisbox[nickid]) + if (!this.nickwhoisbox.get(nickid)) this.updateNickWhoisBox(nickid); - return this.nickwhoisbox[nickid]; + return this.nickwhoisbox.get(nickid); }, updateNickWhoisBox: function(nickid) @@ -1252,7 +1257,6 @@ var className = (! is_ie) ? 'class' : 'className'; var usermeta = this.getAllUserMeta(nickid); - var div = document.createElement('div'); div.setAttribute(className, 'pfc_nickwhois'); @@ -1271,7 +1275,7 @@ img.setAttribute('src', this.res.getFileUrl('images/close-whoisbox.gif')); img.alt = this.res.getLabel('Close'); p.appendChild(img); - p.appendChild(document.createTextNode(usermeta['nick'])); // append the nickname text in the title + p.appendChild(document.createTextNode(usermeta.get('nick'))); // append the nickname text in the title // add the whois information table var table = document.createElement('table'); @@ -1282,7 +1286,7 @@ for (var i=0; i<um_keys.length; i++) { var k = um_keys[i]; - var v = usermeta[k]; + var v = usermeta.get(k); if (v && k != 'nickid' && k != 'nick' // useless because it is displayed in the box title && k != 'isadmin' // useless because of the gold shield icon @@ -1292,12 +1296,12 @@ ) { var tr = document.createElement('tr'); - if (nickmeta_key_to_hide.indexOf(k) != -1) + 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.update(v); + td2.innerHTML = v; tr.appendChild(td2); } else @@ -1306,8 +1310,8 @@ td1.setAttribute(className, 'pfc_nickwhois_c1'); var td2 = document.createElement('td'); td2.setAttribute(className, 'pfc_nickwhois_c2'); - td1.update(k); - td2.update(v); + td1.innerHTML = k; + td2.innerHTML = v; tr.appendChild(td1); tr.appendChild(td2); } @@ -1340,7 +1344,7 @@ div.appendChild(p); } - this.nickwhoisbox[nickid] = div; + this.nickwhoisbox.set(nickid, div); }, buildNickItem: function(nickid) @@ -1502,13 +1506,12 @@ // We don't want to replace smiley strings inside of tags. // Use negative lookahead to search for end of tag. rx = new RegExp(RegExp.escape(sl[i]) + '(?![^<]*>)','g'); - msg = msg.replace(rx, '<img src="'+ smileys[sl[i]] +'" alt="' + sl[i] + '" title="' + sl[i] + '" />'); + msg = msg.replace(rx, '<img src="'+ smileys.get(sl[i]) +'" alt="' + sl[i] + '" title="' + sl[i] + '" />'); } - + // try to parse nickname for highlighting rx = new RegExp('(^|[ :,;])'+RegExp.escape(this.nickname)+'([ :,;]|$)','gi'); msg = msg.replace(rx, '$1<strong>'+ this.nickname +'</strong>$2'); - // this piece of code is replaced by the word-wrap CSS3 rule. /* @@ -1593,7 +1596,7 @@ applyNickColor: function(root, nick, color) { - var nicktochange = this.getElementsByClassName(root, 'pfc_nick_'+ hex_md5(_to_utf8(nick)), ''); + var nicktochange = this.getElementsByClassName(root, 'pfc_nick_'+ _to_utf8(nick).md5(), ''); for(var i = 0; nicktochange.length > i; i++) nicktochange[i].style.color = color; @@ -2070,7 +2073,6 @@ for(var i = 0; i < contentlist.length; i++) { var chatdiv = contentlist[i]; - var style = $H(); if (!this.showwhosonline) { chatdiv.style.width = '100%'; Modified: trunk/data/public/js/pfcgui.js =================================================================== --- trunk/data/public/js/pfcgui.js 2007-11-22 16:45:25 UTC (rev 1214) +++ trunk/data/public/js/pfcgui.js 2007-11-22 16:50:37 UTC (rev 1215) @@ -36,8 +36,8 @@ if (this.getTabId() != tabid) { // no it's not the current active one so just cache the elttoscroll in the famouse this.elttoscroll array - if (!this.elttoscroll[tabid]) this.elttoscroll[tabid] = Array(); - this.elttoscroll[tabid].push(elttoscroll); + if (!this.elttoscroll.get(tabid)) this.elttoscroll.set(tabid, Array()); + this.elttoscroll.get(tabid).push(elttoscroll); return; } // the wanted tab is active so just scroll down the tab content element @@ -48,7 +48,7 @@ // http://sourceforge.net/tracker/index.php?func=detail&aid=1568264&group_id=158880&atid=809601 var dudVar = content.scrollTop; content.scrollTop += elttoscroll.offsetHeight+2; - this.scrollpos[tabid] = content.scrollTop; + this.scrollpos.set(tabid, content.scrollTop); }, isCreated: function(tabid) @@ -69,7 +69,7 @@ // first of all save the scroll pos of the visible tab var content = this.getChatContentFromTabId(this.current_tab_id); - this.scrollpos[this.current_tab_id] = content.scrollTop; + this.scrollpos.set(this.current_tab_id, content.scrollTop); // start without selected tabs this.current_tab = ''; @@ -103,17 +103,17 @@ // restore the scroll pos var content = this.getChatContentFromTabId(tabid); - content.scrollTop = this.scrollpos[tabid]; + content.scrollTop = this.scrollpos.get(tabid); // scroll the new posted message - if (this.elttoscroll[tabid] && - this.elttoscroll[tabid].length > 0) + if (this.elttoscroll.get(tabid) && + this.elttoscroll.get(tabid).length > 0) { // on by one - for (var i=0; i<this.elttoscroll[tabid].length; i++) - this.scrollDown(tabid,this.elttoscroll[tabid][i]); + for (var i=0; i<this.elttoscroll.get(tabid).length; i++) + this.scrollDown(tabid,this.elttoscroll.get(tabid)[i]); // empty the cached element list because it has been scrolled - this.elttoscroll[tabid] = Array(); + this.elttoscroll.set(tabid, Array()); } this.unnotifyTab(tabid); @@ -129,7 +129,7 @@ var className = (! is_ie) ? 'class' : 'className'; // return the chat content if it exists - var cc = this.chatcontent[tabid]; + var cc = this.chatcontent.get(tabid); if (cc) return cc; // if the chat content doesn't exists yet, just create a cached one @@ -141,7 +141,7 @@ cc.style.display = "block"; // needed by IE6 to show the online div at startup (first loaded page) // cc.style.marginLeft = "5px"; - this.chatcontent[tabid] = cc; + this.chatcontent.set(tabid,cc); return cc; }, getOnlineContentFromTabId: function(tabid) @@ -149,7 +149,7 @@ var className = (! is_ie) ? 'class' : 'className'; // return the online content if it exists - var oc = this.onlinecontent[tabid]; + var oc = this.onlinecontent.get(tabid); if (oc) return oc; oc = document.createElement('div'); @@ -160,7 +160,7 @@ // oc.style.borderLeft = "1px solid #555"; oc.style.display = "block"; // needed by IE6 to show the online div at startup (first loaded page) - this.onlinecontent[tabid] = oc; + this.onlinecontent.set(tabid,oc); return oc; }, @@ -194,7 +194,7 @@ /* removeTabByName: function(name) { - var tabid = hex_md5(_to_utf8(name)); + var tabid = _to_utf8(name).md5(); var ret = this.removeTabById(tabid); if (ret == name) return tabid; @@ -214,7 +214,7 @@ // do not create twice a the same tab if (this.isCreated(tabid)) return; - // var tabid = hex_md5(_to_utf8(name)); + // var tabid = _to_utf8(name).md5(); //alert(name+'='+tabid); this.tabs.push(name); this.tabids.push(tabid); @@ -406,7 +406,7 @@ for(var i = 0; i < sl.length; i++) { s_url = sl[i]; - s_symbol = smileys[sl[i]]; + s_symbol = smileys.get(sl[i]); s_symbol = s_symbol.unescapeHTML(); // Replace " with " for IE and Webkit browsers. // The prototype.js version 1.5.1.1 unescapeHTML() function does not do this. Modified: trunk/data/public/js/pfcresource.js =================================================================== --- trunk/data/public/js/pfcresource.js 2007-11-22 16:45:25 UTC (rev 1214) +++ trunk/data/public/js/pfcresource.js 2007-11-22 16:50:37 UTC (rev 1215) @@ -17,15 +17,15 @@ setLabel: function(key, value) { - this.labels[key] = value; + this.labels.set(key,value); }, getLabel: function() { var key = this.getLabel.arguments[0]; - if (this.labels[key]) + if (this.labels.get(key)) { - this.getLabel.arguments[0] = this.labels[key]; + this.getLabel.arguments[0] = this.labels.get(key); return String.sprintf2(this.getLabel.arguments); } else @@ -34,27 +34,27 @@ setFileUrl: function(key, value) { - this.fileurl[key] = value; + this.fileurl.set(key,value); }, getFileUrl: function(key) { - if (this.fileurl[key]) - return this.fileurl[key]; + if (this.fileurl.get(key)) + return this.fileurl.get(key); else return ""; }, setSmiley: function(key, value) { - this.smileys[key] = value; - this.smileysreverse[value] = key; + this.smileys.set(key, value); + this.smileysreverse.set(value,key); this.smileyskeys.push(key); }, getSmiley: function(key) { - if (this.smileys[key]) - return this.smileys[key]; + if (this.smileys.get(key)) + return this.smileys.get(key); else return ""; }, Modified: trunk/data/public/js/prototype.js =================================================================== --- trunk/data/public/js/prototype.js 2007-11-22 16:45:25 UTC (rev 1214) +++ trunk/data/public/js/prototype.js 2007-11-22 16:50:37 UTC (rev 1215) @@ -1,27 +1,29 @@ -/* Prototype JavaScript framework, version 1.5.1.1 +/* Prototype JavaScript framework, version 1.6.0 * (c) 2005-2007 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.5.1.1', + Version: '1.6.0', 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 + 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('form').__proto__) + document.createElement('div').__proto__ && + document.createElement('div').__proto__ !== + document.createElement('form').__proto__ }, ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>', @@ -29,24 +31,81 @@ emptyFunction: function() { }, K: function(x) { return x } -} +}; +if (Prototype.Browser.MobileSafari) + Prototype.BrowserFeatures.SpecificElementExtensions = false; + +if (Prototype.Browser.WebKit) + Prototype.BrowserFeatures.XPath = false; + +/* Based on Alex Arnell's inheritance implementation. */ var Class = { create: function() { - return 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; } -} +}; -var Abstract = new Object(); +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) { + for (var property in source) destination[property] = source[property]; - } return destination; -} +}; Object.extend(Object, { inspect: function(object) { @@ -62,24 +121,35 @@ toJSON: function(object) { var type = typeof object; - switch(type) { + 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.ownerDocument === document) return; + if (Object.isElement(object)) return; + var results = []; for (var property in object) { var value = Object.toJSON(object[property]); if (value !== undefined) 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) @@ -95,55 +165,99 @@ }, clone: function(object) { - return Object.extend({}, object); + return Object.extend({ }, object); + }, + + isElement: function(object) { + return object && object.nodeType == 1; + }, + + isArray: function(object) { + return object && object.constructor === Array; + }, + + 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"; } }); -Function.prototype.bind = function() { - var __method = this, args = $A(arguments), object = args.shift(); - return function() { - return __method.apply(object, args.concat($A(arguments))); - } -} +Object.extend(Function.prototype, { + argumentNames: function() { + var names = this.toString().match(/^[\s\(]*function[^(]*\((.*?)\)/)[1].split(",").invoke("strip"); + return names.length == 1 && !names[0] ? [] : names; + }, -Function.prototype.bindAsEventListener = function(object) { - var __method = this, args = $A(arguments), object = args.shift(); - return function(event) { - return __method.apply(object, [event || window.event].concat(args)); - } -} + bind: function() { + if (arguments.length < 2 && arguments[0] === undefined) return this; + var __method = this, args = $A(arguments), object = args.shift(); + return function() { + return __method.apply(object, args.concat($A(arguments))); + } + }, -Object.extend(Number.prototype, { - toColorPart: function() { - return this.toPaddedString(2, 16); + bindAsEventListener: function() { + var __method = this, args = $A(arguments), object = args.shift(); + return function(event) { + return __method.apply(object, [event || window.event].concat(args)); + } }, - succ: function() { - return this + 1; + curry: function() { + if (!arguments.length) return this; + var __method = this, args = $A(arguments); + return function() { + return __method.apply(this, args.concat($A(arguments))); + } }, - times: function(iterator) { - $R(0, this, true).each(iterator); - return this; + delay: function() { + var __method = this, args = $A(arguments), timeout = args.shift() * 1000; + return window.setTimeout(function() { + return __method.apply(__method, args); + }, timeout); }, - toPaddedString: function(length, radix) { - var string = this.toString(radix || 10); - return '0'.times(length - string.length) + string; + wrap: function(wrapper) { + var __method = this; + return function() { + return wrapper.apply(this, [__method.bind(this)].concat($A(arguments))); + } }, - toJSON: function() { - return isFinite(this) ? this.toString() : 'null'; + 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.getFullYear() + '-' + - (this.getMonth() + 1).toPaddedString(2) + '-' + - this.getDate().toPaddedString(2) + 'T' + - this.getHours().toPaddedString(2) + ':' + - this.getMinutes().toPaddedString(2) + ':' + - this.getSeconds().toPaddedString(2) + '"'; + 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 = { @@ -155,17 +269,22 @@ try { returnValue = lambda(); break; - } catch (e) {} + } catch (e) { } } return returnValue; } -} +}; +RegExp.prototype.match = RegExp.prototype.test; + +RegExp.escape = function(str) { + return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); +}; + /*--------------------------------------------------------------------------*/ -var PeriodicalExecuter = Class.create(); -PeriodicalExecuter.prototype = { +var PeriodicalExecuter = Class.create({ initialize: function(callback, frequency) { this.callback = callback; this.frequency = frequency; @@ -178,6 +297,10 @@ this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); }, + execute: function() { + this.callback(this); + }, + stop: function() { if (!this.timer) return; clearInterval(this.timer); @@ -188,13 +311,13 @@ if (!this.currentlyExecuting) { try { this.currentlyExecuting = true; - this.callback(this); + this.execute(); } finally { this.currentlyExecuting = false; } } } -} +}); Object.extend(String, { interpret: function(value) { return value == null ? '' : String(value); @@ -238,14 +361,14 @@ scan: function(pattern, iterator) { this.gsub(pattern, iterator); - return this; + return String(this); }, truncate: function(length, truncation) { length = length || 30; truncation = truncation === undefined ? '...' : truncation; return this.length > length ? - this.slice(0, length - truncation.length) + truncation : this; + this.slice(0, length - truncation.length) + truncation : String(this); }, strip: function() { @@ -279,7 +402,7 @@ }, unescapeHTML: function() { - var div = document.createElement('div'); + 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 }) : @@ -288,16 +411,16 @@ toQueryParams: function(separator) { var match = this.strip().match(/([^?#]*)(#.*)?$/); - if (!match) return {}; + if (!match) return { }; - return match[1].split(separator || '&').inject({}, function(hash, pair) { + 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 (hash[key].constructor != Array) hash[key] = [hash[key]]; + if (!Object.isArray(hash[key])) hash[key] = [hash[key]]; hash[key].push(value); } else hash[key] = value; @@ -316,9 +439,7 @@ }, times: function(count) { - var result = ''; - for (var i = 0; i < count; i++) result += this; - return result; + return count < 1 ? '' : new Array(count + 1).join(this); }, camelize: function() { @@ -396,6 +517,10 @@ blank: function() { return /^\s*$/.test(this); + }, + + interpolate: function(object, pattern) { + return new Template(this, pattern).evaluate(object); } }); @@ -409,10 +534,10 @@ }); String.prototype.gsub.prepareReplacement = function(replacement) { - if (typeof replacement == 'function') return 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; @@ -423,28 +548,46 @@ with (String.prototype.escapeHTML) div.appendChild(text); -var Template = Class.create(); -Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; -Template.prototype = { +var Template = Class.create({ initialize: function(template, pattern) { this.template = template.toString(); - this.pattern = pattern || Template.Pattern; + this.pattern = pattern || Template.Pattern; }, evaluate: function(object) { + if (Object.isFunction(object.toTemplateReplacements)) + object = object.toTemplateReplacements(); + return this.template.gsub(this.pattern, function(match) { - var before = match[1]; + if (object == null) return ''; + + var before = match[1] || ''; if (before == '\\') return match[2]; - return before + String.interpret(object[match[3]]); - }); + + 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); + }.bind(this)); } -} +}); +Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; -var $break = {}, $continue = new Error('"throw $continue" is deprecated, use "return" instead'); +var $break = { }; var Enumerable = { - each: function(iterator) { + each: function(iterator, context) { var index = 0; + iterator = iterator.bind(context); try { this._each(function(value) { iterator(value, index++); @@ -455,40 +598,45 @@ return this; }, - eachSlice: function(number, iterator) { + 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.map(iterator); + return slices.collect(iterator, context); }, - all: function(iterator) { + all: function(iterator, context) { + iterator = iterator ? iterator.bind(context) : Prototype.K; var result = true; this.each(function(value, index) { - result = result && !!(iterator || Prototype.K)(value, index); + result = result && !!iterator(value, index); if (!result) throw $break; }); return result; }, - any: function(iterator) { + any: function(iterator, context) { + iterator = iterator ? iterator.bind(context) : Prototype.K; var result = false; this.each(function(value, index) { - if (result = !!(iterator || Prototype.K)(value, index)) + if (result = !!iterator(value, index)) throw $break; }); return result; }, - collect: function(iterator) { + collect: function(iterator, context) { + iterator = iterator ? iterator.bind(context) : Prototype.K; var results = []; this.each(function(value, index) { - results.push((iterator || Prototype.K)(value, index)); + results.push(iterator(value, index)); }); return results; }, - detect: function(iterator) { + detect: function(iterator, context) { + iterator = iterator.bind(context); var result; this.each(function(value, index) { if (iterator(value, index)) { @@ -499,7 +647,8 @@ return result; }, - findAll: function(iterator) { + findAll: function(iterator, context) { + iterator = iterator.bind(context); var results = []; this.each(function(value, index) { if (iterator(value, index)) @@ -508,17 +657,24 @@ return results; }, - grep: function(pattern, iterator) { + 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) { - var stringValue = value.toString(); - if (stringValue.match(pattern)) - results.push((iterator || Prototype.K)(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) { @@ -537,7 +693,8 @@ }); }, - inject: function(memo, iterator) { + inject: function(memo, iterator, context) { + iterator = iterator.bind(context); this.each(function(value, index) { memo = iterator(memo, value, index); }); @@ -551,30 +708,33 @@ }); }, - max: function(iterator) { + max: function(iterator, context) { + iterator = iterator ? iterator.bind(context) : Prototype.K; var result; this.each(function(value, index) { - value = (iterator || Prototype.K)(value, index); + value = iterator(value, index); if (result == undefined || value >= result) result = value; }); return result; }, - min: function(iterator) { + min: function(iterator, context) { + iterator = iterator ? iterator.bind(context) : Prototype.K; var result; this.each(function(value, index) { - value = (iterator || Prototype.K)(value, index); + value = iterator(value, index); if (result == undefined || value < result) result = value; }); return result; }, - partition: function(iterator) { + partition: function(iterator, context) { + iterator = iterator ? iterator.bind(context) : Prototype.K; var trues = [], falses = []; this.each(function(value, index) { - ((iterator || Prototype.K)(value, index) ? + (iterator(value, index) ? trues : falses).push(value); }); return [trues, falses]; @@ -582,13 +742,14 @@ pluck: function(property) { var results = []; - this.each(function(value, index) { + this.each(function(value) { results.push(value[property]); }); return results; }, - reject: function(iterator) { + reject: function(iterator, context) { + iterator = iterator.bind(context); var results = []; this.each(function(value, index) { if (!iterator(value, index)) @@ -597,7 +758,8 @@ return results; }, - sortBy: function(iterator) { + 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) { @@ -612,7 +774,7 @@ zip: function() { var iterator = Prototype.K, args = $A(arguments); - if (typeof args.last() == 'function') + if (Object.isFunction(args.last())) iterator = args.pop(); var collections = [this].concat(args).map($A); @@ -628,46 +790,42 @@ 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 + entries: Enumerable.toArray, + every: Enumerable.all, + some: Enumerable.any }); -var $A = Array.from = function(iterable) { +function $A(iterable) { if (!iterable) return []; - if (iterable.toArray) { - return iterable.toArray(); - } else { - var results = []; - for (var i = 0, length = iterable.length; i < length; i++) - results.push(iterable[i]); - return results; - } + if (iterable.toArray) return iterable.toArray(); + var length = iterable.length, results = new Array(length); + while (length--) results[length] = iterable[length]; + return results; } if (Prototype.Browser.WebKit) { - $A = Array.from = function(iterable) { + function $A(iterable) { if (!iterable) return []; - if (!(typeof iterable == 'function' && iterable == '[object NodeList]') && - iterable.toArray) { - return iterable.toArray(); - } else { - var results = []; - for (var i = 0, length = iterable.length; i < length; i++) - results.push(iterable[i]); - return results; - } + if (!(Object.isFunction(iterable) && iterable == '[object NodeList]') && + iterable.toArray) return iterable.toArray(); + var length = iterable.length, 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; +if (!Array.prototype._reverse) Array.prototype._reverse = Array.prototype.reverse; Object.extend(Array.prototype, { _each: function(iterator) { @@ -696,7 +854,7 @@ flatten: function() { return this.inject([], function(array, value) { - return array.concat(value && value.constructor == Array ? + return array.concat(Object.isArray(value) ? value.flatten() : [value]); }); }, @@ -708,12 +866,6 @@ }); }, - indexOf: function(object) { - for (var i = 0, length = this.length; i < length; i++) - if (this[i] ==... [truncated message content] |