Thread: [Phpfreechat-svn] SF.net SVN: phpfreechat: [908] trunk/data/public/js
Status: Beta
Brought to you by:
kerphi
From: <ke...@us...> - 2006-12-21 06:34:20
|
Revision: 908 http://svn.sourceforge.net/phpfreechat/?rev=908&view=rev Author: kerphi Date: 2006-12-20 22:34:20 -0800 (Wed, 20 Dec 2006) Log Message: ----------- optimizations on interface loading (work in progress) Added Paths: ----------- trunk/data/public/js/activity.js trunk/data/public/js/cookie.js trunk/data/public/js/createstylerule.js trunk/data/public/js/image_preloader.js trunk/data/public/js/md5.js trunk/data/public/js/mousepos.js trunk/data/public/js/myprototype.js trunk/data/public/js/pfcclient.js trunk/data/public/js/pfcgui.js trunk/data/public/js/pfcresource.js trunk/data/public/js/regex.js trunk/data/public/js/sprintf2.js trunk/data/public/js/utf8.js trunk/data/public/js/xajax.js Added: trunk/data/public/js/activity.js =================================================================== --- trunk/data/public/js/activity.js (rev 0) +++ trunk/data/public/js/activity.js 2006-12-21 06:34:20 UTC (rev 908) @@ -0,0 +1,67 @@ +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; + } +} + + + +/* +// Unused code, by usefull for further auto idle features + + _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; + }, +*/ Added: trunk/data/public/js/cookie.js =================================================================== --- trunk/data/public/js/cookie.js (rev 0) +++ trunk/data/public/js/cookie.js 2006-12-21 06:34:20 UTC (rev 908) @@ -0,0 +1,59 @@ +// Cookie API v1.0.1 +// documentation: http://www.dithered.com/javascript/cookies/index.html +// license: http://creativecommons.org/licenses/by/1.0/ +// code (mostly) by Chris Nott (chris[at]dithered[dot]com) + + +// Write a cookie value +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; +} + + +// Retrieve a named cookie value +function getCookie(name) { + var dc = document.cookie; + + // find beginning of cookie value in 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; + + // find end of cookie value + var end = document.cookie.indexOf(";", begin); + if (end == -1) end = dc.length; + + // return cookie value + return unescape(dc.substring(begin + prefix.length, end)); +} + + +// Delete a named cookie value +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; +} + + +// Fix Netscape 2.x Date bug +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; +} + + +// Test for cookie support +function supportsCookies(rootPath) { + setCookie('checking_for_cookie_support', 'testing123', '', (rootPath != null ? rootPath : '')); + if (getCookie('checking_for_cookie_support')) return true; + else return false; +} \ No newline at end of file Added: trunk/data/public/js/createstylerule.js =================================================================== --- trunk/data/public/js/createstylerule.js (rev 0) +++ trunk/data/public/js/createstylerule.js 2006-12-21 06:34:20 UTC (rev 908) @@ -0,0 +1,27 @@ +// from http://www.bobbyvandersluis.com/articles/dynamicCSS.php +function createStyleRule(selector, declaration) { + if (!document.getElementsByTagName || + !(document.createElement || document.createElementNS)) return; + var agt = navigator.userAgent.toLowerCase(); + var is_ie = ((agt.indexOf("msie") != -1) && (agt.indexOf("opera") == -1)); + var is_iewin = (is_ie && (agt.indexOf("win") != -1)); + var is_iemac = (is_ie && (agt.indexOf("mac") != -1)); + if (is_iemac) return; // script doesn't work properly in IE/Mac + var head = document.getElementsByTagName("head")[0]; + var style = (typeof document.createElementNS != "undefined") ? + document.createElementNS("http://www.w3.org/1999/xhtml", "style") : + document.createElement("style"); + if (!is_iewin) { + var styleRule = document.createTextNode(selector + " {" + declaration + "}"); + style.appendChild(styleRule); // bugs in IE/Win + } + style.setAttribute("type", "text/css"); + style.setAttribute("media", "screen"); + head.appendChild(style); + if (is_iewin && document.styleSheets && document.styleSheets.length > 0) { + var lastStyle = document.styleSheets[document.styleSheets.length - 1]; + if (typeof lastStyle.addRule == "object") { + lastStyle.addRule(selector, declaration); + } + } +} \ No newline at end of file Added: trunk/data/public/js/image_preloader.js =================================================================== --- trunk/data/public/js/image_preloader.js (rev 0) +++ trunk/data/public/js/image_preloader.js 2006-12-21 06:34:20 UTC (rev 908) @@ -0,0 +1,13 @@ +// Image Preloader v1.0.1 +// documentation: http://www.dithered.com/javascript/image_preloader/index.html +// license: http://creativecommons.org/licenses/by/1.0/ +// code by Chris Nott (chris[at]dithered[dot]com) + + +function preloadImages() { + if (document.images) { + for (var i = 0; i < preloadImages.arguments.length; i++) { + (new Image()).src = preloadImages.arguments[i]; + } + } +} \ No newline at end of file Added: trunk/data/public/js/md5.js =================================================================== --- trunk/data/public/js/md5.js (rev 0) +++ trunk/data/public/js/md5.js 2006-12-21 06:34:20 UTC (rev 908) @@ -0,0 +1,256 @@ +/* + * 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. + */ + +/* + * 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 */ + +/* + * 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)); } + +/* + * Perform a simple self-test to see if the VM is working + */ +function md5_vm_test() +{ + return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72"; +} + +/* + * 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; + + 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 = 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); + + 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; +} Added: trunk/data/public/js/mousepos.js =================================================================== --- trunk/data/public/js/mousepos.js (rev 0) +++ trunk/data/public/js/mousepos.js 2006-12-21 06:34:20 UTC (rev 908) @@ -0,0 +1,25 @@ +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; +} Added: trunk/data/public/js/myprototype.js =================================================================== --- trunk/data/public/js/myprototype.js (rev 0) +++ trunk/data/public/js/myprototype.js 2006-12-21 06:34:20 UTC (rev 908) @@ -0,0 +1,1514 @@ +// modified prototype library + +var Prototype = { + Version: '1.4.0', + ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)', + + emptyFunction: function() {}, + K: function(x) {return x} +} + +var Class = { + create: function() { + return function() { + this.initialize.apply(this, arguments); + } + } +} + +var Abstract = new Object(); + +Object.extend = function(destination, source) { + for (property in source) { + destination[property] = source[property]; + } + return destination; +} + +Object.inspect = function(object) { + try { + if (object == undefined) return 'undefined'; + if (object == null) return 'null'; + return object.inspect ? object.inspect() : object.toString(); + } catch (e) { + if (e instanceof RangeError) return '...'; + throw e; + } +} + +Function.prototype.bind = function() { + var __method = this, args = $A(arguments), object = args.shift(); + return function() { + return __method.apply(object, args.concat($A(arguments))); + } +} + +Function.prototype.bindAsEventListener = function(object) { + var __method = this; + return function(event) { + return __method.call(object, event || window.event); + } +} + +Object.extend(Number.prototype, { + toColorPart: function() { + var digits = this.toString(16); + if (this < 16) return '0' + digits; + return digits; + }, + + succ: function() { + return this + 1; + }, + + times: function(iterator) { + $R(0, this, true).each(iterator); + return this; + } +}); + +var Try = { + these: function() { + var returnValue; + + for (var i = 0; i < arguments.length; i++) { + var lambda = arguments[i]; + try { + returnValue = lambda(); + break; + } catch (e) {} + } + + return returnValue; + } +} + +/*--------------------------------------------------------------------------*/ + +var PeriodicalExecuter = Class.create(); +PeriodicalExecuter.prototype = { + initialize: function(callback, frequency) { + this.callback = callback; + this.frequency = frequency; + this.currentlyExecuting = false; + + this.registerCallback(); + }, + + registerCallback: function() { + setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); + }, + + onTimerEvent: function() { + if (!this.currentlyExecuting) { + try { + this.currentlyExecuting = true; + this.callback(); + } finally { + this.currentlyExecuting = false; + } + } + } +} + +/*--------------------------------------------------------------------------*/ + +function $() { + var elements = new Array(); + + for (var i = 0; i < arguments.length; i++) { + var element = arguments[i]; + if (typeof element == 'string') + element = document.getElementById(element); + + if (arguments.length == 1) + return element; + + elements.push(element); + } + + return elements; +} +Object.extend(String.prototype, { + 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(eval); + }, + + escapeHTML: function() { + var div = document.createElement('div'); + var text = document.createTextNode(this); + div.appendChild(text); + return div.innerHTML; + }, + + unescapeHTML: function() { + var div = document.createElement('div'); + div.innerHTML = this.stripTags(); + return div.childNodes[0] ? div.childNodes[0].nodeValue : ''; + }, + + toQueryParams: function() { + var pairs = this.match(/^\??(.*)$/)[1].split('&'); + return pairs.inject({}, function(params, pairString) { + var pair = pairString.split('='); + params[pair[0]] = pair[1]; + return params; + }); + }, + + toArray: function() { + return this.split(''); + }, + + camelize: function() { + var oStringList = this.split('-'); + if (oStringList.length == 1) return oStringList[0]; + + var camelizedString = this.indexOf('-') == 0 + ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1) + : oStringList[0]; + + for (var i = 1, len = oStringList.length; i < len; i++) { + var s = oStringList[i]; + camelizedString += s.charAt(0).toUpperCase() + s.substring(1); + } + + return camelizedString; + }, + + inspect: function() { + return "'" + this.replace('\\', '\\\\').replace("'", '\\\'') + "'"; + } +}); + +String.prototype.parseQuery = String.prototype.toQueryParams; + +var $break = new Object(); +var $continue = new Object(); + +var Enumerable = { + each: function(iterator) { + var index = 0; + try { + this._each(function(value) { + try { + iterator(value, index++); + } catch (e) { + if (e != $continue) throw e; + } + }); + } catch (e) { + if (e != $break) throw e; + } + }, + + all: function(iterator) { + var result = true; + this.each(function(value, index) { + result = result && !!(iterator || Prototype.K)(value, index); + if (!result) throw $break; + }); + return result; + }, + + any: function(iterator) { + var result = true; + this.each(function(value, index) { + if (result = !!(iterator || Prototype.K)(value, index)) + throw $break; + }); + return result; + }, + + collect: function(iterator) { + var results = []; + this.each(function(value, index) { + results.push(iterator(value, index)); + }); + return results; + }, + + detect: function (iterator) { + var result; + this.each(function(value, index) { + if (iterator(value, index)) { + result = value; + throw $break; + } + }); + return result; + }, + + findAll: function(iterator) { + var results = []; + this.each(function(value, index) { + if (iterator(value, index)) + results.push(value); + }); + return results; + }, + + grep: function(pattern, iterator) { + var results = []; + this.each(function(value, index) { + var stringValue = value.toString(); + if (stringValue.match(pattern)) + results.push((iterator || Prototype.K)(value, index)); + }) + return results; + }, + + include: function(object) { + var found = false; + this.each(function(value) { + if (value == object) { + found = true; + throw $break; + } + }); + return found; + }, + + inject: function(memo, iterator) { + this.each(function(value, index) { + memo = iterator(memo, value, index); + }); + return memo; + }, + + invoke: function(method) { + var args = $A(arguments).slice(1); + return this.collect(function(value) { + return value[method].apply(value, args); + }); + }, + + max: function(iterator) { + var result; + this.each(function(value, index) { + value = (iterator || Prototype.K)(value, index); + if (value >= (result || value)) + result = value; + }); + return result; + }, + + min: function(iterator) { + var result; + this.each(function(value, index) { + value = (iterator || Prototype.K)(value, index); + if (value <= (result || value)) + result = value; + }); + return result; + }, + + partition: function(iterator) { + var trues = [], falses = []; + this.each(function(value, index) { + ((iterator || Prototype.K)(value, index) ? + trues : falses).push(value); + }); + return [trues, falses]; + }, + + pluck: function(property) { + var results = []; + this.each(function(value, index) { + results.push(value[property]); + }); + return results; + }, + + reject: function(iterator) { + var results = []; + this.each(function(value, index) { + if (!iterator(value, index)) + results.push(value); + }); + return results; + }, + + sortBy: function(iterator) { + return this.collect(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.collect(Prototype.K); + }, + + zip: function() { + var iterator = Prototype.K, args = $A(arguments); + if (typeof args.last() == 'function') + iterator = args.pop(); + + var collections = [this].concat(args).map($A); + return this.map(function(value, index) { + iterator(value = collections.pluck(index)); + return value; + }); + }, + + inspect: function() { + return '#<Enumerable:' + this.toArray().inspect() + '>'; + } +} + +Object.extend(Enumerable, { + map: Enumerable.collect, + find: Enumerable.detect, + select: Enumerable.findAll, + member: Enumerable.include, + entries: Enumerable.toArray + }); + +var $A = Array.from = function(iterable) { + if (!iterable) return []; + if (iterable.toArray) { + return iterable.toArray(); + } else { + var results = []; + for (var i = 0; i < iterable.length; i++) + results.push(iterable[i]); + return results; + } +} + +//Array.prototype._reverse = Array.prototype.reverse; + +//Object.extend(Array.prototype, Enumerable); +/* +Array.prototype._reverse = Array.prototype.reverse; + + +Object.extend(Array.prototype, { + _each: function(iterator) { + for (var i = 0; i < this.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 != undefined || value != null; + }); + }, + + flatten: function() { + return this.inject([], function(array, value) { + return array.concat(value.constructor == Array ? + value.flatten() : [value]); + }); + }, + + without: function() { + var values = $A(arguments); + return this.select(function(value) { + return !values.include(value); + }); + }, + + indexOf: function(object) { + for (var i = 0; i < this.length; i++) + if (this[i] == object) return i; + return -1; + }, + + reverse: function(inline) { + return (inline !== false ? this : this.toArray())._reverse(); + }, + + shift: function() { + var result = this[0]; + for (var i = 0; i < this.length - 1; i++) + this[i] = this[i + 1]; + this.length--; + return result; + }, + + inspect: function() { + return '[' + this.map(Object.inspect).join(', ') + ']'; + } +}); +*/ + + +var Hash = { + _each: function(iterator) { + for (key in this) { + var value = this[key]; + if (typeof value == 'function') continue; + + var pair = [key, value]; + pair.key = key; + pair.value = value; + iterator(pair); + } + }, + + keys: function() { + return this.pluck('key'); + }, + + values: function() { + return this.pluck('value'); + }, + + merge: function(hash) { + return $H(hash).inject($H(this), function(mergedHash, pair) { + mergedHash[pair.key] = pair.value; + return mergedHash; + }); + }, + + toQueryString: function() { + return this.map(function(pair) { + return pair.map(encodeURIComponent).join('='); + }).join('&'); + }, + + inspect: function() { + return '#<Hash:{' + this.map(function(pair) { + return pair.map(Object.inspect).join(': '); + }).join(', ') + '}>'; + } +} + +function $H(object) { + var hash = Object.extend({}, object || {}); + Object.extend(hash, Enumerable); + Object.extend(hash, Hash); + return hash; +} +ObjectRange = Class.create(); +Object.extend(ObjectRange.prototype, Enumerable); +Object.extend(ObjectRange.prototype, { + initialize: function(start, end, exclusive) { + this.start = start; + this.end = end; + this.exclusive = exclusive; + }, + + _each: function(iterator) { + var value = this.start; + do { + iterator(value); + value = value.succ(); + } while (this.include(value)); + }, + + 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); +} + +document.getElementsByClassName = function(className, parentElement) { + var children = ($(parentElement) || document.body).getElementsByTagName('*'); + return $A(children).inject([], function(elements, child) { + if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)"))) + elements.push(child); + return elements; + }); +} + +/*--------------------------------------------------------------------------*/ + +if (!window.Element) { + var Element = new Object(); +} + +Object.extend(Element, { + visible: function(element) { + return $(element).style.display != 'none'; + }, + + toggle: function() { + for (var i = 0; i < arguments.length; i++) { + var element = $(arguments[i]); + Element[Element.visible(element) ? 'hide' : 'show'](element); + } + }, + + hide: function() { + for (var i = 0; i < arguments.length; i++) { + var element = $(arguments[i]); + element.style.display = 'none'; + } + }, + + show: function() { + for (var i = 0; i < arguments.length; i++) { + var element = $(arguments[i]); + element.style.display = ''; + } + }, + + remove: function(element) { + element = $(element); + element.parentNode.removeChild(element); + }, + + update: function(element, html) { + $(element).innerHTML = html.stripScripts(); + setTimeout(function() {html.evalScripts()}, 10); + }, + + getHeight: function(element) { + element = $(element); + return element.offsetHeight; + }, + + classNames: function(element) { + return new Element.ClassNames(element); + }, + + hasClassName: function(element, className) { + if (!(element = $(element))) return; + return Element.classNames(element).include(className); + }, + + addClassName: function(element, className) { + if (!(element = $(element))) return; + return Element.classNames(element).add(className); + }, + + removeClassName: function(element, className) { + if (!(element = $(element))) return; + return Element.classNames(element).remove(className); + }, + + // removes whitespace-only text node children + cleanWhitespace: function(element) { + element = $(element); + for (var i = 0; i < element.childNodes.length; i++) { + var node = element.childNodes[i]; + if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) + Element.remove(node); + } + }, + + empty: function(element) { + return $(element).innerHTML.match(/^\s*$/); + }, + + scrollTo: function(element) { + element = $(element); + var x = element.x ? element.x : element.offsetLeft, + y = element.y ? element.y : element.offsetTop; + window.scrollTo(x, y); + }, + + getStyle: function(element, style) { + element = $(element); + var value = element.style[style.camelize()]; + if (!value) { + if (document.defaultView && document.defaultView.getComputedStyle) { + var css = document.defaultView.getComputedStyle(element, null); + value = css ? css.getPropertyValue(style) : null; + } else if (element.currentStyle) { + value = element.currentStyle[style.camelize()]; + } + } + + if (window.opera && ['left', 'top', 'right', 'bottom'].include(style)) + if (Element.getStyle(element, 'position') == 'static') value = 'auto'; + + return value == 'auto' ? null : value; + }, + + setStyle: function(element, style) { + element = $(element); + for (name in style) + element.style[name.camelize()] = style[name]; + }, + + getDimensions: function(element) { + element = $(element); + if (Element.getStyle(element, 'display') != 'none') + return {width: element.offsetWidth, height: element.offsetHeight}; + + // All *Width and *Height properties give 0 on elements with display none, + // so enable the element temporarily + var els = element.style; + var originalVisibility = els.visibility; + var originalPosition = els.position; + els.visibility = 'hidden'; + els.position = 'absolute'; + els.display = ''; + var originalWidth = element.clientWidth; + var originalHeight = element.clientHeight; + els.display = 'none'; + 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'; + // Opera returns the offset relative to the positioning context, when an + // element is position relative but top and left have not been defined + if (window.opera) { + element.style.top = 0; + element.style.left = 0; + } + } + }, + + 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 = ''; + } + }, + + makeClipping: function(element) { + element = $(element); + if (element._overflow) return; + element._overflow = element.style.overflow; + if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden') + element.style.overflow = 'hidden'; + }, + + undoClipping: function(element) { + element = $(element); + if (element._overflow) return; + element.style.overflow = element._overflow; + element._overflow = undefined; + } +}); + +var Toggle = new Object(); +Toggle.display = Element.toggle; + +/*--------------------------------------------------------------------------*/ + +Abstract.Insertion = function(adjacency) { + this.adjacency = adjacency; +} + +Abstract.Insertion.prototype = { + initialize: function(element, content) { + this.element = $(element); + this.content = content.stripScripts(); + + if (this.adjacency && this.element.insertAdjacentHTML) { + try { + this.element.insertAdjacentHTML(this.adjacency, this.content); + } catch (e) { + if (this.element.tagName.toLowerCase() == 'tbody') { + this.insertContent(this.contentFromAnonymousTable()); + } else { + throw e; + } + } + } else { + this.range = this.element.ownerDocument.createRange(); + if (this.initializeRange) this.initializeRange(); + this.insertContent([this.range.createContextualFragment(this.content)]); + } + + setTimeout(function() {content.evalScripts()}, 10); + }, + + contentFromAnonymousTable: function() { + var div = document.createElement('div'); + div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>'; + return $A(div.childNodes[0].childNodes[0].childNodes); + } +} + +var Insertion = new Object(); + +Insertion.Before = Class.create(); +Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), { + initializeRange: function() { + this.range.setStartBefore(this.element); + }, + + insertContent: function(fragments) { + fragments.each((function(fragment) { + this.element.parentNode.insertBefore(fragment, this.element); + }).bind(this)); + } +}); + +Insertion.Top = Class.create(); +Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), { + initializeRange: function() { + this.range.selectNodeContents(this.element); + this.range.collapse(true); + }, + + insertContent: function(fragments) { + fragments.reverse(false).each((function(fragment) { + this.element.insertBefore(fragment, this.element.firstChild); + }).bind(this)); + } +}); + +Insertion.Bottom = Class.create(); +Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), { + initializeRange: function() { + this.range.selectNodeContents(this.element); + this.range.collapse(this.element); + }, + + insertContent: function(fragments) { + fragments.each((function(fragment) { + this.element.appendChild(fragment); + }).bind(this)); + } +}); + +Insertion.After = Class.create(); +Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), { + initializeRange: function() { + this.range.setStartAfter(this.element); + }, + + insertContent: function(fragments) { + fragments.each((function(fragment) { + this.element.parentNode.insertBefore(fragment, + this.element.nextSibling); + }).bind(this)); + } +}); + +/*--------------------------------------------------------------------------*/ + +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(this.toArray().concat(classNameToAdd).join(' ')); + }, + + remove: function(classNameToRemove) { + if (!this.include(classNameToRemove)) return; + this.set(this.select(function(className) { + return className != classNameToRemove; + }).join(' ')); + }, + + toString: function() { + return this.toArray().join(' '); + } +} + +Object.extend(Element.ClassNames.prototype, Enumerable); +var Field = { + clear: function() { + for (var i = 0; i < arguments.length; i++) + $(arguments[i]).value = ''; + }, + + focus: function(element) { + $(element).focus(); + }, + + present: function() { + for (var i = 0; i < arguments.length; i++) + if ($(arguments[i]).value == '') return false; + return true; + }, + + select: function(element) { + $(element).select(); + }, + + activate: function(element) { + element = $(element); + element.focus(); + if (element.select) + element.select(); + } +} + +/*--------------------------------------------------------------------------*/ + +var Form = { + serialize: function(form) { + var elements = Form.getElements($(form)); + var queryComponents = new Array(); + + for (var i = 0; i < elements.length; i++) { + var queryComponent = Form.Element.serialize(elements[i]); + if (queryComponent) + queryComponents.push(queryComponent); + } + + return queryComponents.join('&'); + }, + + getElements: function(form) { + form = $(form); + var elements = new Array(); + + for (tagName in Form.Element.Serializers) { + var tagElements = form.getElementsByTagName(tagName); + for (var j = 0; j < tagElements.length; j++) + elements.push(tagElements[j]); + } + return elements; + }, + + getInputs: function(form, typeName, name) { + form = $(form); + var inputs = form.getElementsByTagName('input'); + + if (!typeName && !name) + return inputs; + + var matchingInputs = new Array(); + for (var i = 0; i < inputs.length; i++) { + var input = inputs[i]; + if ((typeName && input.type != typeName) || + (name && input.name != name)) + continue; + matchingInputs.push(input); + } + + return matchingInputs; + }, + + disable: function(form) { + var elements = Form.getElements(form); + for (var i = 0; i < elements.length; i++) { + var element = elements[i]; + element.blur(); + element.disabled = 'true'; + } + }, + + enable: function(form) { + var elements = Form.getElements(form); + for (var i = 0; i < elements.length; i++) { + var element = elements[i]; + element.disabled = ''; + } + }, + + findFirstElement: function(form) { + return Form.getElements(form).find(function(element) { + return element.type != 'hidden' && !element.disabled && + ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); + }); + }, + + focusFirstElement: function(form) { + Field.activate(Form.findFirstElement(form)); + }, + + reset: function(form) { + $(form).reset(); + } +} + +Form.Element = { + serialize: function(element) { + element = $(element); + var method = element.tagName.toLowerCase(); + var parameter = Form.Element.Serializers[method](element); + + if (parameter) { + var key = encodeURIComponent(parameter[0]); + if (key.length == 0) return; + + if (parameter[1].constructor != Array) + parameter[1] = [parameter[1]]; + + return parameter[1].map(function(value) { + return key + '=' + encodeURIComponent(value); + }).join('&'); + } + }, + + getValue: function(element) { + element = $(element); + var method = element.tagName.toLowerCase(); + var parameter = Form.Element.Serializers[method](element); + + if (parameter) + return parameter[1]; + } +} + +Form.Element.Serializers = { + input: function(element) { + switch (element.type.toLowerCase()) { + case 'submit': + case 'hidden': + case 'password': + case 'text': + return Form.Element.Serializers.textarea(element); + case 'checkbox': + case 'radio': + return Form.Element.Serializers.inputSelector(element); + } + return false; + }, + + inputSelector: function(element) { + if (element.checked) + return [element.name, element.value]; + }, + + textarea: function(element) { + return [element.name, element.value]; + }, + + select: function(element) { + return Form.Element.Serializers[element.type == 'select-one' ? + 'selectOne' : 'selectMany'](element); + }, + + selectOne: function(element) { + var value = '', opt, index = element.selectedIndex; + if (index >= 0) { + opt = element.options[index]; + value = opt.value; + if (!value && !('value' in opt)) + value = opt.text; + } + return [element.name, value]; + }, + + selectMany: function(element) { + var value = new Array(); + for (var i = 0; i < element.length; i++) { + var opt = element.options[i]; + if (opt.selected) { + var optValue = opt.value; + if (!optValue && !('value' in opt)) + optValue = opt.text; + value.push(optValue); + } + } + return [element.name, value]; + } +} + +/*--------------------------------------------------------------------------*/ + +var $F = Form.Element.getValue; + +/*--------------------------------------------------------------------------*/ + +Abstract.TimedObserver = function() {} +Abstract.TimedObserver.prototype = { + initialize: function(element, frequency, callback) { + this.frequency = frequency; + this.element = $(element); + this.callback = callback; + + this.lastValue = this.getValue(); + this.registerCallback(); + }, + + registerCallback: function() { + setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); + }, + + onTimerEvent: function() { + var value = this.getValue(); + if (this.lastValue != value) { + this.callback(this.element, value); + this.lastValue = value; + } + } +} + +Form.Element.Observer = Class.create(); +Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { + getValue: function() { + return Form.Element.getValue(this.element); + } +}); + +Form.Observer = Class.create(); +Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { + getValue: function() { + return Form.serialize(this.element); + } +}); + +/*--------------------------------------------------------------------------*/ + +Abstract.EventObserver = function() {} +Abstract.EventObserver.prototype = { + 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() { + var elements = Form.getElements(this.element); + for (var i = 0; i < elements.length; i++) + this.registerCallback(elements[i]); + }, + + registerCallback: function(element) { + if (element.type) { + switch (element.type.toLowerCase()) { + case 'checkbox': + case 'radio': + Event.observe(element, 'click', this.onElementEvent.bind(this)); + break; + case 'password': + case 'text': + case 'textarea': + case 'select-one': + case 'select-multiple': + Event.observe(element, 'change', this.onElementEvent.bind(this)); + break; + } + } + } +} + +Form.Element.EventObserver = Class.create(); +Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { + getValue: function() { + return Form.Element.getValue(this.element); + } +}); + +Form.EventObserver = Class.create(); +Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { + getValue: function() { + return Form.serialize(this.element); + } +}); +if (!window.Event) { + var Event = new Object(); +} + +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, + + element: function(event) { + return event.target || event.srcElement; + }, + + isLeftClick: function(event) { + return (((event.which) && (event.which == 1)) || + ((event.button) && (event.button == 1))); + }, + + pointerX: function(event) { + return event.pageX || (event.clientX + + (document.documentElement.scrollLeft || document.body.scrollLeft)); + }, + + pointerY: function(event) { + return event.pageY || (event.clientY + + (document.documentElement.scrollTop || document.body.scrollTop)); + }, + + stop: function(event) { + if (event.preventDefault) { + event.preventDefault(); + event.stopPropagation(); + } else { + event.returnValue = false; + event.cancelBubble = true; + } + }, + + // find the first node with the given tagName, starting from the + // node the event was triggered on; traverses the DOM upwards + findElement: function(event, tagName) { + var element = Event.element(event); + while (element.parentNode && (!element.tagName || + (element.tagName.toUpperCase() != tagName.toUpperCase()))) + element = element.parentNode; + return element; + }, + + observers: false, + + _observeAndCache: function(element, name, observer, useCapture) { + if (!this.observers) this.observers = []; + if (element.addEventListener) { + this.observers.push([element, name, observer, useCapture]); + element.addEventListener(name, observer, useCapture); + } else if (element.attachEvent) { + this.observers.push([element, name, observer, useCapture]); + element.attachEvent('on' + name, observer); + } + }, + + unloadCache: function() { + if (!Event.observers) return; + for (var i = 0; i < Event.observers.length; i++) { + Event.stopObserving.apply(this, Event.observers[i]); + Event.observers[i][0] = null; + } + Event.observers = false; + }, + + observe: function(element, name, observer, useCapture) { + var element = $(element); + useCapture = useCapture || false; + + if (name == 'keypress' && + (navigator.appVersion.match(/Konqueror|Safari|KHTML/) + || element.attachEvent)) + name = 'keydown'; + + this._observeAndCache(element, name, observer, useCapture); + }, + + stopObserving: function(element, name, observer, useCapture) { + var element = $(element); + useCapture = useCapture || false; + + if (name == 'keypress' && + (navigator.appVersion.match(/Konqueror|Safari|KHTML/) + || element.detachEvent)) + name = 'keydown'; + + if (element.removeEventListener) { + element.removeEventListener(name, observer, useCapture); + } else if (element.detachEvent) { + element.detachEvent('on' + name, observer); + } + } +}); + +/* prevent memory leaks in IE */ +Event.observe(window, 'unload', Event.unloadCache, false); +var Position = { + // set to true if needed, warning: firefox performance problems + // NOT neeeded for page scrolling, only if draggable contained in + // scrollable elements + includeScrollOffsets: false, + + // must be called before calling withinIncludingScrolloffset, every time the + // page is scrolled + prepare: function() { + this.deltaX = window.pageXOffset + || document.documentElement.scrollLeft + || document.body.scrollLeft + || 0; + this.deltaY = window.pageYOffset + || document.documentElement.scrollTop + || document.body.scrollTop + || 0; + }, + + realOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.scrollTop || 0; + valueL += element.scrollLeft || 0; + element = element.parentNode; + } while (element); + return [valueL, valueT]; + }, + + cumulativeOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + } while (element); + return [valueL, valueT]; + }, + + positionedOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + if (element) { + p = Element.getStyle(element, 'position'); + if (p == 'relative' || p == 'absolute') break; + } + } while (element); + return [valueL, valueT]; + }, + + offsetParent: 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; + }, + + // caches x/y coordinate pair to use with overlap + within: function(element, x, y) { + if (this.includeScrollOffsets) + return this.withinIncludingScrolloffsets(element, x, y); + this.xcomp = x; + this.ycomp = y; + this.offset = this.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 = this.realOffset(element); + + this.xcomp = x + offsetcache[0] - this.deltaX; + this.ycomp = y + offsetcache[1] - this.deltaY; + this.offset = this.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); + }, + + // within must be called directly before + 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; + }, + + clone: function(source, target) { + source = $(source); + target = $(target); + target.style.position = 'absolute'; + var offsets = this.cumulativeOffset(source); + target.style.top = offsets[1] + 'px'; + target.style.left = offsets[0] + 'px'; + target.style.width = source.offsetWidth + 'px'; + target.style.height = source.offsetHeight + 'px'; + }, + + page: function(forElement) { + var valueT = 0, valueL = 0; + + var element = forElement; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + + // Safari fix + if (element.offsetParent==document.body) + if (Element.getStyle(element,'position')=='absolute') break; + + } while (element = element.offsetParent); + + element = forElement; + do { + valueT -= element.scrollTop || 0; + valueL -= element.scrollLeft || 0; + } while (element = element.parentNode); + + return [valueL, valueT]; + }, + + clone: function(source, target) { + var options = Object.extend({ + setLeft: true, + setTop: true, + setWidth: true, + setHeight: true, + offsetTop: 0, + offsetLeft: 0 + }, arguments[2] || {}) + + // find page position of source + source = $(source); + var p = Position.page(source); + + // find coordinate system to use + target = $(target); + var delta = [0, 0]; + var parent = null; + // delta [0,0] will do fine with position: fixed elements, + // position:absolute needs offsetParent deltas + if (Element.getStyle(target,'position') == 'absolute') { + parent = Position.offsetParent(target); + delta = Position.page(parent); + } + + // correct by body offsets (fixes Safari) + if (parent == document.body) { + delta[0] -= document.body.offsetLeft; + delta[1] -= document.body.offsetTop; + } + + // set position + if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; + if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; + if(options.setWidth) target.style.width = source.offsetWidth + 'px'; + if(options.setHeight) target.style.height = source.offsetHeight + 'px'; + }, + + absolutize: function(element) { + element = $(element); + if (element.style.position == 'absolute') return; + Position.prepare(); + + var offsets = Position.positionedOffset(element); + 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';; + }, + + relativize: function(element) { + element = $(element); + if (element.style.position == 'relative') return; + Position.prepare(); + + 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; + } +} + +// Safari returns margins on body which is incorrect if the child is absolutely +// positioned. For performance reasons, redefine Position.cumulativeOffset for +// KHTML/WebKit only. +if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) { + Position.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 [valueL, valueT]; + } +} + + +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; +} Added: trunk/data/public/js/pfcclient.js =================================================================== --- trunk/data/public/js/pfcclient.js (rev 0) +++ trunk/data/public/js/pfcclient.js 2006-12-21 06:34:20 UTC (rev 908) @@ -0,0 +1,1736 @@ +var is_ie = navigator.appName.match("Explorer"); +var is_khtml = navigator.appName.match("Konqueror") || navigator.appVersion.match("KHTML"); +var is_ff = navigator.appName.match("Netscape"); + +/** + * This class is the client part of phpFreeChat + * (depends on prototype library) + * @author Stephane Gully + */ +var pfcClient = Class.create(); + +//defining the rest of the class implmentation +pfcClient.prototype = { + + initialize: function() + { + // load the graphical user interface builder + this.gui = new pfcGui(); + // load the resources manager (labels and urls) + this.res = new pfcResource(); + + this.nickname = pfc_nickname; + this.nickid = pfc_nickid; + this.usermeta = $H(); + this.chanmeta = $H(); + this.nickwhoisbox = $H(); + + // this array contains all the sent command + // used the up and down key to navigate in the history + // (doesn't work on IE6) + 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.refresh_delay = pfc_refresh_delay; + this.max_refresh_delay = pfc_max_refresh_delay; + this.last_refresh_time = 0; + /* 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(); + }, ... [truncated message content] |
From: <ke...@us...> - 2007-01-05 13:34:38
|
Revision: 918 http://svn.sourceforge.net/phpfreechat/?rev=918&view=rev Author: kerphi Date: 2007-01-05 05:34:37 -0800 (Fri, 05 Jan 2007) Log Message: ----------- [en] Bug fix: cannot close the private chat tab if the chatter is disconnected [0h30] [fr] Bug fix : impossible de fermer l'onglet des messages priv?\195?\169s si l'autre chatteur est d?\195?\169connect?\195?\169 [0h30] Modified Paths: -------------- trunk/data/public/js/pfcclient.js trunk/data/public/js/pfcgui.js Modified: trunk/data/public/js/pfcclient.js =================================================================== --- trunk/data/public/js/pfcclient.js 2007-01-05 13:11:18 UTC (rev 917) +++ trunk/data/public/js/pfcclient.js 2007-01-05 13:34:37 UTC (rev 918) @@ -888,12 +888,12 @@ * Call the ajax request function * Will query the server */ - sendRequest: function(cmd) + sendRequest: function(cmd, recipientid) { if (pfc_debug) if (cmd != "/update") trace('sendRequest: '+cmd); var rx = new RegExp('(^\/[^ ]+) *(.*)','ig'); - var recipientid = this.gui.getTabId(); + if (!recipientid) recipientid = this.gui.getTabId(); cmd = cmd.replace(rx, '$1 '+this.clientid+' '+(recipientid==''?'0':recipientid)+' $2'); return eval('pfc_handleRequest(cmd);'); }, Modified: trunk/data/public/js/pfcgui.js =================================================================== --- trunk/data/public/js/pfcgui.js 2007-01-05 13:11:18 UTC (rev 917) +++ trunk/data/public/js/pfcgui.js 2007-01-05 13:34:37 UTC (rev 918) @@ -255,7 +255,7 @@ a2.onclick = function(){ var res = confirm(pfc.res.getLabel('Do you really want to leave this room ?')); if (res == true) - pfc.sendRequest('/leave '+this.pfc_tabtype+' "'+this.pfc_tabname+'"'); + pfc.sendRequest('/leave',this.pfc_tabid); return false; } a2.alt = pfc.res.getLabel('Close this tab'); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ke...@us...> - 2007-02-20 08:23:37
|
Revision: 972 http://svn.sourceforge.net/phpfreechat/?rev=972&view=rev Author: kerphi Date: 2007-02-20 00:23:37 -0800 (Tue, 20 Feb 2007) Log Message: ----------- [en] Bug fix: the focus was lost in the new prompt dialog box [0h40] [fr] Bug fix : le focus ?\195?\169tait perdu dans la boite de dialogue demandant le pseudo [0h40] Modified Paths: -------------- trunk/data/public/js/pfcclient.js trunk/data/public/js/pfcprompt.js Modified: trunk/data/public/js/pfcclient.js =================================================================== --- trunk/data/public/js/pfcclient.js 2007-02-19 16:33:16 UTC (rev 971) +++ trunk/data/public/js/pfcclient.js 2007-02-20 08:23:37 UTC (rev 972) @@ -80,9 +80,6 @@ Event.observe(this.el_words, 'focus', this.callbackWords_OnFocus.bindAsEventListener(this), false); Event.observe(this.el_handle, 'keydown', this.callbackHandle_OnKeydown.bindAsEventListener(this), false); Event.observe(this.el_handle, 'change', this.callbackHandle_OnChange.bindAsEventListener(this), false); - Event.observe(this.el_container, 'mousemove', this.callbackContainer_OnMousemove.bindAsEventListener(this), false); - Event.observe(this.el_container, 'mousedown', this.callbackContainer_OnMousedown.bindAsEventListener(this), false); - Event.observe(this.el_container, 'mouseup', this.callbackContainer_OnMouseup.bindAsEventListener(this), false); Event.observe(document.body, 'unload', this.callback_OnUnload.bindAsEventListener(this), false); }, @@ -699,22 +696,6 @@ } }, - callbackContainer_OnMousemove: function(evt) - { - this.isdraging = true; - }, - callbackContainer_OnMousedown: function(evt) - { - if ( ((is_ie || is_khtml) && evt.button == 1) || (is_ff && evt.button == 0) ) - this.isdraging = false; - }, - callbackContainer_OnMouseup: function(evt) - { - if ( ((is_ie || is_khtml) && evt.button == 1) || (is_ff && evt.button == 0) ) - if (!this.isdraging) - if (this.el_words && !this.minmax_status) - this.el_words.focus(); - }, /** * hide error area and stop blinking fields Modified: trunk/data/public/js/pfcprompt.js =================================================================== --- trunk/data/public/js/pfcprompt.js 2007-02-19 16:33:16 UTC (rev 971) +++ trunk/data/public/js/pfcprompt.js 2007-02-20 08:23:37 UTC (rev 972) @@ -25,7 +25,7 @@ this.box.id = 'pfc_promptbox'; this.box.style.position = 'absolute'; this.box.style.width = '330px'; - this.box.style.zIndex = '100'; + this.box.style.zIndex = 100; this.box.style.display = 'none'; var div = document.createElement('h2'); @@ -83,7 +83,7 @@ this.bgbox.style.filter = 'alpha(opacity=70)'; // this.bgbox.style.height = (document.body.offsetHeight<screen.height) ? screen.height+'px' : document.body.offsetHeight+20+'px'; this.bgbox.style.display = 'none'; - this.bgbox.style.zIndex = '50'; + this.bgbox.style.zIndex = 50; this.container.appendChild(this.bgbox); } }, This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <gpi...@us...> - 2007-08-12 04:27:13
|
Revision: 1116 http://phpfreechat.svn.sourceforge.net/phpfreechat/?rev=1116&view=rev Author: gpinzone Date: 2007-08-11 21:27:16 -0700 (Sat, 11 Aug 2007) Log Message: ----------- pfcclient.js: Major browser compatibility updates for Nickname completion. Safari and Opera work as well as IE and Firefox. Documented all known issues with Konqueror. pfcprompt.js: Forgot to change is_ff to is_gecko. Fixed. Modified Paths: -------------- trunk/data/public/js/pfcclient.js trunk/data/public/js/pfcprompt.js Modified: trunk/data/public/js/pfcclient.js =================================================================== --- trunk/data/public/js/pfcclient.js 2007-08-11 06:41:57 UTC (rev 1115) +++ trunk/data/public/js/pfcclient.js 2007-08-12 04:27:16 UTC (rev 1116) @@ -1,3 +1,4 @@ +// Browser detection mostly taken from prototype.js 1.5.1.1. 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; @@ -189,7 +190,6 @@ trace('handleResponse: '+cmd + "-"+resp+"-"+param); } - // store the new refresh time this.last_response_time = new Date().getTime(); @@ -321,10 +321,10 @@ } else if (resp == "notallowed") { - // when frozen_nick is true and the nickname is allready used, server will return + // When frozen_nick is true and the nickname is already used, server will return // the 'notallowed' status. It will display a message and stop chat update. - // if the chat update is not stopped, this will loop forever - // as long as the forced nickname is not changed + // If the chat update is not stopped, this will loop forever + // as long as the forced nickname is not changed. // display a message this.setError(this.res.getLabel('Choosen nickname is not allowed'), Array()); @@ -556,32 +556,32 @@ var w = this.el_words; var wval = w.value; - // append the string to the history + // Append the string to the history. this.cmdhistory.push(wval); this.cmdhistoryid = this.cmdhistory.length; this.cmdhistoryissearching = false; - // send the string to the server + // Send the string to the server. re = new RegExp("^(\/[a-zA-Z0-9]+)( (.*)|)"); if (wval.match(re)) { - // a user command + // A user command. 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 { - // a classic 'send' command + // A classic 'send' command. - // empty messages with only spaces + // Empty messages with only spaces. rx = new RegExp('^[ ]*$','g'); wval = wval.replace(rx,''); - // truncate the text length + // Truncate the text length. wval = wval.substr(0,pfc_max_text_len); - // colorize the text with current_text_color + // Colorize the text with current_text_color. if (this.current_text_color != '' && wval.length != '') wval = '[color=#' + this.current_text_color + '] ' + wval + ' [/color]'; @@ -592,19 +592,19 @@ }, /** - * Try to complete a nickname like on IRC when pressing the TAB key - * Nicks with spaces may not work under certain circumstances - * Replacing standards spaces with alternate spaces (e.g., ) helps - * Gecko browsers convert the to regular spaces - * TODO: Move cursor to end of line after nick completion in Konqueror and Webkit browsers - * Note: IRC does not allow nicks with spaces + * 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., ) helps. + * Gecko browsers convert the 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 last_space = w.value.lastIndexOf(' '); var nick_src = w.value.substring(last_space+1, w.value.length); - var non_nick_src = w.value.substring(0,last_space+1); + var non_nick_src = w.value.substring(0, last_space+1); if (nick_src != '') { @@ -641,12 +641,13 @@ w.value = non_nick_src + nick_src.replace(nick_src, nick_replace); } }, + /** * Cycle to older entry in history */ historyUp: function() { - // write the previous command in the history + // Write the previous command in the history. if (this.cmdhistory.length > 0) { var w = this.el_words; @@ -665,7 +666,7 @@ */ historyDown: function() { - // write the next command in the history + // Write the next command in the history. if (this.cmdhistory.length > 0) { var w = this.el_words; @@ -684,32 +685,26 @@ }, /** - * Handle the pressed keys + * Handle the pressed keys. * see also callbackWords_OnKeydown */ callbackWords_OnKeypress: function(evt) { - // All browsers except for IE should use evt.which + // All browsers except for IE should use "evt.which." var code = (evt.which) ? evt.which : evt.keyCode; - if (code == Event.KEY_TAB) /* tab key */ + if (code == Event.KEY_RETURN) /* ENTER key */ { - /* FF & Konqueror workaround : ignore TAB key here */ - /* do the nickname completion work like on IRC */ - this.completeNick(); - return false; /* do not leave the tab key default behavior */ - } - else if (code == Event.KEY_RETURN) /* enter key */ - { return this.doSendMessage(); } else { - /* allow other keys */ + // Allow other key defaults. return true; } }, + /** - * Handle the pressed keys + * Handle the pressed keys. * see also callbackWords_OnKeypress * WARNING: Suppressing defaults on the keydown event * may prevent keypress and/or keyup events @@ -720,31 +715,69 @@ if (!this.isconnected) return false; this.clearError(Array(this.el_words)); var code = (evt.which) ? evt.which : evt.keyCode - if (code == 9) /* tab key */ + if (code == 38 && (is_gecko || is_ie || is_opera || is_webkit)) // up arrow key { - /* IE workaround : ignore TAB key here */ - /* do the nickname completion work like on IRC */ - this.completeNick(); - return false; /* do not leave the tab key default behavior */ - } - else if (code == 38 && (is_gecko || is_ie || is_opera || is_webkit)) // up arrow key - { - /* TODO: Fix up arrow issue in Opera */ - // Konqueror does not work due to keycode conflicts - // write the previous command in the history + /* 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. */ + + // Write the previous command in the history. this.historyUp(); - return false; // do not leave the tab key default behavior + + if (evt.returnValue) // IE + evt.returnValue = false; + if (evt.preventDefault) // DOM + evt.preventDefault(); + return false; // should work in all browsers } else if (code == 40 && (is_gecko || is_ie || is_opera || is_webkit)) // down arrow key { - // Konqueror does not work due to keycode conflicts - // write the next command in the history + /* Konqueror cannot use this feature due to keycode conflicts. */ + + // Write the previous command in the history. this.historyDown(); - return false; // do not leave the tab key default behavior + + if (evt.returnValue) // IE + evt.returnValue = false; + if (evt.preventDefault) // DOM + evt.preventDefault(); + return false; // should work in all browsers } + else if (code == 9) /* TAB key */ + { + /* Konqueror has the same problem as Webkit (Safari), + but setSelectionRange() won't work on + KDE versions <3.5.2. Therefore, I'm leaving + the Webkit fix out for these browsers. */ + + // Do nickname completion like on IRC / Unix command line. + this.completeNick(); + + var tb = evt.srcElement || evt.target; + if (is_webkit) + { + // Move cursor to end of line for Webkit (Safari). + var selEnd = this.el_words.value.length; + tb.setSelectionRange(selEnd, selEnd); + } + if (is_opera) + { + // Fixes Opera's loss of focus after TAB key is pressed. + // This is most likely due to a bug in Opera + // that executes the default key operation BEFORE the + // keydown and keypress event handler. + // This is probably the reason for the "up arrow" issue above. + window.setTimeout(function(){tb.focus();}, 0); + } + + if (evt.returnValue) // IE + evt.returnValue = false; + if (evt.preventDefault) // DOM + evt.preventDefault(); + return false; // Should work in all browsers. + } else { - /* allow other keys */ + // Allow other key defaults. return true; } }, Modified: trunk/data/public/js/pfcprompt.js =================================================================== --- trunk/data/public/js/pfcprompt.js 2007-08-11 06:41:57 UTC (rev 1115) +++ trunk/data/public/js/pfcprompt.js 2007-08-12 04:27:16 UTC (rev 1116) @@ -27,7 +27,7 @@ this.box.style.zIndex = 100; this.box.style.display = 'none'; - if (is_ff) { + if (is_gecko) { this.box.style.overflow = 'auto'; } @@ -119,7 +119,7 @@ { // _doSubmit is called when the user enters or cancels the box. var val = this.prompt_field.value; - if (is_ff) this.box.focus(); // test is_ff because it doesn't work on KHTML browser, the popup shows infinitly + if (is_gecko) this.box.focus(); // test is_ff because it doesn't work on KHTML browser, the popup shows infinitly this.box.style.display = 'none'; // clear out the dialog box this.bgbox.style.display = 'none'; // clear out the screen this.prompt_field.value = ''; // clear out the text field This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <gpi...@us...> - 2007-09-06 14:30:25
|
Revision: 1178 http://phpfreechat.svn.sourceforge.net/phpfreechat/?rev=1178&view=rev Author: gpinzone Date: 2007-09-06 07:30:28 -0700 (Thu, 06 Sep 2007) Log Message: ----------- Made variable and function names clearer. Modified Paths: -------------- trunk/data/public/js/pfcclient.js trunk/data/public/js/pfcresource.js Modified: trunk/data/public/js/pfcclient.js =================================================================== --- trunk/data/public/js/pfcclient.js 2007-09-06 14:11:45 UTC (rev 1177) +++ trunk/data/public/js/pfcclient.js 2007-09-06 14:30:28 UTC (rev 1178) @@ -1460,7 +1460,7 @@ // try to parse smileys var smileys = this.res.getSmileyHash(); - var sl = this.res.getSmileyKeys(); + var sl = this.res.getSmileyKeysSorted(); for(var i = 0; i < sl.length; i++) { // We don't want to replace smiley strings inside of tags. Modified: trunk/data/public/js/pfcresource.js =================================================================== --- trunk/data/public/js/pfcresource.js 2007-09-06 14:11:45 UTC (rev 1177) +++ trunk/data/public/js/pfcresource.js 2007-09-06 14:30:28 UTC (rev 1178) @@ -12,7 +12,7 @@ this.fileurl = $H(); this.smileys = $H(); this.smileysreverse = $H(); - this.smileyskeys = new Array(); + this.smileyskeyssorted = new Array(); }, setLabel: function(key, value) @@ -49,9 +49,9 @@ { this.smileys[key] = value; this.smileysreverse[value] = key; - this.smileyskeys.push(key); + this.smileyskeyssorted.push(key); // Sort keys by longest to shortest. This prevents a smiley like :) from being used on >:) - this.smileyskeys = this.smileyskeys.sort(function (a,b){return (b.unescapeHTML().length - a.unescapeHTML().length);}) + this.smileyskeyssorted.sort(function (a,b){return (b.unescapeHTML().length - a.unescapeHTML().length);}) }, getSmiley: function(key) { @@ -68,9 +68,9 @@ { return this.smileysreverse; }, - getSmileyKeys: function() + getSmileyKeysSorted: function() { - return this.smileyskeys; + return this.smileyskeyssorted; }, }; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <gpi...@us...> - 2007-09-06 17:08:59
|
Revision: 1181 http://phpfreechat.svn.sourceforge.net/phpfreechat/?rev=1181&view=rev Author: gpinzone Date: 2007-09-06 10:09:01 -0700 (Thu, 06 Sep 2007) Log Message: ----------- Move sort to loadSmileyBox(). Modified Paths: -------------- trunk/data/public/js/pfcclient.js trunk/data/public/js/pfcgui.js trunk/data/public/js/pfcresource.js Modified: trunk/data/public/js/pfcclient.js =================================================================== --- trunk/data/public/js/pfcclient.js 2007-09-06 15:39:43 UTC (rev 1180) +++ trunk/data/public/js/pfcclient.js 2007-09-06 17:09:01 UTC (rev 1181) @@ -1460,7 +1460,7 @@ // try to parse smileys var smileys = this.res.getSmileyHash(); - var sl = this.res.getSmileyKeysSorted(); + var sl = this.res.getSmileyKeys(); // Keys should be sorted by length from pfc.gui.loadSmileyBox() for(var i = 0; i < sl.length; i++) { // We don't want to replace smiley strings inside of tags. Modified: trunk/data/public/js/pfcgui.js =================================================================== --- trunk/data/public/js/pfcgui.js 2007-09-06 15:39:43 UTC (rev 1180) +++ trunk/data/public/js/pfcgui.js 2007-09-06 17:09:01 UTC (rev 1181) @@ -402,17 +402,17 @@ var container = $('pfc_smileys'); var smileys = pfc.res.getSmileyReverseHash();//getSmileyHash(); var sl = smileys.keys(); + pfc.res.sortSmileyKeys(); // Sort smiley keys once. for(var i = 0; i < sl.length; i++) { s_url = sl[i]; s_symbol = smileys[sl[i]]; s_symbol = s_symbol.unescapeHTML(); // Replace " with " for IE and Webkit browsers. - // The prototype.js version 1.5.1.1 does not do this. - // IE and Webkit detection from prototype.js - if (window.attachEvent && !window.opera || navigator.userAgent.indexOf('AppleWebKit/') > -1) + // The prototype.js version 1.5.1.1 unescapeHTML() function does not do this. + if (is_ie || is_webkit) s_symbol = s_symbol.replace(/"/g,'"'); - + var img = document.createElement('img'); img.setAttribute('src', s_url); img.setAttribute('alt', s_symbol); @@ -764,5 +764,5 @@ soundcontainerbox.setAttribute('id', 'pfc_sound_container'); container.appendChild(soundcontainerbox); */ - } + } }; Modified: trunk/data/public/js/pfcresource.js =================================================================== --- trunk/data/public/js/pfcresource.js 2007-09-06 15:39:43 UTC (rev 1180) +++ trunk/data/public/js/pfcresource.js 2007-09-06 17:09:01 UTC (rev 1181) @@ -12,7 +12,7 @@ this.fileurl = $H(); this.smileys = $H(); this.smileysreverse = $H(); - this.smileyskeyssorted = new Array(); + this.smileyskeys = new Array(); }, setLabel: function(key, value) @@ -49,9 +49,7 @@ { this.smileys[key] = value; this.smileysreverse[value] = key; - //this.smileyskeyssorted.push(key); - // Sort keys by longest to shortest. This prevents a smiley like :) from being used on >:) - this.smileyskeyssorted.sort(function (a,b){return (b.unescapeHTML().length - a.unescapeHTML().length);}) + this.smileyskeys.push(key); }, getSmiley: function(key) { @@ -68,11 +66,31 @@ { return this.smileysreverse; }, - getSmileyKeysSorted: function() + getSmileyKeys: function() { - return this.smileyskeyssorted; + return this.smileyskeys; + }, + sortSmileyKeys: function() + { + // Sort keys by longest to shortest. This prevents a smiley like :) from being used on >:) + return this.smileyskeys.sort( + function (a,b) + { + a = a.unescapeHTML(); + b = b.unescapeHTML(); + + // Replace " with " for IE and Webkit browsers. + // The prototype.js version 1.5.1.1 unescapeHTML() function does not do this. + if (is_ie || is_webkit) + { + a = a.replace(/"/g,'"'); + b = b.replace(/"/g,'"'); + } + + return (b.length - a.length); + } + ); } - }; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <gpi...@us...> - 2007-08-16 13:04:46
|
Revision: 1126 http://phpfreechat.svn.sourceforge.net/phpfreechat/?rev=1126&view=rev Author: gpinzone Date: 2007-08-16 06:04:48 -0700 (Thu, 16 Aug 2007) Log Message: ----------- Minor documentation updates. No change in functionality. Modified Paths: -------------- trunk/data/public/js/pfcclient.js trunk/data/public/js/pfcprompt.js Modified: trunk/data/public/js/pfcclient.js =================================================================== --- trunk/data/public/js/pfcclient.js 2007-08-15 19:35:55 UTC (rev 1125) +++ trunk/data/public/js/pfcclient.js 2007-08-16 13:04:48 UTC (rev 1126) @@ -31,7 +31,6 @@ // this array contains all the sent commands // use the up and down arrow key to navigate through the history - // may not work in Safari 1.3 this.cmdhistory = Array(); this.cmdhistoryid = -1; this.cmdhistoryissearching = false; @@ -1071,6 +1070,8 @@ // supports the Gecko selection model. However, these values may be // useful for debugging. Also, Opera recognizes Gecko and IE range // commands, so we need to ensure Opera only uses the Gecko model. + /* WARNING: Do not use this for textareas. They require a more + complex algorithm. */ if (obj.setSelectionRange) { obj.selStart = obj.selectionStart; @@ -1141,7 +1142,6 @@ /** * insert a smiley - * TODO: Merge functionality into "insert_text" function and eliminate. */ insertSmiley: function(smiley) { Modified: trunk/data/public/js/pfcprompt.js =================================================================== --- trunk/data/public/js/pfcprompt.js 2007-08-15 19:35:55 UTC (rev 1125) +++ trunk/data/public/js/pfcprompt.js 2007-08-16 13:04:48 UTC (rev 1126) @@ -119,7 +119,7 @@ { // _doSubmit is called when the user enters or cancels the box. var val = this.prompt_field.value; - if (is_gecko) this.box.focus(); // test is_ff because it doesn't work on KHTML browser, the popup shows infinitly + if (is_gecko) this.box.focus(); // test is_gecko because it doesn't work on KHTML browser, the popup shows infinitly this.box.style.display = 'none'; // clear out the dialog box this.bgbox.style.display = 'none'; // clear out the screen this.prompt_field.value = ''; // clear out the text field This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <gpi...@us...> - 2007-09-06 14:11:43
|
Revision: 1177 http://phpfreechat.svn.sourceforge.net/phpfreechat/?rev=1177&view=rev Author: gpinzone Date: 2007-09-06 07:11:45 -0700 (Thu, 06 Sep 2007) Log Message: ----------- Smiley key sorting caused performance problems on clients. Created new array for smiley keys and sort it during setSmiley() function calls. Modified Paths: -------------- trunk/data/public/js/pfcclient.js trunk/data/public/js/pfcresource.js Modified: trunk/data/public/js/pfcclient.js =================================================================== --- trunk/data/public/js/pfcclient.js 2007-09-03 14:16:03 UTC (rev 1176) +++ trunk/data/public/js/pfcclient.js 2007-09-06 14:11:45 UTC (rev 1177) @@ -1460,8 +1460,7 @@ // try to parse smileys var smileys = this.res.getSmileyHash(); - // Sort keys by longest to shortest. This prevents a smiley like :) from being used on >:) - var sl = smileys.keys().sort(function (a,b){return (b.unescapeHTML().length - a.unescapeHTML().length);}); + var sl = this.res.getSmileyKeys(); for(var i = 0; i < sl.length; i++) { // We don't want to replace smiley strings inside of tags. Modified: trunk/data/public/js/pfcresource.js =================================================================== --- trunk/data/public/js/pfcresource.js 2007-09-03 14:16:03 UTC (rev 1176) +++ trunk/data/public/js/pfcresource.js 2007-09-06 14:11:45 UTC (rev 1177) @@ -12,6 +12,7 @@ this.fileurl = $H(); this.smileys = $H(); this.smileysreverse = $H(); + this.smileyskeys = new Array(); }, setLabel: function(key, value) @@ -48,6 +49,9 @@ { this.smileys[key] = value; this.smileysreverse[value] = key; + this.smileyskeys.push(key); + // Sort keys by longest to shortest. This prevents a smiley like :) from being used on >:) + this.smileyskeys = this.smileyskeys.sort(function (a,b){return (b.unescapeHTML().length - a.unescapeHTML().length);}) }, getSmiley: function(key) { @@ -63,7 +67,11 @@ getSmileyReverseHash: function() { return this.smileysreverse; - } + }, + getSmileyKeys: function() + { + return this.smileyskeys; + }, }; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |