1// Browser detection mostly taken from prototype.js 1.5.1.1. 2var is_ie = !!(window.attachEvent && !window.opera); 3var is_khtml = !!(navigator.appName.match("Konqueror") || navigator.appVersion.match("KHTML")); 4var is_gecko = navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1; 5var is_ie7 = navigator.userAgent.indexOf('MSIE 7') > 0; 6var is_ie6 = navigator.userAgent.indexOf('MSIE 6') > 0; 7var is_opera = !!window.opera; 8var is_webkit = navigator.userAgent.indexOf('AppleWebKit/') > -1; 9 10/** 11 * This class is the client part of phpFreeChat 12 * (depends on prototype library) 13 * @author Stephane Gully 14 */ 15var pfcClient = Class.create(); 16 17//defining the rest of the class implmentation 18pfcClient.prototype = { 19 20 initialize: function() 21 { 22 // load the graphical user interface builder 23 this.gui = new pfcGui(); 24 // load the resources manager (labels and urls) 25 this.res = new pfcResource(); 26 27 this.nickname = pfc_nickname; 28 this.nickid = pfc_nickid; 29 this.usermeta = $H(); 30 this.chanmeta = $H(); 31 this.nickwhoisbox = $H(); 32 33 // this array contains all the sent commands 34 // use the up and down arrow key to navigate through the history 35 this.cmdhistory = Array(); 36 this.cmdhistoryid = -1; 37 this.cmdhistoryissearching = false; 38 39 /* 40 this.channels = Array(); 41 this.channelids = Array(); 42 */ 43 this.privmsgs = Array(); 44 this.privmsgids = Array(); 45 46 this.timeout = null; 47 this.timeout_time = new Date().getTime(); 48 49 this.refresh_delay = pfc_refresh_delay; 50 this.refresh_delay_steps = pfc_refresh_delay_steps; 51 this.last_response_time = new Date().getTime(); 52 this.last_request_time = new Date().getTime(); 53 this.last_activity_time = new Date().getTime(); 54 55 /* unique client id for each windows used to identify a open window 56 * this id is passed every time the JS communicate with server 57 * (2 clients can use the same session: then only the nickname is shared) */ 58 this.clientid = pfc_clientid; 59 60 this.isconnected = false; 61 this.nicklist = $H(); 62 this.nickcolor = Array(); 63 this.colorlist = Array(); 64 65 this.blinktmp = Array(); 66 this.blinkloop = Array(); 67 this.blinktimeout = Array(); 68 }, 69 70 loadChat: function() { 71 new Ajax.Request(pfc_server_script_url, { 72 method: 'get', 73 parameters: {pfc_ajax: 1, f: 'loadChat'}, 74 onSuccess: function(transport) { 75 eval( transport.responseText ); 76 } 77 }); 78 }, 79 80 connectListener: function() 81 { 82 this.el_words = $('pfc_words'); 83 this.el_handle = $('pfc_handle'); 84 this.el_container = $('pfc_container'); 85// this.el_online = $('pfc_online'); 86 this.el_errors = $('pfc_errors'); 87 88 this.detectactivity = new DetectActivity(this.el_container); 89 // restore the window title when user come back to the active zone 90 if (pfc_notify_window) this.detectactivity.onunactivate = this.gui.unnotifyWindow.bindAsEventListener(this.gui); 91 92 /* the events callbacks */ 93 this.el_words.onkeypress = this.callbackWords_OnKeypress.bindAsEventListener(this); 94// don't use this line because when doing completeNick the "return false" doesn't work (focus is lost) 95// Event.observe(this.el_words, 'keypress', this.callbackWords_OnKeypress.bindAsEventListener(this), false); 96 Event.observe(this.el_words, 'keydown', this.callbackWords_OnKeydown.bindAsEventListener(this), false); 97 Event.observe(this.el_words, 'keyup', this.callbackWords_OnKeyup.bindAsEventListener(this), false); 98 Event.observe(this.el_words, 'mouseup', this.callbackWords_OnMouseup.bindAsEventListener(this), false); 99 Event.observe(this.el_words, 'focus', this.callbackWords_OnFocus.bindAsEventListener(this), false); 100 Event.observe(document.body, 'unload', this.callback_OnUnload.bindAsEventListener(this), false); 101 }, 102 103 refreshGUI: function() 104 { 105 this.minmax_status = pfc_start_minimized; 106 var cookie = getCookie('pfc_minmax_status'); 107 if (cookie != null) 108 this.minmax_status = (cookie == 'true'); 109 110 cookie = getCookie('pfc_nickmarker'); 111 this.nickmarker = (cookie == 'true'); 112 if (cookie == '' || cookie == null) 113 this.nickmarker = pfc_nickmarker; 114 115 cookie = getCookie('pfc_clock'); 116 this.clock = (cookie == 'true'); 117 if (cookie == '' || cookie == null) 118 this.clock = pfc_clock; 119 120 cookie = getCookie('pfc_showsmileys'); 121 this.showsmileys = (cookie == 'true'); 122 if (cookie == '' || cookie == null) 123 this.showsmileys = pfc_showsmileys; 124 125 cookie = getCookie('pfc_showwhosonline'); 126 this.showwhosonline = (cookie == 'true'); 127 if (cookie == '' || cookie == null) 128 this.showwhosonline = pfc_showwhosonline; 129 130 // '' means no forced color, let CSS choose the text color 131 this.current_text_color = ''; 132 cookie = getCookie('pfc_current_text_color'); 133 if (cookie != null) 134 this.switch_text_color(cookie); 135 136 cookie = getCookie('pfc_issoundenable'); 137 this.issoundenable = (cookie == 'true'); 138 if (cookie == '' || cookie == null) 139 this.issoundenable = pfc_startwithsound; 140 141 this.refresh_loginlogout(); 142 this.refresh_minimize_maximize(); 143 this.refresh_Smileys(); 144 this.refresh_sound(); 145 this.refresh_nickmarker(); 146 }, 147 148 /** 149 * Show a popup dialog to ask user to choose a nickname 150 */ 151 askNick: function(nickname,error_text) 152 { 153 // ask to choose a nickname 154 if (nickname == '' || nickname == undefined) nickname = this.nickname; 155 156 // build a dhtml prompt box 157 var pfcp = this.getPrompt();//new pfcPrompt($('pfc_container')); 158 pfcp.callback = function(v) { pfc.askNickResponse(v); } 159 pfcp.prompt((error_text != undefined ? '<span style="color:red">'+error_text+'</span><br/>' : '')+this.res.getLabel('Please enter your nickname'), nickname); 160 pfcp.focus(); 161 }, 162 askNickResponse: function(newnick) 163 { 164 if (newnick) 165 { 166 if (this.isconnected) 167 this.sendRequest('/nick "'+newnick+'"'); 168 else 169 this.sendRequest('/connect "'+newnick+'"'); 170 } 171 }, 172 173 /** 174 * Reacte to the server response 175 */ 176 handleResponse: function(cmd, resp, param) 177 { 178 // display some debug messages 179 if (pfc_debug) 180 if (cmd != "update") 181 { 182 var param2 = param; 183 if (cmd == "who" || cmd == "who2") 184 { 185 param2 = $H(param2); 186 param2.set('meta', $H(param2.get('meta'))); 187 param2.get('meta').set('users', $H(param2.get('meta').get('users'))); 188 trace('handleResponse: '+cmd + "-"+resp+"-"+param2.inspect()); 189 } 190 else 191 if (cmd == "whois" || cmd == "whois2") 192 { 193 param2 = $H(param2); 194 trace('handleResponse: '+cmd + "-"+resp+"-"+param2.inspect()); 195 } 196 else 197 if (cmd == "getnewmsg" || cmd == "join") 198 { 199 param2 = $A(param2); 200 trace('handleResponse: '+cmd + "-"+resp+"-"+param2.inspect()); 201 } 202 else 203 trace('handleResponse: '+cmd + "-"+resp+"-"+param); 204 } 205 206 if (cmd != "update") 207 { 208 // speed up timeout if activity 209 this.last_activity_time = new Date().getTime(); 210 var delay = this.calcDelay(); 211 if (this.timeout_time - new Date().getTime() > delay) 212 { 213 clearTimeout(this.timeout); 214 this.timeout = setTimeout('pfc.updateChat(true)', delay); 215 this.timeout_time = new Date().getTime() + delay; 216 } 217 } 218 219 if (cmd == "connect") 220 { 221 if (resp == "ok") 222 { 223 this.nickname = param[0]; 224 this.isconnected = true; 225 226 // start the polling system 227 this.updateChat(true); 228 } 229 else 230 this.isconnected = false; 231 this.refresh_loginlogout(); 232 } 233 else if (cmd == "quit") 234 { 235 if (resp =="ok") 236 { 237 // stop updates 238 this.updateChat(false); 239 this.isconnected = false; 240 this.refresh_loginlogout(); 241 } 242 } 243 else if (cmd == "join" || cmd == "join2") 244 { 245 if (resp =="ok") 246 { 247 // create the new channel 248 var tabid = param[0]; 249 var name = param[1]; 250 this.gui.createTab(name, tabid, "ch"); 251 if (cmd != "join2" || this.gui.tabs.length == 1) this.gui.setTabById(tabid); 252 this.refresh_Smileys(); 253 this.refresh_WhosOnline(); 254 } 255 else if (resp == "max_channels") 256 { 257 this.displayMsg( cmd, this.res.getLabel('Maximum number of joined channels has been reached') ); 258 } 259 else 260 alert(cmd + "-"+resp+"-"+param); 261 } 262 else if (cmd == "leave") 263 { 264 if (resp =="ok") 265 { 266 // remove the channel 267 var tabid = param; 268 this.gui.removeTabById(tabid); 269 270 // synchronize the channel client arrays 271 /* 272 var index = -1; 273 index = this.channelids.indexOf(tabid); 274 this.channelids = this.channelids.without(tabid); 275 this.channels = this.channels.without(this.channels[index]); 276 */ 277 278 // synchronize the privmsg client arrays 279 index = -1; 280 index = indexOf(this.privmsgids, tabid); 281 this.privmsgids = without(this.privmsgids, tabid); 282 this.privmsgs = without(this.privmsgs, this.privmsgs[index]); 283 284 } 285 } 286 else if (cmd == "privmsg" || cmd == "privmsg2") 287 { 288 if (resp == "ok") 289 { 290 // create the new channel 291 var tabid = param[0]; 292 var name = param[1]; 293 this.gui.createTab(name, tabid, "pv"); 294 if (cmd != "privmsg2" || this.gui.tabs.length == 1) this.gui.setTabById(tabid); 295 296 this.privmsgs.push(name); 297 this.privmsgids.push(tabid); 298 299 } 300 else if (resp == "max_privmsg") 301 { 302 this.displayMsg( cmd, this.res.getLabel('Maximum number of private chat has been reached') ); 303 } 304 else if (resp == "unknown") 305 { 306 // speak to unknown user 307 this.displayMsg( cmd, this.res.getLabel('You are trying to speak to a unknown (or not connected) user') ); 308 } 309 else if (resp == "speak_to_myself") 310 { 311 this.displayMsg( cmd, this.res.getLabel('You are not allowed to speak to yourself') ); 312 } 313 else 314 alert(cmd + "-"+resp+"-"+param); 315 } 316 else if (cmd == "nick") 317 { 318 // give focus the the input text box if wanted 319 if (pfc_focus_on_connect) this.el_words.focus(); 320 321 if (resp == "connected" || resp == "notchanged") 322 { 323 cmd = ''; 324 } 325 326 if (resp == "ok" || resp == "notchanged" || resp == "changed" || resp == "connected") 327 { 328 this.setUserMeta(this.nickid, 'nick', param); 329 this.el_handle.innerHTML = this.getUserMeta(this.nickid, 'nick').escapeHTML(); 330 this.nickname = this.getUserMeta(this.nickid, 'nick'); 331 this.updateNickBox(this.nickid); 332 333 // clear the possible error box generated by the bellow displayMsg(...) function 334 this.clearError(Array(this.el_words)); 335 } 336 else if (resp == "isused") 337 { 338 this.setError(this.res.getLabel('Chosen nickname is already used'), Array()); 339 this.askNick(param,this.res.getLabel('Chosen nickname is already used')); 340 } 341 else if (resp == "notallowed") 342 { 343 // When frozen_nick is true and the nickname is already used, server will return 344 // the 'notallowed' status. It will display a message and stop chat update. 345 // If the chat update is not stopped, this will loop forever 346 // as long as the forced nickname is not changed. 347 348 // display a message 349 this.setError(this.res.getLabel('Chosen nickname is not allowed'), Array()); 350 // then stop chat updates 351 this.updateChat(false); 352 this.isconnected = false; 353 this.refresh_loginlogout(); 354 } 355 } 356 else if (cmd == "update") 357 { 358 } 359 else if (cmd == "version") 360 { 361 if (resp == "ok") 362 { 363 this.displayMsg( cmd, this.res.getLabel('phpfreechat current version is %s',param) ); 364 } 365 } 366 else if (cmd == "help") 367 { 368 if (resp == "ok") 369 { 370 this.displayMsg( cmd, param); 371 } 372 } 373 else if (cmd == "rehash") 374 { 375 if (resp == "ok") 376 { 377 this.displayMsg( cmd, this.res.getLabel('Configuration has been rehashed') ); 378 } 379 else if (resp == "ko") 380 { 381 this.displayMsg( cmd, this.res.getLabel('A problem occurs during rehash') ); 382 } 383 } 384 else if (cmd == "banlist") 385 { 386 if (resp == "ok" || resp == "ko") 387 { 388 this.displayMsg( cmd, param ); 389 } 390 } 391 else if (cmd == "unban") 392 { 393 if (resp == "ok" || resp == "ko") 394 { 395 this.displayMsg( cmd, param ); 396 } 397 } 398 else if (cmd == "auth") 399 { 400 if (resp == "ban") 401 { 402 alert(param); 403 } 404 if (resp == "frozen") 405 { 406 alert(param); 407 } 408 else if (resp == "nick") 409 { 410 this.displayMsg( cmd, param ); 411 } 412 } 413 else if (cmd == "debug") 414 { 415 if (resp == "ok" || resp == "ko") 416 { 417 this.displayMsg( cmd, param ); 418 } 419 } 420 else if (cmd == "clear") 421 { 422 var tabid = this.gui.getTabId(); 423 var container = this.gui.getChatContentFromTabId(tabid); 424 container.innerHTML = ""; 425 } 426 else if (cmd == "identify") 427 { 428 this.displayMsg( cmd, param ); 429 } 430 else if (cmd == "checknickchange") 431 { 432 this.displayMsg( cmd, param ); 433 } 434 else if (cmd == "whois" || cmd == "whois2") 435 { 436 param = $H(param); 437 var nickid = param.get('nickid'); 438 if (resp == "ok") 439 { 440 this.setUserMeta(nickid, param); 441 this.updateNickBox(nickid); 442 } 443 if (cmd == "whois") 444 { 445 // display the whois info 446 var um = this.getAllUserMeta(nickid); 447 var um_keys = um.keys(); 448 var msg = ''; 449 for (var i=0; i<um_keys.length; i++) 450 { 451 var k = um_keys[i]; 452 var v = um.get(k); 453 if (v && 454 // these parameter are used internaly (don't display it) 455 k != 'nickid' && 456 k != 'floodtime' && 457 k != 'flood_nbmsg' && 458 k != 'flood_nbchar') 459 msg = msg + '<strong>' + k + '</strong>: ' + v + '<br/>'; 460 } 461 this.displayMsg( cmd, msg ); 462 } 463 } 464 else if (cmd == "who" || cmd == "who2") 465 { 466 param = $H(param); 467 var chan = param.get('chan'); 468 var chanid = param.get('chanid'); 469 var meta = $H(param.get('meta')); 470 meta.set('users', $H(meta.get('users'))); 471 if (resp == "ok") 472 { 473 this.setChanMeta(chanid,meta); 474 // send /whois commands for unknown users 475 for (var i=0; i<meta.get('users').get('nickid').length; i++) 476 { 477 var nickid = meta.get('users').get('nickid')[i]; 478 var nick = meta.get('users').get('nick')[i]; 479 var um = this.getAllUserMeta(nickid); 480 if (!um) this.sendRequest('/whois2 "'+nickid+'"'); 481 } 482 483 // update the nick list display on the current channel 484 this.updateNickListBox(chanid); 485 } 486 if (cmd == "who") 487 { 488 // display the whois info 489 var cm = this.getAllChanMeta(chanid); 490 var cm_keys = cm.keys(); 491 var msg = ''; 492 for (var i=0; i<cm_keys.length; i++) 493 { 494 var k = cm_keys[i]; 495 var v = cm[k]; 496 if (k != 'users') 497 { 498 msg = msg + '<strong>' + k + '</strong>: ' + v + '<br/>'; 499 } 500 } 501 this.displayMsg( cmd, msg ); 502 } 503 } 504 else if (cmd == "getnewmsg") 505 { 506 if (resp == "ok") 507 { 508 this.handleComingRequest(param); 509 } 510 } 511 else if (cmd == "send") 512 { 513 } 514 else 515 alert(cmd + "-"+resp+"-"+param); 516 }, 517 518 getAllUserMeta: function(nickid) 519 { 520 if (nickid && this.usermeta.get(nickid)) 521 return this.usermeta.get(nickid); 522 else 523 return null; 524 }, 525 526 getUserMeta: function(nickid, key) 527 { 528 if (nickid && key && this.usermeta.get(nickid) && this.usermeta.get(nickid).get(key)) 529 return this.usermeta.get(nickid).get(key); 530 else 531 return ''; 532 }, 533 534 setUserMeta: function(nickid, key, value) 535 { 536 if (nickid && key) 537 { 538 if (!this.usermeta.get(nickid)) this.usermeta.set(nickid, $H()); 539 if (value) 540 this.usermeta.get(nickid).set(key, value); 541 else 542 this.usermeta.set(nickid, $H(key)); 543 } 544 }, 545 546 getAllChanMeta: function(chanid) 547 { 548 if (chanid && this.chanmeta.get(chanid)) 549 return this.chanmeta.get(chanid); 550 else 551 return null; 552 }, 553 554 getChanMeta: function(chanid, key) 555 { 556 if (chanid && key && this.chanmeta.get(chanid) && this.chanmeta.get(chanid).get(key)) 557 return this.chanmeta.get(chanid).get(key); 558 else 559 return ''; 560 }, 561 562 setChanMeta: function(chanid, key, value) 563 { 564 if (chanid && key) 565 { 566 if (!this.chanmeta.get(chanid)) this.chanmeta.set(chanid, $H()); 567 if (value) 568 this.chanmeta.get(chanid).set(key,value); 569 else 570 this.chanmeta.set(chanid, $H(key)); 571 } 572 }, 573 574 doSendMessage: function() 575 { 576 var w = this.el_words; 577 var wval = w.value; 578 579 // Append the string to the history. 580 this.cmdhistory.push(wval); 581 this.cmdhistoryid = this.cmdhistory.length; 582 this.cmdhistoryissearching = false; 583 584 // Send the string to the server. 585 re = new RegExp("^(\/[a-zA-Z0-9]+)( (.*)|)"); 586 if (wval.match(re)) 587 { 588 // A user command. 589 cmd = wval.replace(re, '$1'); 590 param = wval.replace(re, '$3'); 591 this.sendRequest(cmd +' '+ param.substr(0, pfc_max_text_len + 2*this.clientid.length)); 592 } 593 else 594 { 595 // A classic 'send' command. 596 597 // Empty messages with only spaces. 598 rx = new RegExp('^[ ]*$','g'); 599 wval = wval.replace(rx,''); 600 601 // Truncate the text length. 602 wval = wval.substr(0,pfc_max_text_len); 603 604 // Colorize the text with current_text_color. 605 if (this.current_text_color != '' && wval.length != '') 606 wval = '[color=#' + this.current_text_color + '] ' + wval + ' [/color]'; 607 608 this.sendRequest('/send '+ wval); 609 } 610 w.value = ''; 611 return false; 612 }, 613 614 /** 615 * Try to complete a nickname like on IRC when pressing the TAB key. 616 * Nicks with spaces may not work under certain circumstances. 617 * Replacing spaces with alternate spaces (e.g., ) helps. 618 * Gecko browsers convert the to regular spaces, so no help for these browsers. 619 * Note: IRC does not allow nicks with spaces, so it's much easier for those clients. :) 620 * @author Gerard Pinzone 621 */ 622 completeNick: function() 623 { 624 var w = this.el_words; 625 var selStart = w.value.length; // Default for browsers that don't support selection/caret position commands. 626 var selEnd = selStart; 627 628 // Get selection/caret position. 629 if (w.setSelectionRange) 630 { 631 // We don't rely on the stored values for browsers that support 632 // the selectionStart and selectionEnd commands. 633 selStart = w.selectionStart; 634 selEnd = w.selectionEnd; 635 } 636 else if (w.createTextRange && document.selection) 637 { 638 // We must rely on the stored values for IE browsers. 639 selStart = (w.selStart != null) ? w.selStart : w.value.length; 640 selEnd = (w.selEnd != null) ? w.selEnd : w.value.length; 641 } 642 643 var begin = w.value.lastIndexOf(' ', selStart - 1) + 1; 644 var end = (w.value.indexOf(' ', selStart) >= 0) ? w.value.indexOf(' ', selStart) : w.value.length; 645 var nick_src = w.value.substring(begin, end); 646 var non_nick_begin = w.value.substring(0, begin); 647 var non_nick_end = w.value.substring(end, w.value.length); 648 649 if (nick_src != '') 650 { 651 var tabid = this.gui.getTabId(); 652 var n_list = this.getChanMeta(tabid, 'users')['nick']; 653 var nick_match = false; 654 for (var i = 0; i < n_list.length; i++) 655 { 656 var nick_tmp = n_list[i]; 657 // replace spaces in nicks with 658 nick_tmp = nick_tmp.replace(/ /g, '\240'); 659 if (nick_tmp.indexOf(nick_src) == 0) 660 { 661 if (! nick_match) 662 { 663 nick_match = true; 664 nick_replace = nick_tmp; 665 } 666 else 667 { 668 // more than one possibility for completion 669 var nick_len = Math.min(nick_tmp.length, nick_replace.length); 670 // only keep characters that are common to all matches 671 var j = 0; 672 for (j = 0; j < nick_len; j++) 673 if (nick_tmp.charAt(j) != nick_replace.charAt(j)) 674 break; 675 676 nick_replace = nick_replace.substr(0, j); 677 } 678 } 679 } 680 if (nick_match) 681 { 682 w.value = non_nick_begin + nick_replace + non_nick_end; 683 w.selStart = w.selEnd = non_nick_begin.length + nick_replace.length; 684 685 // Move cursor to end of completed nick. 686 if (w.setSelectionRange) 687 w.setSelectionRange(w.selEnd, w.selEnd); // Gecko 688 else 689 this.setSelection(w); // IE 690 } 691 } 692 }, 693 694 /** 695 * Cycle to older entry in history 696 */ 697 historyUp: function() 698 { 699 // Write the previous command in the history. 700 if (this.cmdhistory.length > 0) 701 { 702 var w = this.el_words; 703 if (this.cmdhistoryissearching == false && w.value != "") 704 this.cmdhistory.push(w.value); 705 this.cmdhistoryissearching = true; 706 this.cmdhistoryid = this.cmdhistoryid - 1; 707 if (this.cmdhistoryid < 0) 708 this.cmdhistoryid = 0; // stop at oldest entry 709 w.value = this.cmdhistory[this.cmdhistoryid]; 710 } 711 }, 712 713 /** 714 * Cycle to newer entry in history 715 */ 716 historyDown: function() 717 { 718 // Write the next command in the history. 719 if (this.cmdhistory.length > 0) 720 { 721 var w = this.el_words; 722 if (this.cmdhistoryissearching == false && w.value != "") 723 this.cmdhistory.push(w.value); 724 this.cmdhistoryissearching = true; 725 this.cmdhistoryid = this.cmdhistoryid + 1; 726 if (this.cmdhistoryid >= this.cmdhistory.length) 727 { 728 this.cmdhistoryid = this.cmdhistory.length; // stop at newest entry + 1 729 w.value = ""; // blank input box 730 } 731 else 732 w.value = this.cmdhistory[this.cmdhistoryid]; 733 } 734 }, 735 736 /** 737 * Handle the pressed keys. 738 * see also callbackWords_OnKeydown 739 */ 740 callbackWords_OnKeypress: function(evt) 741 { 742 // All browsers except for IE should use "evt.which." 743 var code = (evt.which) ? evt.which : evt.keyCode; 744 if (code == Event.KEY_RETURN) /* ENTER key */ 745 { 746 return this.doSendMessage(); 747 } 748 else 749 { 750 // Allow other key defaults. 751 return true; 752 } 753 }, 754 755 /** 756 * Handle the pressed keys. 757 * see also callbackWords_OnKeypress 758 * WARNING: Suppressing defaults on the keydown event 759 * may prevent keypress and/or keyup events 760 * from firing. 761 */ 762 callbackWords_OnKeydown: function(evt) 763 { 764 if (!this.isconnected) return false; 765 this.clearError(Array(this.el_words)); 766 var code = (evt.which) ? evt.which : evt.keyCode 767 if (code == 38 && (is_gecko || is_ie || is_opera || is_webkit)) // up arrow key 768 { 769 /* TODO: Fix up arrow issue in Opera - may be a bug in Opera. See TAB handler comments below. */ 770 /* Konqueror cannot use this feature due to keycode conflicts. */ 771 772 // Write the previous command in the history. 773 this.historyUp(); 774 775 if (evt.returnValue) // IE 776 evt.returnValue = false; 777 if (evt.preventDefault) // DOM 778 evt.preventDefault(); 779 return false; // should work in all browsers 780 } 781 else if (code == 40 && (is_gecko || is_ie || is_opera || is_webkit)) // down arrow key 782 { 783 /* Konqueror cannot use this feature due to keycode conflicts. */ 784 785 // Write the previous command in the history. 786 this.historyDown(); 787 788 if (evt.returnValue) // IE 789 evt.returnValue = false; 790 if (evt.preventDefault) // DOM 791 evt.preventDefault(); 792 return false; // should work in all browsers 793 } 794 else if (code == 9) /* TAB key */ 795 { 796 // Do nickname completion like on IRC / Unix command line. 797 this.completeNick(); 798 799 if (is_opera) 800 { 801 // Fixes Opera's loss of focus after TAB key is pressed. 802 // This is most likely due to a bug in Opera 803 // that executes the default key operation BEFORE the 804 // keydown and keypress event handler. 805 // This is probably the reason for the "up arrow" issue above. 806 //window.setTimeout(function(){evt.target.focus();}, 0); 807 evt.target.onblur = function() { this.focus(); this.onblur = null; }; 808 } 809 810 if (evt.returnValue) // IE 811 evt.returnValue = false; 812 if (evt.preventDefault) // DOM 813 evt.preventDefault(); 814 return false; // Should work in all browsers. 815 } 816 else 817 { 818 // Allow other key defaults. 819 return true; 820 } 821 }, 822 callbackWords_OnKeyup: function(evt) 823 { 824 // Needed for IE since the text box loses selection/caret position on blur 825 this.storeSelectionPos(this.el_words); 826 }, 827 callbackWords_OnMouseup: function(evt) 828 { 829 // Needed for IE since the text box loses selection/caret position on blur 830 this.storeSelectionPos(this.el_words); 831 }, 832 callbackWords_OnFocus: function(evt) 833 { 834 // if (this.el_handle && this.el_handle.value == '' && !this.minmax_status) 835 // this.el_handle.focus(); 836 837 // Needed for IE since the text box loses selection/caret position on blur 838 this.setSelection(this.el_words); 839 }, 840 callback_OnUnload: function(evt) 841 { 842 /* don't disconnect users when they reload the window 843 * this event doesn't only occurs when the page is closed but also when the page is reloaded */ 844 if (pfc_quit_on_closedwindow) 845 { 846 if (!this.isconnected) return false; 847 this.sendRequest('/quit'); 848 } 849 }, 850 851 852 /** 853 * hide error area and stop blinking fields 854 */ 855 clearError: function(ids) 856 { 857 this.el_errors.style.display = 'none'; 858 for (var i=0; i<ids.length; i++) 859 this.blink(ids[i].id, 'stop'); 860 }, 861 862 /** 863 * show error area and assign to it an error message and start the blinking of given fields 864 */ 865 setError: function(str, ids) 866 { 867 this.el_errors.innerHTML = str; 868 this.el_errors.style.display = 'block'; 869 for (var i=0; i<ids.length; i++) 870 this.blink(ids[i].id, 'start'); 871 }, 872 873 /** 874 * blink routines used by Error functions 875 */ 876 blink: function(id, action) 877 { 878 clearTimeout(this.blinktimeout[id]); 879 if ($(id) == null) return; 880 if (action == 'start') 881 { 882 this.blinktmp[id] = $(id).style.backgroundColor; 883 clearTimeout(this.blinktimeout[id]); 884 this.blinktimeout[id] = setTimeout('pfc.blink(\'' + id + '\',\'loop\')', 500); 885 } 886 if (action == 'stop') 887 { 888 $(id).style.backgroundColor = this.blinktmp[id]; 889 } 890 if (action == 'loop') 891 { 892 if (this.blinkloop[id] == 1) 893 { 894 $(id).style.backgroundColor = '#FFDFC0'; 895 this.blinkloop[id] = 2; 896 } 897 else 898 { 899 $(id).style.backgroundColor = '#FFFFFF'; 900 this.blinkloop[id] = 1; 901 } 902 this.blinktimeout[id] = setTimeout('pfc.blink(\'' + id + '\',\'loop\')', 500); 903 } 904 }, 905 906 displayMsg: function( cmd, msg ) 907 { 908 this.setError(msg, Array()); 909 910 // @todo find a better crossbrowser way to display messages 911/* 912 // get the current selected tab container 913 var tabid = this.gui.getTabId(); 914 var container = this.gui.getChatContentFromTabId(tabid); 915 916 // to fix IE6 display bug 917 // http://sourceforge.net/tracker/index.php?func=detail&aid=1545403&group_id=158880&atid=809601 918 div = document.createElement('div'); 919 // div.style.padding = "2px 5px 2px 5px"; // this will clear the screen in IE6 920 div.innerHTML = '<div class="pfc_info pfc_info_'+cmd+'" style="margin:5px">'+msg+'</div>'; 921 922 // finaly append this to the message list 923 container.appendChild(div); 924 this.gui.scrollDown(tabid, div); 925*/ 926 }, 927 928 handleComingRequest: function( cmds ) 929 { 930 var msg_html = $H(); 931 var max_msgid = $H(); 932 933 //alert(cmds.inspect()); 934 935 for(var mid = 0; mid < cmds.length ; mid++) 936 { 937 var id = cmds[mid][0]; 938 var date = cmds[mid][1]; 939 var time = cmds[mid][2]; 940 var sender = cmds[mid][3]; 941 var recipientid = cmds[mid][4]; 942 var cmd = cmds[mid][5]; 943 var param = cmds[mid][6]; 944 var fromtoday = cmds[mid][7]; 945 var oldmsg = cmds[mid][8]; 946 947 // format and post message 948 var line = ''; 949 line += '<div id="pfc_msg_'+recipientid+'_'+id+'" class="pfc_cmd_'+ cmd +' pfc_message'; 950 line += (id % 2 == 0) ? ' pfc_evenmsg' : ' pfc_oddmsg'; 951 if (oldmsg == 1) line += ' pfc_oldmsg'; 952 line += '">'; 953 line += '<span class="pfc_date'; 954 if (fromtoday == 1) line += ' pfc_invisible'; 955 line += '">'+ date +'</span> '; 956 line += '<span class="pfc_heure">'+ time +'</span> '; 957 if (cmd == 'send') 958 { 959 line += ' <span class="pfc_nick">'; 960 line += '‹'; 961 line += '<span '; 962 line += 'onclick="pfc.insert_text(\'' + sender.escapeHTML().replace("'", '\\\'') + ', \',\'\',false)" '; 963 line += 'class="pfc_nickmarker pfc_nick_'+ _to_utf8(sender).md5() +'">'; 964 line += sender.escapeHTML(); 965 line += '</span>'; 966 line += '›'; 967 line += '</span> '; 968 } 969 if (cmd == 'notice') 970 line += '<span class="pfc_words">* ' + this.parseMessage(param) +'</span> '; 971 else if (cmd == 'me') 972 line += '<span class="pfc_words">* '+ sender.escapeHTML() + ' ' + this.parseMessage(param) +'</span> '; 973 else 974 line += '<span class="pfc_words">'+ this.parseMessage(param) +'</span> '; 975 line += '</div>'; 976 977 if (oldmsg == 0) 978 if (cmd == 'send' || cmd == 'me') 979 { 980 // notify the hidden tab a message has been received 981 // don't notify anything if this is old messages 982 var tabid = recipientid; 983 if (this.gui.getTabId() != tabid) 984 this.gui.notifyTab(tabid); 985 // notify the window (change the title) 986 if (!this.detectactivity.isActive() && pfc_notify_window) 987 this.gui.notifyWindow(); 988 } 989 990 if (msg_html.get(recipientid) == null) 991 msg_html.set(recipientid, line); 992 else 993 msg_html.set(recipientid, msg_html.get(recipientid) + line); 994 995 // remember the max message id in order to clean old lines 996 if (!max_msgid.get(recipientid)) max_msgid.set(recipientid, 0); 997 if (max_msgid.get(recipientid) < id) max_msgid.set(recipientid, id); 998 } 999 1000 // loop on all recipients and post messages 1001 var keys = msg_html.keys(); 1002 for( var i=0; i<keys.length; i++) 1003 { 1004 var recipientid = keys[i]; 1005 var tabid = recipientid; 1006 // create the tab if it doesn't exists yet 1007 var recipientdiv = this.gui.getChatContentFromTabId(tabid); 1008 1009 // create a dummy div to avoid konqueror bug when setting nickmarkers 1010 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 1011 m.innerHTML = msg_html.get(recipientid); 1012 this.colorizeNicks(m); 1013 this.refresh_clock(m); 1014 // finaly append this to the message list 1015 recipientdiv.appendChild(m); 1016 this.gui.scrollDown(tabid, m); 1017 1018 // delete the old messages from the client (save some memory) 1019 var limit_msgid = max_msgid.get(recipientid) - pfc_max_displayed_lines; 1020 var elt = $('pfc_msg_'+recipientid+'_'+limit_msgid); 1021 while (elt) 1022 { 1023 // delete this element to save browser memory 1024 if(elt.parentNode) 1025 elt.parentNode.removeChild(elt); 1026 else if(elt.parentElement) // older IE browsers (<6.0) may not support parentNode 1027 elt.parentElement.removeChild(elt); 1028 else // if all else fails 1029 elt.innerHTML = ''; 1030 limit_msgid--; 1031 elt = $('pfc_msg_'+recipientid+'_'+limit_msgid); 1032 } 1033 } 1034 1035 }, 1036 1037 calcDelay: function() 1038 { 1039 var lastact = new Date().getTime() - this.last_activity_time; 1040 var dlist = this.refresh_delay_steps.slice(); 1041 var delay = dlist.shift(); 1042 if (this.refresh_delay > delay) delay = this.refresh_delay; 1043 var limit; 1044 while (typeof (limit = dlist.shift()) != "undefined") 1045 { 1046 var d = dlist.shift(); 1047 if (d < delay) continue; 1048 if (lastact > limit) delay = d; 1049 } 1050 return delay; 1051 }, 1052 1053 /** 1054 * Call the ajax request function 1055 * Will query the server 1056 */ 1057 sendRequest: function(cmd, recipientid) 1058 { 1059 // do not send another ajax requests if the last one is not yet finished 1060 if (cmd == '/update' && this.pfc_ajax_connected) return; 1061 1062 var delay = this.calcDelay(); 1063 1064 if (cmd != "/update") 1065 { 1066 // setup a new timeout to update the chat in 5 seconds (in refresh_delay more exactly) 1067 clearTimeout(this.timeout); 1068 this.timeout = setTimeout('pfc.updateChat(true)', delay); 1069 this.timeout_time = new Date().getTime() + delay; 1070 1071 if (pfc_debug) 1072 trace('sendRequest: '+cmd); 1073 } 1074 1075 // prepare the command string 1076 var rx = new RegExp('(^\/[^ ]+) *(.*)','ig'); 1077 if (!recipientid) recipientid = this.gui.getTabId(); 1078 cmd = cmd.replace(rx, '$1 '+this.clientid+' '+(recipientid==''?'0':recipientid)+' $2'); 1079 1080 // send the real ajax request 1081 var url = pfc_server_script_url; 1082 new Ajax.Request(url, { 1083 method: 'post', 1084 parameters: {'pfc_ajax':1, 'f':'handleRequest', 'cmd': cmd }, 1085 onCreate: function(transport) { 1086 this.pfc_ajax_connected = true; 1087 // request time counter used by ping indicator 1088 this.last_request_time = new Date().getTime(); 1089 }.bind(this), 1090 onSuccess: function(transport) { 1091 if (!transport.status) return; // fix strange behavior on KHTML 1092 1093 // request time counter used by ping indicator 1094 this.last_response_time = new Date().getTime(); 1095 // evaluate the javascript response 1096 eval( transport.responseText ); 1097 }.bind(this), 1098 onComplete: function(transport) { 1099 this.pfc_ajax_connected = false; 1100 1101 // calculate the ping and display it 1102 this.ping = Math.abs(this.last_response_time - this.last_request_time); 1103 if ($('pfc_ping')) $('pfc_ping').innerHTML = this.ping+'ms'+' ['+parseInt(this.calcDelay() / 1000)+'s]'; 1104 }.bind(this) 1105 }); 1106 }, 1107 1108 /** 1109 * update function to poll the server each 'refresh_delay' time 1110 */ 1111 updateChat: function(start) 1112 { 1113 clearTimeout(this.timeout); 1114 if (start) 1115 { 1116 this.sendRequest('/update'); 1117 1118 // setup the next update 1119 var delay = this.calcDelay(); 1120 this.timeout = setTimeout('pfc.updateChat(true)', delay); 1121 this.timeout_time = new Date().getTime() + delay; 1122 } 1123 }, 1124 1125 /** 1126 * Stores the caret/selection position for IE 6.x and 7.x 1127 * Returns true if text range start and end values were updated. 1128 * Code based on: http://www.bazon.net/mishoo/articles.epl?art_id=1292 1129 */ 1130 storeSelectionPos: function(obj) 1131 { 1132 // We don't need to store the start and end positions if the browser 1133 // supports the Gecko selection model. However, these values may be 1134 // useful for debugging. Also, Opera recognizes Gecko and IE range 1135 // commands, so we need to ensure Opera only uses the Gecko model. 1136 /* WARNING: Do not use this for textareas. They require a more 1137 complex algorithm. */ 1138 if (obj.setSelectionRange) 1139 { 1140 obj.selStart = obj.selectionStart; 1141 obj.selEnd = obj.selectionEnd; 1142 1143 return true; 1144 } 1145 1146 // IE 1147 else if (obj.createTextRange && document.selection) 1148 { 1149 // Determine current selection start position. 1150 var range = document.selection.createRange(); 1151 var isCollapsed = range.compareEndPoints("StartToEnd", range) == 0; 1152 if (!isCollapsed) 1153 range.collapse(true); 1154 var b = range.getBookmark(); 1155 obj.selStart = b.charCodeAt(2) - b.charCodeAt(0) - 1; 1156 1157 // Determine current selection end position. 1158 range = document.selection.createRange(); 1159 isCollapsed = range.compareEndPoints("StartToEnd", range) == 0; 1160 if (!isCollapsed) 1161 range.collapse(false); 1162 b = range.getBookmark(); 1163 obj.selEnd = b.charCodeAt(2) - b.charCodeAt(0) - 1; 1164 1165 return true; 1166 } 1167 1168 // Browser does not support selection range processing. 1169 else 1170 return false; 1171 }, 1172 1173 /** 1174 * Sets the selection/caret in the object based on the 1175 * object's selStart and selEnd parameters. 1176 * This should only be needed for IE only. 1177 */ 1178 setSelection: function(obj) 1179 { 1180 // This part of the function is included to prevent 1181 // Opera from executing the IE portion. 1182 /* WARNING: Do not attempt to use this function as 1183 a wrapper for the Gekco based setSelectionRange. 1184 It causes problems in Opera when executed from 1185 the event trigger onFocus. */ 1186 if (obj.setSelectionRange) 1187 { 1188 return null; 1189 } 1190 // IE 1191 else if (obj.createTextRange) 1192 { 1193 var range = obj.createTextRange(); 1194 range.collapse(true); 1195 range.moveStart("character", obj.selStart); 1196 range.moveEnd("character", obj.selEnd - obj.selStart); 1197 range.select(); 1198 1199 return range; 1200 } 1201 // Browser does not support selection range processing. 1202 else 1203 return null; 1204 }, 1205 1206 /** 1207 * insert a smiley 1208 */ 1209 insertSmiley: function(smiley) 1210 { 1211 var w = this.el_words; 1212 1213 if (w.setSelectionRange) 1214 { 1215 // Gecko 1216 var s = w.selectionStart; 1217 var e = w.selectionEnd; 1218 w.value = w.value.substring(0, s) + smiley + w.value.substr(e); 1219 w.setSelectionRange(s + smiley.length, s + smiley.length); 1220 w.focus(); 1221 } 1222 else if (w.createTextRange) 1223 { 1224 // IE 1225 w.focus(); 1226 1227 // Get range based on stored values. 1228 var range = this.setSelection(w); 1229 1230 range.text = smiley; 1231 1232 // Move caret position to end of smiley and collapse selection, if any. 1233 // Check if internally kept values for selection are initialized. 1234 w.selStart = (w.selStart) ? w.selStart + smiley.length : smiley.length; 1235 w.selEnd = w.selStart; 1236 } 1237 else 1238 { 1239 // Unsupported browsers get smiley at end of string like old times. 1240 w.value += smiley; 1241 w.focus(); 1242 } 1243 }, 1244 1245 updateNickBox: function(nickid) 1246 { 1247 // @todo optimize this function because it is called lot of times so it could cause CPU consuming on client side 1248 var chanids = this.chanmeta.keys(); 1249 for(var i = 0; chanids.length > i; i++) 1250 { 1251 this.updateNickListBox(chanids[i]); 1252 } 1253 }, 1254 1255 /** 1256 * fill the nickname list with connected nicknames 1257 */ 1258 updateNickListBox: function(chanid) 1259 { 1260 var className = (!is_ie7 && !is_ie6) ? 'class' : 'className'; 1261 1262 var nickidlst = this.getChanMeta(chanid,'users').get('nickid'); 1263 var nickdiv = this.gui.getOnlineContentFromTabId(chanid); 1264 var ul = document.createElement('ul'); 1265 ul.setAttribute(className, 'pfc_nicklist'); 1266 for (var i=0; i<nickidlst.length; i++) 1267 { 1268 var nickid = nickidlst[i]; 1269 var li = this.buildNickItem(nickid); 1270 li.setAttribute(className, 'pfc_nickitem_'+nickid); 1271 ul.appendChild(li); 1272 } 1273 var fc = nickdiv.firstChild; 1274 if (fc) 1275 nickdiv.replaceChild(ul,fc); 1276 else 1277 nickdiv.appendChild(ul,fc); 1278 this.colorizeNicks(nickdiv); 1279 }, 1280 1281 getNickWhoisBox: function(nickid) 1282 { 1283 if (!this.nickwhoisbox.get(nickid)) 1284 this.updateNickWhoisBox(nickid); 1285 return this.nickwhoisbox.get(nickid); 1286 }, 1287 1288 updateNickWhoisBox_ignored_field: function(k) 1289 { 1290 return ( k == 'nickid' || 1291 k == 'nick' || // useless because it is displayed in the box title 1292 k == 'isadmin' || // useless because of the gold shield icon 1293 k == 'floodtime' || 1294 k == 'flood_nbmsg' || 1295 k == 'flood_nbchar' 1296 ); 1297 }, 1298 1299 updateNickWhoisBox_append_html: function(nickid, div) 1300 { 1301 // this methode can be overloaded to append customized data to the whoisbox 1302 }, 1303 1304 updateNickWhoisBox_prepend_html: function(nickid, div) 1305 { 1306 // this methode can be overloaded to prepend customized data to the whoisbox 1307 }, 1308 1309 updateNickWhoisBox: function(nickid) 1310 { 1311 var className = (!is_ie7 && !is_ie6) ? 'class' : 'className'; 1312 1313 var usermeta = this.getAllUserMeta(nickid); 1314 var div = document.createElement('div'); 1315 div.setAttribute(className, 'pfc_nickwhois'); 1316 1317 var p = document.createElement('p'); 1318 p.setAttribute(className, 'pfc_nickwhois_header'); 1319 div.appendChild(p); 1320 1321 // add the close button 1322 var img = document.createElement('img'); 1323 img.setAttribute(className, 'pfc_nickwhois_close'); 1324 img.pfc_parent = div; 1325 img.onclick = function(evt){ 1326 this.pfc_parent.style.display = 'none'; 1327 return false; 1328 } 1329 img.setAttribute('src', this.res.getFileUrl('images/close-whoisbox.gif')); 1330 img.alt = this.res.getLabel('Close'); 1331 p.appendChild(img); 1332 p.appendChild(document.createTextNode(usermeta.get('nick'))); // append the nickname text in the title 1333 1334 this.updateNickWhoisBox_prepend_html(nickid,div); 1335 1336 // add the whois information table 1337 var table = document.createElement('table'); 1338 var tbody = document.createElement('tbody'); 1339 table.appendChild(tbody); 1340 var um_keys = usermeta.keys(); 1341 var msg = ''; 1342 for (var i=0; i<um_keys.length; i++) 1343 { 1344 var k = um_keys[i]; 1345 var v = usermeta.get(k); 1346 if (v && !this.updateNickWhoisBox_ignored_field(k)) 1347 { 1348 var tr = document.createElement('tr'); 1349 if (pfc_nickmeta_key_to_hide.indexOf(k) != -1) 1350 { 1351 var td2 = document.createElement('td'); 1352 td2.setAttribute(className, 'pfc_nickwhois_c2'); 1353 td2.setAttribute('colspan', 2); 1354 td2.innerHTML = v; 1355 tr.appendChild(td2); 1356 } 1357 else 1358 { 1359 var td1 = document.createElement('td'); 1360 td1.setAttribute(className, 'pfc_nickwhois_c1'); 1361 var td2 = document.createElement('td'); 1362 td2.setAttribute(className, 'pfc_nickwhois_c2'); 1363 td1.innerHTML = k; 1364 td2.innerHTML = v; 1365 tr.appendChild(td1); 1366 tr.appendChild(td2); 1367 } 1368 tbody.appendChild(tr); 1369 } 1370 } 1371 div.appendChild(table); 1372 1373 this.updateNickWhoisBox_append_html(nickid,div); 1374 1375 // add the privmsg link (do not add it if the nick is yours) 1376 if (pfc.getUserMeta(nickid,'nick') != this.nickname) 1377 { 1378 var p = document.createElement('p'); 1379 p.setAttribute(className, 'pfc_nickwhois_pv'); 1380 var a = document.createElement('a'); 1381 a.setAttribute('href', ''); 1382 a.pfc_nickid = nickid; 1383 a.pfc_parent = div; 1384 a.onclick = function(evt){ 1385 var nick = pfc.getUserMeta(this.pfc_nickid,'nick'); 1386 pfc.sendRequest('/privmsg "'+nick+'"'); 1387 this.pfc_parent.style.display = 'none'; 1388 return false; 1389 } 1390 var img = document.createElement('img'); 1391 img.setAttribute('src', this.res.getFileUrl('images/openpv.gif')); 1392 img.alt = document.createTextNode(this.res.getLabel('Private message')); 1393 a.appendChild(img); 1394 a.appendChild(document.createTextNode(this.res.getLabel('Private message'))); 1395 p.appendChild(a); 1396 div.appendChild(p); 1397 } 1398 1399 this.nickwhoisbox.set(nickid, div); 1400 }, 1401 1402 buildNickItem_create_image: function(nickid) 1403 { 1404 var className = (!is_ie7 && !is_ie6) ? 'class' : 'className'; 1405 var isadmin = this.getUserMeta(nickid, 'isadmin'); 1406 var img = document.createElement('img'); 1407 if (isadmin) 1408 img.setAttribute('src', this.res.getFileUrl('images/user-admin.gif')); 1409 else 1410 img.setAttribute('src', this.res.getFileUrl('images/user.gif')); 1411 img.style.marginRight = '5px'; 1412 img.setAttribute(className, 'pfc_nickbutton'); 1413 return img; 1414 }, 1415 1416 buildNickItem_modify_nick_style: function(nickid, span) 1417 { 1418 // this method can be overloaded to change the nick style (color, font ...) 1419 // example: span.style.color = 'red'; 1420 }, 1421 1422 buildNickItem: function(nickid) 1423 { 1424 var className = (!is_ie7 && !is_ie6) ? 'class' : 'className'; 1425 1426 var nick = this.getUserMeta(nickid, 'nick'); 1427 var isadmin = this.getUserMeta(nickid, 'isadmin'); 1428 if (isadmin == '') isadmin = false; 1429 1430 var li = document.createElement('li'); 1431 1432 var a = document.createElement('a'); 1433 a.setAttribute('href','#'); 1434 a.pfc_nick = nick; 1435 a.pfc_nickid = nickid; 1436 a.onclick = function(evt){ 1437 var d = pfc.getNickWhoisBox(this.pfc_nickid); 1438 document.body.appendChild(d); 1439 d.style.display = 'block'; 1440 d.style.zIndex = '400'; 1441 d.style.position = 'absolute'; 1442 d.style.left = (mousePosX(evt)-7)+'px'; 1443 d.style.top = (mousePosY(evt)-7)+'px'; 1444 return false; 1445 } 1446 li.appendChild(a); 1447 1448 var img = this.buildNickItem_create_image(nickid); 1449 if (img) a.appendChild(img); 1450 1451 // nobr is not xhtml valid but it's a workeround 1452 // for IE which doesn't support 'white-space: pre' css rule 1453 var nobr = document.createElement('nobr'); 1454 var span = document.createElement('span'); 1455 span.setAttribute(className, 'pfc_nickmarker pfc_nick_'+nickid); 1456 span.innerHTML = nick.escapeHTML(); 1457 this.buildNickItem_modify_nick_style(nickid, span); 1458 nobr.appendChild(span); 1459 a.appendChild(nobr); 1460 1461 return li; 1462 }, 1463 1464 /** 1465 * clear the nickname list 1466 */ 1467 clearNickList: function() 1468 { 1469 /* 1470 var nickdiv = this.el_online; 1471 var fc = nickdiv.firstChild; 1472 if (fc) nickdiv.removeChild(fc); 1473 */ 1474 }, 1475 1476 1477 /** 1478 * clear the message list history 1479 */ 1480 clearMessages: function() 1481 { 1482 //var msgdiv = $('pfc_chat'); 1483 //msgdiv.innerHTML = ''; 1484 }, 1485 1486 /** 1487 * parse the message 1488 */ 1489 parseMessage: function(msg) 1490 { 1491 var rx = null; 1492/* 1493 // parse urls 1494 var rx_url = new RegExp('(^|[^\\"])([a-z]+\:\/\/[a-z0-9.\\~\\/\\?\\=\\&\\-\\_\\#:;%,@]*[a-z0-9\\/\\?\\=\\&\\-\\_\\#])([^\\"]|$)','ig'); 1495 var ttt = msg.split(rx_url); 1496 if (ttt.length > 1 && 1497 !navigator.appName.match("Explorer|Konqueror") && 1498 !navigator.appVersion.match("KHTML")) 1499 { 1500 msg = ''; 1501 for( var i = 0; i<ttt.length; i++) 1502 { 1503 var offset = (ttt[i].length - 7) / 2; 1504 var delta = (ttt[i].length - 7 - 60); 1505 var range1 = 7+offset-delta; 1506 var range2 = 7+offset+delta; 1507 if (ttt[i].match(rx_url)) 1508 { 1509 msg = msg + '<a href="' + ttt[i] + '"'; 1510 if (pfc_openlinknewwindow) 1511 msg = msg + ' onclick="window.open(this.href,\'_blank\');return false;"'; 1512 msg = msg + '>' + (delta>0 ? ttt[i].substring(7,range1)+ ' ... ' + ttt[i].substring(range2,ttt[i].length) : ttt[i]) + '</a>'; 1513 } 1514 else 1515 { 1516 msg = msg + ttt[i]; 1517 } 1518 } 1519 } 1520 else 1521 { 1522 // fallback for IE6/Konqueror which do not support split with regexp 1523 replace = '$1<a href="$2"'; 1524 if (pfc_openlinknewwindow) 1525 replace = replace + ' onclick="window.open(this.href,\'_blank\');return false;"'; 1526 replace = replace + '>$2</a>$3'; 1527 msg = msg.replace(rx_url, replace); 1528 } 1529*/ 1530 1531 // Remove auto-linked entries. 1532 if ( false ) 1533 { 1534 rx = new RegExp('<a href="mailto:(.*?)".*?>.*?<\/a>','ig'); 1535 msg = msg.replace(rx, '$1'); 1536 rx = new RegExp('<a href="(.*?)".*?>.*?<\/a>','ig'); 1537 msg = msg.replace(rx, '$1'); 1538 } 1539 1540 // Replace double spaces outside of tags by " " entity. 1541 rx = new RegExp(' (?= )(?![^<]*>)','g'); 1542 msg = msg.replace(rx, ' '); 1543 1544 // try to parse bbcode 1545 rx = new RegExp('\\[b\\](.+?)\\[\/b\\]','ig'); 1546 msg = msg.replace(rx, '<span style="font-weight: bold">$1</span>'); 1547 rx = new RegExp('\\[i\\](.+?)\\[\/i\\]','ig'); 1548 msg = msg.replace(rx, '<span style="font-style: italic">$1</span>'); 1549 rx = new RegExp('\\[u\\](.+?)\\[\/u\\]','ig'); 1550 msg = msg.replace(rx, '<span style="text-decoration: underline">$1</span>'); 1551 rx = new RegExp('\\[s\\](.+?)\\[\/s\\]','ig'); 1552 msg = msg.replace(rx, '<span style="text-decoration: line-through">$1</span>'); 1553 // rx = new RegExp('\\[pre\\](.+?)\\[\/pre\\]','ig'); 1554 // msg = msg.replace(rx, '<pre>$1</pre>'); 1555/* 1556 rx = new RegExp('\\[email\\]([A-z0-9][\\w.-]*@[A-z0-9][\\w\\-\\.]+\\.[A-z0-9]{2,6})\\[\/email\\]','ig'); 1557 msg = msg.replace(rx, '<a href="mailto: $1">$1</a>'); 1558 rx = new RegExp('\\[email=([A-z0-9][\\w.-]*@[A-z0-9][\\w\\-\\.]+\\.[A-z0-9]{2,6})\\](.+?)\\[\/email\\]','ig'); 1559 msg = msg.replace(rx, '<a href="mailto: $1">$2</a>'); 1560*/ 1561 rx = new RegExp('\\[color=([a-zA-Z]+|\\#?[0-9a-fA-F]{6}|\\#?[0-9a-fA-F]{3})\\](.+?)\\[\/color\\]','ig'); 1562 msg = msg.replace(rx, '<span style="color: $1">$2</span>'); 1563 // parse bbcode colors twice because the current_text_color is a bbcolor 1564 // so it's possible to have a bbcode color imbrication 1565 rx = new RegExp('\\[color=([a-zA-Z]+|\\#?[0-9a-fA-F]{6}|\\#?[0-9a-fA-F]{3})\\](.+?)\\[\/color\\]','ig'); 1566 msg = msg.replace(rx, '<span style="color: $1">$2</span>'); 1567 1568 // try to parse smileys 1569 var smileys = this.res.getSmileyHash(); 1570 var sl = this.res.getSmileyKeys(); // Keys should be sorted by length from pfc.gui.loadSmileyBox() 1571 for(var i = 0; i < sl.length; i++) 1572 { 1573 // We don't want to replace smiley strings inside of tags. 1574 // Use negative lookahead to search for end of tag. 1575 rx = new RegExp(RegExp.escape(sl[i]) + '(?![^<]*>)','g'); 1576 msg = msg.replace(rx, '<img src="'+ smileys.get(sl[i]) +'" alt="' + sl[i] + '" title="' + sl[i] + '" />'); 1577 } 1578 1579 // try to parse nickname for highlighting 1580 rx = new RegExp('(^|[ :,;])'+RegExp.escape(this.nickname)+'([ :,;]|$)','gi'); 1581 msg = msg.replace(rx, '$1<strong>'+ this.nickname +'</strong>$2'); 1582 1583 // this piece of code is replaced by the word-wrap CSS3 rule. 1584 /* 1585 // don't allow to post words bigger than 65 caracteres 1586 // doesn't work with crappy IE and Konqueror ! 1587 rx = new RegExp('([^ \\:\\<\\>\\/\\&\\;]{60})','ig'); 1588 var ttt = msg.split(rx); 1589 if (ttt.length > 1 && 1590 !navigator.appName.match("Explorer|Konqueror") && 1591 !navigator.appVersion.match("KHTML")) 1592 { 1593 msg = ''; 1594 for( var i = 0; i<ttt.length; i++) 1595 { 1596 msg = msg + ttt[i] + ' '; 1597 } 1598 } 1599 */ 1600 return msg; 1601 }, 1602 1603 /** 1604 * apply nicknames color to the root childs 1605 */ 1606 colorizeNicks: function(root) 1607 { 1608 if (this.nickmarker) 1609 { 1610 var nicklist = this.getElementsByClassName(root, 'pfc_nickmarker', ''); 1611 for(var i = 0; i < nicklist.length; i++) 1612 { 1613 var cur_nick = nicklist[i].innerHTML; 1614 var cur_color = this.getAndAssignNickColor(cur_nick); 1615 nicklist[i].style.color = cur_color; 1616 } 1617 } 1618 }, 1619 1620 /** 1621 * Initialize the color array used to colirize the nicknames 1622 */ 1623 reloadColorList: function() 1624 { 1625 this.colorlist = $A(pfc_nickname_color_list); 1626 }, 1627 1628 1629 /** 1630 * get the corresponding nickname color 1631 */ 1632 getAndAssignNickColor: function(nick) 1633 { 1634 /* check the nickname is colorized or not */ 1635 var already_colorized = false; 1636 var nc = ''; 1637 for(var j = 0; j < this.nickcolor.length && !already_colorized; j++) 1638 { 1639 if (this.nickcolor[j][0] == nick) 1640 { 1641 already_colorized = true; 1642 nc = this.nickcolor[j][1]; 1643 } 1644 } 1645 if (!already_colorized) 1646 { 1647 /* reload the color stack if it's empty */ 1648 if (this.colorlist.length == 0) this.reloadColorList(); 1649 /* take the next color from the list and colorize this nickname */ 1650 var cid = Math.round(Math.random()*(this.colorlist.length-1)); 1651 nc = this.colorlist[cid]; 1652 this.colorlist.splice(cid,1); 1653 this.nickcolor.push(new Array(nick, nc)); 1654 } 1655 1656 return nc; 1657 }, 1658 1659 1660 /** 1661 * Colorize with 'color' all the nicknames found as a 'root' child 1662 */ 1663 applyNickColor: function(root, nick, color) 1664 { 1665 1666 var nicktochange = this.getElementsByClassName(root, 'pfc_nick_'+ _to_utf8(nick).md5(), ''); 1667 for(var i = 0; nicktochange.length > i; i++) 1668 nicktochange[i].style.color = color; 1669 1670 }, 1671 1672 /** 1673 * Returns a list of elements which have a clsName class 1674 */ 1675 getElementsByClassName: function( root, clsName, clsIgnore ) 1676 { 1677 var i, matches = new Array(); 1678 var els = root.getElementsByTagName('*'); 1679 var rx1 = new RegExp('.*'+clsName+'.*'); 1680 var rx2 = new RegExp('.*'+clsIgnore+'.*'); 1681 for(i=0; i<els.length; i++) { 1682 if(els.item(i).className.match(rx1) && 1683 (clsIgnore == '' || !els.item(i).className.match(rx2)) ) 1684 { 1685 matches.push(els.item(i)); 1686 } 1687 } 1688 return matches; 1689 }, 1690 1691 showClass: function(root, clsName, clsIgnore, show) 1692 { 1693 var elts = this.getElementsByClassName(root, clsName, clsIgnore); 1694 for(var i = 0; elts.length > i; i++) 1695 if (show) 1696 elts[i].style.display = 'inline'; 1697 else 1698 elts[i].style.display = 'none'; 1699 }, 1700 1701 1702 /** 1703 * Nickname marker show/hide 1704 */ 1705 nickmarker_swap: function() 1706 { 1707 if (this.nickmarker) { 1708 this.nickmarker = false; 1709 } else { 1710 this.nickmarker = true; 1711 } 1712 this.refresh_nickmarker() 1713 setCookie('pfc_nickmarker', this.nickmarker); 1714 }, 1715 refresh_nickmarker: function(root) 1716 { 1717 var nickmarker_icon = $('pfc_nickmarker'); 1718 if (!root) root = $('pfc_channels_content'); 1719 if (this.nickmarker) 1720 { 1721 nickmarker_icon.src = this.res.getFileUrl('images/color-on.gif'); 1722 nickmarker_icon.alt = this.res.getLabel("Hide nickname marker"); 1723 nickmarker_icon.title = nickmarker_icon.alt; 1724 this.colorizeNicks(root); 1725 } 1726 else 1727 { 1728 nickmarker_icon.src = this.res.getFileUrl('images/color-off.gif'); 1729 nickmarker_icon.alt = this.res.getLabel("Show nickname marker"); 1730 nickmarker_icon.title = nickmarker_icon.alt; 1731 var elts = this.getElementsByClassName(root, 'pfc_nickmarker', ''); 1732 for(var i = 0; elts.length > i; i++) 1733 { 1734 // this is not supported in konqueror =>>> elts[i].removeAttribute('style'); 1735 elts[i].style.color = ''; 1736 } 1737 } 1738 }, 1739 1740 1741 /** 1742 * Date/Hour show/hide 1743 */ 1744 clock_swap: function() 1745 { 1746 if (this.clock) { 1747 this.clock = false; 1748 } else { 1749 this.clock = true; 1750 } 1751 this.refresh_clock(); 1752 setCookie('pfc_clock', this.clock); 1753 }, 1754 refresh_clock: function( root ) 1755 { 1756 var clock_icon = $('pfc_clock'); 1757 if (!root) root = $('pfc_channels_content'); 1758 if (this.clock) 1759 { 1760 clock_icon.src = this.res.getFileUrl('images/clock-on.gif'); 1761 clock_icon.alt = this.res.getLabel('Hide dates and hours'); 1762 clock_icon.title = clock_icon.alt; 1763 this.showClass(root, 'pfc_date', 'pfc_invisible', true); 1764 this.showClass(root, 'pfc_heure', 'pfc_invisible', true); 1765 } 1766 else 1767 { 1768 clock_icon.src = this.res.getFileUrl('images/clock-off.gif'); 1769 clock_icon.alt = this.res.getLabel('Show dates and hours'); 1770 clock_icon.title = clock_icon.alt; 1771 this.showClass(root, 'pfc_date', 'pfc_invisible', false); 1772 this.showClass(root, 'pfc_heure', 'pfc_invisible', false); 1773 } 1774 // browser automaticaly scroll up misteriously when showing the dates 1775 // $('pfc_chat').scrollTop += 30; 1776 }, 1777 1778 /** 1779 * Sound button 1780 */ 1781 sound_swap: function() 1782 { 1783 if (this.issoundenable) { 1784 this.issoundenable = false; 1785 } else { 1786 this.issoundenable = true; 1787 } 1788 this.refresh_sound(); 1789 setCookie('pfc_issoundenable', this.issoundenable); 1790 }, 1791 refresh_sound: function( root ) 1792 { 1793 var snd_icon = $('pfc_sound'); 1794 if (this.issoundenable) 1795 { 1796 snd_icon.src = this.res.getFileUrl('images/sound-on.gif'); 1797 snd_icon.alt = this.res.getLabel('Disable sound notifications'); 1798 snd_icon.title = snd_icon.alt; 1799 } 1800 else 1801 { 1802 snd_icon.src = this.res.getFileUrl('images/sound-off.gif'); 1803 snd_icon.alt = this.res.getLabel('Enable sound notifications'); 1804 snd_icon.title = snd_icon.alt; 1805 } 1806 }, 1807 1808 /** 1809 * Connect/disconnect button 1810 */ 1811 connect_disconnect: function() 1812 { 1813 if (this.isconnected) 1814 this.sendRequest('/quit'); 1815 else 1816 { 1817 if (this.nickname == '') 1818 this.askNick(); 1819 else 1820 this.sendRequest('/connect "'+this.nickname+'"'); 1821 } 1822 }, 1823 refresh_loginlogout: function() 1824 { 1825 var loginlogout_icon = $('pfc_loginlogout'); 1826 if (this.isconnected) 1827 { 1828 loginlogout_icon.src = this.res.getFileUrl('images/logout.gif'); 1829 loginlogout_icon.alt = this.res.getLabel('Disconnect'); 1830 loginlogout_icon.title = loginlogout_icon.alt; 1831 } 1832 else 1833 { 1834 this.clearMessages(); 1835 this.clearNickList(); 1836 loginlogout_icon.src = this.res.getFileUrl('images/login.gif'); 1837 loginlogout_icon.alt = this.res.getLabel('Connect'); 1838 loginlogout_icon.title = loginlogout_icon.alt; 1839 } 1840 }, 1841 1842 1843 /** 1844 * Minimize/Maximized the chat zone 1845 */ 1846 swap_minimize_maximize: function() 1847 { 1848 if (this.minmax_status) { 1849 this.minmax_status = false; 1850 } else { 1851 this.minmax_status = true; 1852 } 1853 setCookie('pfc_minmax_status', this.minmax_status); 1854 this.refresh_minimize_maximize(); 1855 }, 1856 refresh_minimize_maximize: function() 1857 { 1858 var content = $('pfc_content_expandable'); 1859 var btn = $('pfc_minmax'); 1860 if (this.minmax_status) 1861 { 1862 btn.src = this.res.getFileUrl('images/maximize.gif'); 1863 btn.alt = this.res.getLabel('Magnify'); 1864 btn.title = btn.alt; 1865 content.style.display = 'none'; 1866 } 1867 else 1868 { 1869 btn.src = this.res.getFileUrl('images/minimize.gif'); 1870 btn.alt = this.res.getLabel('Cut down'); 1871 btn.title = btn.alt; 1872 content.style.display = 'block'; 1873 } 1874 }, 1875 1876 1877 /** 1878 * BBcode ToolBar 1879 */ 1880 insert_text: function(open, close, promptifselempty) 1881 { 1882 var msgfield = $('pfc_words'); 1883 1884 var pfcp = this.getPrompt(); 1885 pfcp.msgfield = msgfield; 1886 pfcp.open = open; 1887 pfcp.close = close; 1888 pfcp.promptifselempty = promptifselempty; 1889 pfcp.callback = this.insert_text_callback; 1890 1891 // Gecko 1892 /* Always check for Gecko selection processing commands 1893 first. This is needed for Opera. */ 1894 if (msgfield.selectionStart || msgfield.selectionStart == '0') 1895 { 1896 var startPos = msgfield.selectionStart; 1897 var endPos = msgfield.selectionEnd; 1898 1899 var text = msgfield.value.substring(startPos, endPos); 1900 if (startPos == endPos && promptifselempty) 1901 { 1902 pfcp.prompt(this.res.getLabel('Enter the text to format'), ''); 1903 pfcp.focus(); 1904 } 1905 else 1906 this.insert_text_callback(text, pfcp); 1907 } 1908 1909 // IE 1910 else if (document.selection && document.selection.createRange) 1911 { 1912 msgfield.focus(); 1913 1914 // Get selection range. 1915 pfcp.range = this.setSelection(msgfield); 1916 var text = pfcp.range.text; 1917 if (text == "" && promptifselempty) 1918 { 1919 pfcp.prompt(this.res.getLabel('Enter the text to format'), ''); 1920 pfcp.focus(); 1921 } 1922 else 1923 this.insert_text_callback(text, pfcp); 1924 } 1925 1926 // Fallback support for other browsers 1927 else 1928 { 1929 pfcp.prompt(this.res.getLabel('Enter the text to format'), ''); 1930 pfcp.focus(); 1931 } 1932 return; 1933 }, 1934 insert_text_callback: function(text, pfcp) 1935 { 1936 var open = pfcp.open; 1937 var close = pfcp.close; 1938 var promptifselempty = pfcp.promptifselempty; 1939 var msgfield = pfcp.msgfield; 1940 var range = pfcp.range; 1941 1942 // Gecko 1943 /* Always check for Gecko selection processing commands 1944 first. This is needed for Opera. */ 1945 if (msgfield.selectionStart || msgfield.selectionStart == '0') 1946 { 1947 var startPos = msgfield.selectionStart; 1948 var endPos = msgfield.selectionEnd; 1949 1950 var extralength = 0; 1951 if (startPos == endPos && promptifselempty) 1952 { 1953 if (text == null) text = ""; 1954 extralength = text.length; 1955 } 1956 if (text.length > 0 || !promptifselempty) 1957 { 1958 msgfield.value = msgfield.value.substring(0, startPos) + open + text + close + msgfield.value.substring(endPos, msgfield.value.length); 1959 var caretPos = endPos + open.length + extralength + close.length; 1960 msgfield.setSelectionRange(caretPos, caretPos); 1961 msgfield.focus(); 1962 } 1963 } 1964 // IE 1965 else if (document.selection && document.selection.createRange) 1966 { 1967 if (text == null) text = ""; 1968 if (text.length > 0 || !promptifselempty) 1969 { 1970 msgfield.focus(); 1971 1972 range.text = open + text + close; 1973 1974 // Increment caret position. 1975 // Check if internally kept values for selection are initialized. 1976 msgfield.selStart = (msgfield.selStart) ? msgfield.selStart + open.length + text.length + close.length : open.length + text.length + close.length; 1977 msgfield.selEnd = msgfield.selStart; 1978 1979 msgfield.focus(); 1980 } 1981 } 1982 // Fallback support for other browsers 1983 else 1984 { 1985 if (text == null) text = ""; 1986 if (text.length > 0 || !promptifselempty) 1987 { 1988 msgfield.value += open + text + close; 1989 msgfield.focus(); 1990 } 1991 } 1992 }, 1993 1994 /** 1995 * Minimize/Maximize none/inline 1996 */ 1997 minimize_maximize: function(idname, type) 1998 { 1999 var element = $(idname); 2000 if(element.style) 2001 { 2002 if(element.style.display == type ) 2003 { 2004 element.style.display = 'none'; 2005 } 2006 else 2007 { 2008 element.style.display = type; 2009 } 2010 } 2011 }, 2012 2013 switch_text_color: function(color) 2014 { 2015 /* clear any existing borders on the color buttons */ 2016 var colorbtn = this.getElementsByClassName($('pfc_colorlist'), 'pfc_color', ''); 2017 for(var i = 0; colorbtn.length > i; i++) 2018 { 2019 colorbtn[i].style.border = 'none'; 2020 colorbtn[i].style.padding = '0'; 2021 } 2022 2023 /* assign the new border style to the selected button */ 2024 this.current_text_color = color; 2025 setCookie('pfc_current_text_color', this.current_text_color); 2026 var idname = 'pfc_color_' + color; 2027 $(idname).style.border = '1px solid #555'; 2028 $(idname).style.padding = '1px'; 2029 2030 // assigne the new color to the input text box 2031 this.el_words.style.color = '#'+color; 2032 this.el_words.focus(); 2033 }, 2034 2035 /** 2036 * Smiley show/hide 2037 */ 2038 showHideSmileys: function() 2039 { 2040 if (this.showsmileys) 2041 { 2042 this.showsmileys = false; 2043 } 2044 else 2045 { 2046 this.showsmileys = true; 2047 } 2048 setCookie('pfc_showsmileys', this.showsmileys); 2049 this.refresh_Smileys(); 2050 }, 2051 refresh_Smileys: function() 2052 { 2053 // first of all : show/hide the smiley box 2054 var content = $('pfc_smileys'); 2055 if (this.showsmileys) 2056 content.style.display = 'block'; 2057 else 2058 content.style.display = 'none'; 2059 2060 // then switch the button icon 2061 var btn = $('pfc_showHideSmileysbtn'); 2062 if (this.showsmileys) 2063 { 2064 if (btn) 2065 { 2066 btn.src = this.res.getFileUrl('images/smiley-on.gif'); 2067 btn.alt = this.res.getLabel('Hide smiley box'); 2068 btn.title = btn.alt; 2069 } 2070 } 2071 else 2072 { 2073 if (btn) 2074 { 2075 btn.src = this.res.getFileUrl('images/smiley-off.gif'); 2076 btn.alt = this.res.getLabel('Show smiley box'); 2077 btn.title = btn.alt; 2078 } 2079 } 2080 }, 2081 2082 2083 /** 2084 * Show Hide who's online 2085 */ 2086 showHideWhosOnline: function() 2087 { 2088 if (this.showwhosonline) 2089 { 2090 this.showwhosonline = false; 2091 } 2092 else 2093 { 2094 this.showwhosonline = true; 2095 } 2096 setCookie('pfc_showwhosonline', this.showwhosonline); 2097 this.refresh_WhosOnline(); 2098 }, 2099 refresh_WhosOnline: function() 2100 { 2101 // first of all : show/hide the nickname list box 2102 var root = $('pfc_channels_content'); 2103 var contentlist = this.getElementsByClassName(root, 'pfc_online', ''); 2104 for(var i = 0; i < contentlist.length; i++) 2105 { 2106 var content = contentlist[i]; 2107 if (this.showwhosonline) 2108 content.style.display = 'block'; 2109 else 2110 content.style.display = 'none'; 2111 content.style.zIndex = '100'; // for IE6, force the nickname list borders to be shown 2112 } 2113 2114 // then refresh the button icon 2115 var btn = $('pfc_showHideWhosOnlineBtn'); 2116 if (!btn) return; 2117 if (this.showwhosonline) 2118 { 2119 btn.src = this.res.getFileUrl('images/online-on.gif'); 2120 btn.alt = this.res.getLabel('Hide online users box'); 2121 btn.title = btn.alt; 2122 } 2123 else 2124 { 2125 btn.src = this.res.getFileUrl('images/online-off.gif'); 2126 btn.alt = this.res.getLabel('Show online users box'); 2127 btn.title = btn.alt; 2128 } 2129 this.refresh_Chat(); 2130 }, 2131 2132 /** 2133 * Resize chat 2134 */ 2135 refresh_Chat: function() 2136 { 2137 // resize all the tabs content 2138 var root = $('pfc_channels_content'); 2139 var contentlist = this.getElementsByClassName(root, 'pfc_chat', ''); 2140 for(var i = 0; i < contentlist.length; i++) 2141 { 2142 var chatdiv = contentlist[i]; 2143 if (!this.showwhosonline) 2144 { 2145 chatdiv.style.width = '100%'; 2146 } 2147 else 2148 { 2149 chatdiv.style.width = ''; 2150 } 2151 } 2152 }, 2153 2154 getPrompt: function() 2155 { 2156 if (!this.pfc) 2157 this.pfc = new pfcPrompt($('pfc_container')); 2158 return this.pfc; 2159 } 2160}; 2161