omnomirc.js 24 KB

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