omnomirc.js 24 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007
  1. /*
  2. OmnomIRC COPYRIGHT 2010,2011 Netham45
  3. OmnomIRC3 rewrite COPYRIGHT 2013 Nathaniel 'Eeems' van Diepen
  4. This file is part of OmnomIRC.
  5. OmnomIRC is free software: you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation, either version 3 of the License, or
  8. (at your option) any later version.
  9. OmnomIRC is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with OmnomIRC. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. (function(window,$,io,undefined){
  17. var $o = window.OmnomIRC = window.$o = function(){
  18. return 'Version: '+version;
  19. },
  20. event = function(msg,type){
  21. type=typeof type == 'undefined'?'event':type;
  22. switch(type){
  23. case 'ready':type='document_ready';break;
  24. }
  25. log('['+type.toUpperCase()+'] '+msg);
  26. },
  27. emit = window.emit = function(type,data){
  28. if($o.chat.connected()){
  29. socket.emit.apply(socket,arguments);
  30. }else{
  31. if(tabs.length > 0){
  32. $o.msg('Disconnected, cannot do anything');
  33. }
  34. }
  35. },
  36. noop = function(){},
  37. log = function(){
  38. console.log.apply(console,arguments);
  39. },
  40. exists = function(object){
  41. return typeof object != 'undefined';
  42. },
  43. prevent = function(e){
  44. e.stopImmediatePropagation();
  45. e.stopPropagation();
  46. e.preventDefault();
  47. return false;
  48. },
  49. selectedTab=0,
  50. settings = {
  51. colour: false,
  52. timestamp: 'exact',
  53. server: location.origin,
  54. autoconnect: true,
  55. autojoin: [
  56. '#omnimaga',
  57. '#omnimaga-fr',
  58. '#irp'
  59. ],
  60. scrollspeed: 100,
  61. theme: 'default',
  62. nick: 'User'
  63. },
  64. tabs = [],
  65. properties = {
  66. nick: 'User',
  67. sig: '',
  68. tabs: tabs,
  69. themes: [
  70. 'default'
  71. ]
  72. },
  73. commands = [
  74. { // names
  75. cmd: 'names',
  76. fn: function(args){
  77. emit('names',{
  78. name: $o.ui.tabs.current().name
  79. });
  80. }
  81. },
  82. { // me
  83. cmd: 'me',
  84. help: 'Say something in third person',
  85. fn: function(args){
  86. var i,ret='';
  87. for(i=1;i<args.length;i++){
  88. ret += ' '+args[i];
  89. }
  90. emit('message',{
  91. from: 0,
  92. message: properties.nick+' '+ret,
  93. room: $o.ui.tabs.current().name
  94. });
  95. }
  96. },
  97. { // connect
  98. cmd: 'connect',
  99. fn: function(){
  100. if(!$o.chat.connected()){
  101. $o.chat.connect();
  102. }
  103. }
  104. },
  105. { // disconnect
  106. cmd: 'disconnect',
  107. fn: function(){
  108. $o.disconnect();
  109. }
  110. },
  111. { // nick
  112. cmd: 'nick',
  113. fn: function(args){
  114. $o.set('nick',args[1]);
  115. }
  116. },
  117. { // help
  118. cmd: 'help',
  119. fn: function(args){
  120. if(typeof args[1] == 'undefined'){
  121. var m = 'Commands:',i;
  122. for(i in commands){
  123. m += ' '+commands[i].cmd;
  124. }
  125. $o.msg(m);
  126. }else{
  127. var i,cmd;
  128. for(i in commands){
  129. cmd = commands[i];
  130. if(cmd.cmd == args[1] && typeof cmd.help != 'undefined'){
  131. $o.msg('Command /'+cmd.cmd+': '+cmd.help);
  132. return;
  133. }
  134. }
  135. $o.send('/help');
  136. }
  137. }
  138. },
  139. { // open
  140. cmd: 'open',
  141. fn: function(args){
  142. $o.ui.tabs.add(args[1]);
  143. }
  144. },
  145. { // clear
  146. cmd: 'clear',
  147. fn: function(args){
  148. $o.ui.tabs.current().clear();
  149. }
  150. },
  151. { // close
  152. cmd: 'close',
  153. fn: function(args){
  154. if(args.length > 1){
  155. $o.ui.tabs.remove(args[1]);
  156. }else{
  157. $o.ui.tabs.remove(selectedTab);
  158. }
  159. }
  160. },
  161. { // tabs
  162. cmd: 'tabs',
  163. fn: function(args){
  164. $o.msg('tabs:');
  165. for(var i in tabs){
  166. $o.msg(' ['+i+'] '+tabs[i].name);
  167. }
  168. }
  169. }
  170. ],
  171. handles = [
  172. { // names
  173. on: 'names',
  174. fn: function(data){
  175. var tab = $o.ui.tabs.tab(data.room),
  176. users = tab.users,
  177. i;
  178. tab.users = data.names;
  179. if($o.ui.tabs.idForName(data.room) == selectedTab){
  180. $o.ui.render.users();
  181. }
  182. $(users).each(function(i,v){
  183. if(v != null){
  184. if(tab.users.indexOf(v.trim()) == -1){
  185. emit('echo',{
  186. room: $o.ui.tabs.current().name,
  187. message: v+' left the room',
  188. from: 0
  189. });
  190. }
  191. }
  192. });
  193. }
  194. },
  195. { // authorized
  196. on: 'authorized',
  197. fn: function(data){
  198. properties.nick = data.nick;
  199. for(var i in settings.autojoin){
  200. emit('join',{
  201. name: settings.autojoin[i]
  202. });
  203. }
  204. }
  205. },
  206. { // join
  207. on: 'join',
  208. fn: function(data){
  209. event('joined '+data.name);
  210. var flag = tabs.length == 0;
  211. $o.ui.tabs.add(data.name);
  212. if(flag){
  213. $o.ui.tabs.select(0);
  214. }
  215. }
  216. },
  217. { // reconnect
  218. on: 'reconnect',
  219. fn: function(data){
  220. event('reconnected');
  221. properties.connected = true;
  222. $o.chat.auth();
  223. emit('echo',{
  224. room: $o.ui.tabs.current().name,
  225. from: 0,
  226. message: 'reconnected'
  227. });
  228. }
  229. },
  230. { // connect
  231. on: 'connect',
  232. fn: function(data){
  233. event('connected');
  234. properties.connected = true;
  235. $o.chat.auth();
  236. emit('echo',{
  237. room: $o.ui.tabs.current().name,
  238. from: 0,
  239. message: 'connected'
  240. });
  241. }
  242. },
  243. { // disconnect
  244. on: 'disconnect',
  245. fn: function(data){
  246. event('disconnected');
  247. properties.connected = false;
  248. $o.msg('* disconnected');
  249. }
  250. },
  251. { // message
  252. on: 'message',
  253. fn: function(data){
  254. event('recieved message');
  255. var date = new Date(),
  256. string,
  257. time = date.getTime(),
  258. child,
  259. i,
  260. msg = function(msg){
  261. string = '<span class="cell date_cell">[<abbr class="date date_'+time+'" title="'+date.toISOString()+'"></abbr>]</span>';
  262. child = $('<li>').html(string+'<span class="cell">'+
  263. msg
  264. .htmlentities()
  265. .replace(
  266. /(https?:\/\/(([-\w\.]+)+(:\d+)?(\/([\w/_\.]*(\?\S+)?)?)?))/g,
  267. "<a href=\"$1\" title=\"\">$1</a>"
  268. )
  269. +'</span>');
  270. $o.msg({html:child},data.room);
  271. };
  272. if(data.from != 0){
  273. msg(' <'+data.from+'> '+data.message);
  274. }else{
  275. msg(' * '+data.message);
  276. }
  277. abbrDate('abbr.date_'+time);
  278. if(settings.timestamp == ''){
  279. $('.date_cell').css('visibility','hidden');
  280. }else{
  281. $('.date_cell').css('visibility','visible');
  282. }
  283. }
  284. }
  285. ],
  286. hooks = [
  287. { // load - style
  288. type: 'style',
  289. hook: 'load',
  290. fn: function(){
  291. }
  292. }
  293. ],
  294. runHook = function(name){
  295. var i,hook;
  296. for(i in hooks){
  297. hook = hooks[i];
  298. if(hook.hook == name){
  299. with({
  300. // Sandbox
  301. }){
  302. hook.fn();
  303. }
  304. }
  305. }
  306. },
  307. version = '3.0',
  308. abbrDate = function(selector){
  309. if(settings.timestamp == 'fuzzy'){
  310. $(selector).timeago();
  311. }else{
  312. $(selector).each(function(){
  313. var timestamp = settings.timestamp,
  314. i,
  315. text='',
  316. date = new Date($(this).attr('title'));
  317. if(timestamp == 'exact'){
  318. timestamp = 'H:m:s t';
  319. }
  320. for(i=0;i<timestamp.length;i++){
  321. switch(timestamp[i]){
  322. case 'H':text+=((date.getHours()+11)%12)+1;break;
  323. case 'h':text+=date.getHours();break;
  324. case 'm':text+=(date.getMinutes()>9?'':'0')+date.getMinutes();break;
  325. case 's':text+=(date.getSeconds()>9?'':'0')+date.getSeconds();break;
  326. case 't':text+=(date.getHours()>11)?'pm':'am';break;
  327. default:text+=timestamp[i];
  328. }
  329. }
  330. $(this).text(text);
  331. }).timeago('dispose');
  332. }
  333. },
  334. socket,$i,$s,$h,$cl,$tl,hht;
  335. $.extend($o,{
  336. version: function(){
  337. return version;
  338. },
  339. register: {
  340. theme: function(name){
  341. if(-1==$.inArray(properties.themes,name)){
  342. properties.themes.push(name);
  343. return true;
  344. }
  345. return false;
  346. },
  347. command: function(name,fn,help){
  348. if(-1==$.inArray(commands,name)){
  349. var o = {
  350. cmd: name,
  351. fn: fn
  352. };
  353. if(typeof help != 'undefined'){
  354. o.help = help;
  355. }
  356. commands.push(o);
  357. return true;
  358. }
  359. return false;
  360. },
  361. plugin: function(){
  362. // STUB
  363. },
  364. setting: function(name,defaultVal,validate,values){
  365. // STUB
  366. },
  367. hook: function(event,fn){
  368. }
  369. },
  370. hook: function(event,fn){
  371. $o.register.hook(event,fn);
  372. },
  373. ui: {
  374. render: {
  375. settings: function(){
  376. var name,setting,frag = document.createDocumentFragment(),item;
  377. for(name in settings){
  378. setting = $o.get(name,true);
  379. switch(setting.type){
  380. case 'select':
  381. item = $('<select>')
  382. .attr('id','setting_'+name)
  383. .change(function(){
  384. $o.set(this.id.substr(8),$(this).find(':selected').text(),false);
  385. });
  386. for(var i in setting.values){
  387. item.append(
  388. $('<option>')
  389. .text(setting.values[i])
  390. );
  391. }
  392. item.find(':contains('+setting.val+')').attr('selected','selected');
  393. break;
  394. case 'array':
  395. item = $('<input>')
  396. .attr({
  397. type: 'text',
  398. id: 'setting_'+name
  399. })
  400. .val(setting.val)
  401. .change(function(){
  402. $o.set(this.id.substr(8),$(this).val().split(','),false);
  403. });
  404. break;
  405. case 'boolean':
  406. item = $('<input>')
  407. .attr({
  408. type: 'checkbox',
  409. id: 'setting_'+name
  410. })
  411. .change(function(){
  412. $o.set(this.id.substr(8),$(this).is(':checked'),false);
  413. });
  414. if(setting.val){
  415. item.attr('checked','checked');
  416. }
  417. break;
  418. case 'number':
  419. case 'string':default:
  420. item = $('<input>')
  421. .attr({
  422. type: 'text',
  423. id: 'setting_'+name
  424. })
  425. .val(setting.val)
  426. .change(function(){
  427. $o.set(this.id.substr(8),$(this).val(),false);
  428. });
  429. }
  430. $(frag).append(
  431. $('<li>')
  432. .addClass('row')
  433. .append(
  434. $('<span>')
  435. .text(name)
  436. .addClass('cell')
  437. )
  438. .append(
  439. $('<span>')
  440. .append(item)
  441. .addClass('cell')
  442. )
  443. );
  444. }
  445. $('#settings-list').html(frag);
  446. },
  447. users: function(){
  448. event('Rendering userlist');
  449. var $ul = $('#user-list').html(''),
  450. i,
  451. names = $o.ui.tabs.current().users;
  452. for(i in names){
  453. $ul.append(
  454. $('<li>').text(names[i])
  455. );
  456. }
  457. },
  458. tab: function(){
  459. $cl.html($($o.ui.tabs.current().body).clone());
  460. },
  461. tablist: function(){
  462. $tl.html('');
  463. var i,tab;
  464. for(i in tabs){
  465. tab = $o.ui.tabs.obj(i);
  466. if(i==selectedTab){
  467. tab.addClass('clicked');
  468. $('#title').text(tabs[i].name);
  469. $('#topic').text(tabs[i].topic);
  470. }
  471. $tl.append(tab);
  472. }
  473. if($tl.get(0).scrollHeight-20 != $tl.scrollTop()){
  474. $('#tabs-scroll-right').removeClass('disabled');
  475. }
  476. if($tl.scrollTop() != 0){
  477. $('#tabs-scroll-left').removeClass('disabled');
  478. }
  479. }
  480. },
  481. tabs: {
  482. add: function(name){
  483. event('Tab added: '+name);
  484. if(!(function(){
  485. for(var i in tabs){
  486. if(name==tabs[i].name){
  487. return true;
  488. }
  489. }
  490. return false;
  491. })()){
  492. var scroll = $.localStorage('tabs'),
  493. i,
  494. frag = document.createDocumentFragment(),
  495. id = tabs.length;
  496. for(i in scroll){
  497. if(scroll[i].name == name){
  498. scroll[i].body = $(scroll[i].body).slice(-10);
  499. $(frag)
  500. .append(scroll[i].body)
  501. .append(
  502. $('<li>').html('<span class="to_remove">-- loaded old scrollback for '+scroll[i].date+' --</span>')
  503. )
  504. .children()
  505. .children('.remove')
  506. .remove();
  507. $(frag)
  508. .children()
  509. .children('.to_remove')
  510. .removeClass('to_remove')
  511. .addClass('remove');
  512. event('loading old tab scrollback for '+name+' last saved +'+scroll[i].date);
  513. }
  514. }
  515. tabs.push({
  516. name: name,
  517. body: frag,
  518. date: new Date(),
  519. send: function(msg){
  520. $o.chat.send(msg,$o.ui.tabs.tab(id).name);
  521. },
  522. close: function(){
  523. $o.ui.tabs.remove(id);
  524. },
  525. users: [],
  526. names: function(){
  527. emit('names',{
  528. name: $o.ui.tabs.tab(id).name
  529. });
  530. },
  531. select: function(){
  532. $o.ui.tabs.select(id);
  533. },
  534. clear: function(){
  535. $cl.html('');
  536. $o.ui.tabs.tab(id).body = document.createDocumentFragment();
  537. emit('echo',{
  538. room: $o.ui.tabs.tab(id).name,
  539. message: 'messages cleared',
  540. from: 0
  541. });
  542. }
  543. });
  544. $tl.append($o.ui.tabs.obj(id));
  545. $o.ui.render.tablist();
  546. $o.ui.render.users();
  547. }else{
  548. event('Attempted to add an existing tab');
  549. }
  550. },
  551. remove: function(name){
  552. if(typeof name == 'number'){
  553. name = tabs[name].name;
  554. }
  555. for(var id=0;id<tabs.length;id++){
  556. if($o.ui.tabs.tab(id).name == name){
  557. event('Tab removed: '+$o.ui.tabs.tab(id).name);
  558. emit('part',{
  559. name: $o.ui.tabs.tab(id).name
  560. });
  561. tabs.splice(id,1);
  562. if(selectedTab==id&&selectedTab>0){
  563. selectedTab--;
  564. }
  565. break;
  566. }
  567. }
  568. $o.ui.render.tablist();
  569. $cl.html($o.ui.tabs.current().body);
  570. $o.ui.render.users();
  571. },
  572. selected: function(){
  573. return selectedTab;
  574. },
  575. idForName: function(name){
  576. for(var i in tabs){
  577. if(tabs[i].name == name){
  578. return i;
  579. }
  580. }
  581. return false;
  582. },
  583. tab: function(id){
  584. if(typeof id == 'string' && !id.isNumber()){
  585. id = $o.ui.tabs.idForName(id);
  586. if(!id) return false;
  587. }
  588. return typeof tabs[id] == 'undefined'?false:tabs[id];
  589. },
  590. dom: function(id){
  591. if(typeof id == 'string' && !id.isNumber()){
  592. id = $o.ui.tabs.idForName(id);
  593. if(!id) return false;
  594. }
  595. return typeof tabs[id] == 'undefined'?false:tabs[id].body;
  596. },
  597. obj: function(id){
  598. if(typeof id !== 'undefined'){
  599. if(typeof id == 'string' && !id.isNumber()){
  600. id = $o.ui.tabs.idForName(id);
  601. if(!id) return;
  602. }
  603. return $('<div>')
  604. .addClass('tab')
  605. .text($o.ui.tabs.tab(id).name)
  606. .mouseup(function(e){
  607. switch(e.which){
  608. case 1: // RMB
  609. if($(this).data('id')!=selectedTab){
  610. $o.ui.tabs.select($(this).data('id'));
  611. return prevent(e);
  612. }
  613. break;
  614. case 2: // MMB
  615. $(this).children('span.close-button').click();
  616. return prevent(e);
  617. break;
  618. case 3: // LMB
  619. return prevent(e);
  620. break;
  621. default:
  622. return prevent(e);
  623. }
  624. })
  625. .append(
  626. $('<span>')
  627. .addClass('close-button')
  628. .click(function(){
  629. $o.ui.tabs.remove(id);
  630. return false;
  631. })
  632. .css({
  633. 'position': 'absolute',
  634. 'background-color': 'inherit',
  635. 'top': 0,
  636. 'right': 0
  637. })
  638. .html('&times;')
  639. )
  640. .data('id',id);
  641. }
  642. },
  643. select: function(id){
  644. if(typeof id == 'string' && !id.isNumber()){
  645. id = $o.ui.tabs.idForName(id);
  646. if(!id) return false;
  647. }
  648. event(id+' '+$o.ui.tabs.tab(id).name,'tab_select');
  649. if(id<tabs.length&&id>=0){
  650. selectedTab=id;
  651. }
  652. $tl.children('.clicked').removeClass('clicked');
  653. $($tl.children().get(id)).addClass('clicked');
  654. $('#title').text($o.ui.tabs.tab(id).name);
  655. $('#topic').text($o.ui.tabs.tab(id).topic);
  656. $cl.html($($o.ui.tabs.tab(id).body).clone());
  657. abbrDate('abbr.date');
  658. $o.ui.render.users();
  659. setTimeout(function scrollContent(){
  660. if($c.scrollTop() < $c[0].scrollHeight){
  661. $c.scrollTop($c.scrollTop()+1);
  662. setTimeout(scrollContent,settings.scrollspeed);
  663. }else{
  664. event('scrolling stopped');
  665. }
  666. },settings.scrollspeed);
  667. },
  668. current: function(){
  669. if(tabs.length > 0 && tabs.length > selectedTab){
  670. return tabs[selectedTab];
  671. }else{
  672. return {
  673. name: '',
  674. body: document.createDocumentFragment(),
  675. date: new Date(),
  676. send: noop,
  677. close: noop,
  678. users: [],
  679. names: noop,
  680. select: noop,
  681. clear: noop
  682. }
  683. }
  684. }
  685. },
  686. },
  687. chat: {
  688. connect: function(server){
  689. if($o.chat.connected()){
  690. $o.disconnect();
  691. }
  692. if(typeof server == 'undefined'){
  693. server = settings.server;
  694. }
  695. socket = window.socket = io.connect(server);
  696. for(var i in handles){
  697. socket.on(handles[i].on,handles[i].fn);
  698. }
  699. $o.chat.auth();
  700. },
  701. disconnect: function(){
  702. if($o.chat.connected()){
  703. socket.disconnect();
  704. }
  705. },
  706. connected: function(){
  707. return typeof socket == 'undefined'?false:properties.connected;
  708. },
  709. send: function(msg,room){
  710. if(typeof room == 'undefined'){
  711. room = $o.ui.tabs.current().name;
  712. }
  713. if(msg !== ''){
  714. if(msg[0] == '/' && msg[1] != '/'){
  715. var args = msg.split(' '),
  716. cmd = args[0].substr(1),
  717. i;
  718. event(msg,'command');
  719. for(i in commands){
  720. if(commands[i].cmd == cmd){
  721. commands[i].fn(args);
  722. return;
  723. }
  724. }
  725. $o.msg(cmd+' is not a valid command.');
  726. }else{
  727. event(msg,'send');
  728. emit('message',{
  729. message: msg,
  730. room: room,
  731. from: properties.nick
  732. });
  733. }
  734. }
  735. },
  736. auth: function(){
  737. if(settings.nick == ''){
  738. $o.set('nick','User');
  739. return;
  740. }
  741. emit('auth',{
  742. nick: settings.nick
  743. // TODO - send authorization info
  744. });
  745. }
  746. },
  747. get: function(name,formatted){
  748. if(typeof formatted == 'undefined'){
  749. return exists(settings[name])?settings[name]:false;
  750. }else{
  751. var val = $o.get(name),
  752. type,
  753. values = false;
  754. switch(name){
  755. case 'theme':
  756. type = 'select';
  757. values = properties.themes;
  758. break;
  759. case 'autojoin':type = 'array';break;
  760. case 'timestamp':type = 'string';break;
  761. default:
  762. type = typeof val;
  763. }
  764. return {
  765. type: type,
  766. val: val,
  767. values: values,
  768. name: name
  769. };
  770. }
  771. },
  772. set: function(name,value,render){
  773. if(exists(settings[name])){
  774. settings[name] = value;
  775. $.localStorage('settings',JSON.stringify(settings));
  776. switch(name){
  777. case 'timestamp':
  778. abbrDate('abbr.date');
  779. if(settings.timestamp == ''){
  780. $('.date_cell').css('visibility','hidden');
  781. }else{
  782. $('.date_cell').css('visibility','visible');
  783. }
  784. break;
  785. case 'nick':
  786. $o.chat.auth();
  787. break;
  788. }
  789. if(typeof render == 'undefined'){
  790. $o.ui.render.settings();
  791. }
  792. return true;
  793. }else{
  794. return false;
  795. }
  796. },
  797. prop: function(name){
  798. return exists(properties[name])?properties[name]:null;
  799. },
  800. send: function(msg){
  801. $o.chat.send(msg);
  802. },
  803. msg: function(msg,tabName){
  804. var frag;
  805. console.log(tabName);
  806. if(typeof tabName == 'undefined' || tabName == $o.ui.tabs.current().name || typeof $o.ui.tabs.tab(tabName).body == 'undefined'){
  807. frag = document.createDocumentFragment();
  808. }else{
  809. frag = $o.ui.tabs.tab(tabName).body;
  810. }
  811. try{
  812. switch(typeof msg){
  813. case 'string':
  814. $(frag).append($('<li>').html(msg.htmlentities()));
  815. break;
  816. case 'object':
  817. if(typeof msg.html == 'undefined'){
  818. $(frag).append($('<li>').html('&lt;'+msg.user+'&gt;&nbsp;'+msg.text.htmlentities()));
  819. }else{
  820. $(frag).append(msg.html);
  821. }
  822. break;
  823. }
  824. }catch(e){event('Failed to add message','error')}
  825. if(tabs.length > 0){
  826. $($o.ui.tabs.tab(tabName).body || $o.ui.tabs.current().body).append(frag);
  827. }
  828. var scroll = [],i,html;
  829. for(i in tabs){
  830. html = '';
  831. $(tabs[i].body).children().each(function(){
  832. html += this.outerHTML;
  833. });
  834. scroll.push({
  835. name: tabs[i].name,
  836. body: html,
  837. date: new Date().toString()
  838. });
  839. }
  840. $.localStorage('tabs',scroll);
  841. if(typeof tabName == 'undefined' || tabName == $o.ui.tabs.current().name){
  842. $o.ui.tabs.select(selectedTab);
  843. }
  844. },
  845. event: function(event_name,message){
  846. event(message,event_name);
  847. }
  848. });
  849. String.prototype.htmlentities = function(){
  850. return this
  851. .replace(/&/g, '&amp;')
  852. .replace(/</g, '&lt;')
  853. .replace(/>/g, '&gt;')
  854. .replace(/\n/g,'<br/>')
  855. .replace(/\t/g, '&nbsp;&nbsp;&nbsp;&nbsp;')
  856. .replace(/\s/g, '&nbsp;')
  857. .replace(/"/g, '&quot;');
  858. };
  859. $(document).ready(function(){
  860. $.extend(settings,$.parseJSON($.localStorage('settings')));
  861. $.localStorage('settings',JSON.stringify(settings));
  862. $i = $('#input');
  863. $s = $('#send');
  864. $cl = $('#content-list');
  865. $c = $('#content');
  866. $tl = $('#tabs-list');
  867. $h = $('#head');
  868. $s.click(function(){
  869. if(!$s.hasClass('clicked')){
  870. $s.addClass('clicked');
  871. setTimeout(function(){
  872. $s.removeClass('clicked');
  873. },500);
  874. }
  875. $o.send($i.val());
  876. $i.val('');
  877. });
  878. $i.keypress(function(e){
  879. if(e.keyCode == 13){
  880. if(!$s.hasClass('clicked')){
  881. $s.addClass('clicked');
  882. setTimeout(function(){
  883. $s.removeClass('clicked');
  884. },500);
  885. }
  886. $o.send($i.val());
  887. $i.val('');
  888. }
  889. });
  890. $('#settings, #users').click(function(){
  891. $(this).addClass('open');
  892. $(this).children('.close-button').show();
  893. }).hover(function(){
  894. $(this).addClass('hovered');
  895. },function(){
  896. $(this).removeClass('hovered');
  897. }).children('.close-button').click(function(){
  898. $(this).parent().removeClass('open');
  899. $(this).hide();
  900. return false;
  901. }).hide();
  902. $('#users').hoverIntent({
  903. out: function(){
  904. $(this).removeClass('open');
  905. $(this).children('.close-button').hide();
  906. },
  907. timeout: 1000
  908. });
  909. $('#content').click(function(){
  910. $('#settings, #users, #head').removeClass('hovered').removeClass('open');
  911. $('#settings, #users').children('.close-button').hide()
  912. });
  913. $('.unselectable').attr('unselectable','on');
  914. $.contextMenu({
  915. selector: 'div.tab',
  916. items: {
  917. add: {
  918. name: 'New Tab',
  919. icon: 'add',
  920. callback: function(){
  921. $(this).contextMenu('hide');
  922. $o.ui.tabs.add(prompt('Channel'));
  923. }
  924. },
  925. s1: '',
  926. close: {
  927. name: 'Close',
  928. icon: 'delete',
  929. callback: function(){
  930. $(this).contextMenu('hide');
  931. $o.ui.tabs.remove($(this).data('id'));
  932. }
  933. }
  934. },
  935. zIndex: 99999,
  936. trigger: 'right'
  937. });
  938. $.contextMenu({
  939. selector: '#tabs-list',
  940. items: {
  941. add: {
  942. name: 'New Tab',
  943. icon: 'add',
  944. callback: function(){
  945. $(this).contextMenu('hide');
  946. $o.ui.tabs.add(prompt('channel'));
  947. }
  948. }
  949. },
  950. zIndex: 99999,
  951. trigger: 'right'
  952. });
  953. $('#tabs-scroll-right').click(function(){
  954. event('scroll right');
  955. $tl.scrollTop(($tl.scrollTop()||0)+20);
  956. if($tl.get(0).scrollHeight-20 == $tl.scrollTop()){
  957. $('#tabs-scroll-right').addClass('disabled');
  958. }
  959. $('#tabs-scroll-left').removeClass('disabled');
  960. });
  961. $('#tabs-scroll-left').click(function(){
  962. event('scroll left');
  963. $tl.scrollTop(($tl.scrollTop()||0)-20);
  964. if($tl.scrollTop() == 0){
  965. $('#tabs-scroll-left').addClass('disabled');
  966. }
  967. $('#tabs-scroll-right').removeClass('disabled');
  968. });
  969. (function scrollup(){
  970. $('#tabs-scroll-left').click();
  971. if($tl.scrollTop() != 0){
  972. setTimeout(scrollup,10);
  973. }
  974. })();
  975. event('Date '+new Date,'ready');
  976. $h.addClass('hovered');
  977. setTimeout(function(){
  978. $h.removeClass('hovered');
  979. },1000);
  980. $o.ui.render.settings();
  981. if(settings.autoconnect){
  982. $o.chat.connect();
  983. }
  984. });
  985. delete window.io;
  986. })(window,jQuery,io);
  987. if (!Date.prototype.toISOString) {
  988. Date.prototype.toISOString = function() {
  989. function pad(n) { return n < 10 ? '0' + n : n }
  990. return this.getUTCFullYear() + '-'
  991. + pad(this.getUTCMonth() + 1) + '-'
  992. + pad(this.getUTCDate()) + 'T'
  993. + pad(this.getUTCHours()) + ':'
  994. + pad(this.getUTCMinutes()) + ':'
  995. + pad(this.getUTCSeconds()) + 'Z';
  996. };
  997. }
  998. if(!String.prototype.isNumber){
  999. String.prototype.isNumber = function(){return /^\d+$/.test(this);}
  1000. }