IP.Chat Pings + Highlight

Pings you when specified words are said in the chat.

  1. // ==UserScript==
  2. // @name IP.Chat Pings + Highlight
  3. // @namespace Makaze
  4. // @description Pings you when specified words are said in the chat.
  5. // @include *
  6. // @grant none
  7. // @version 2.4.0
  8. // ==/UserScript==
  9.  
  10. var titlePing,
  11. highlightPings,
  12. pingSound,
  13. audiblePingFile,
  14. audiblePingOnFocus,
  15. audiblePing,
  16. hasFocus = true,
  17. MakazeScriptStyles,
  18. IPChatMenuItems,
  19. pingMenu,
  20. menuButton,
  21. styleElem,
  22. defaultStyle =
  23. 'font-weight: bolder;\n' +
  24. 'font-size: 120%;\n' +
  25. 'color: #f24;\n' +
  26. 'text-shadow: 0px 1px #222;',
  27. opts,
  28. pingStyle,
  29. pings,
  30. userPings,
  31. userName,
  32. script_delay;
  33.  
  34. // Global variable constructor
  35.  
  36. function GlobalHandler() {
  37. var output;
  38.  
  39. this.receiveEvent = function(event) {
  40. output = event.detail;
  41. };
  42.  
  43. this.dispatch = function(variable, name) {
  44. document.dispatchEvent(
  45. new CustomEvent('getGlobalVar_' + name, {
  46. detail: variable
  47. })
  48. );
  49. };
  50.  
  51. this.get = function(variable) {
  52. document.addEventListener('getGlobalVar_' + variable, this.receiveEvent, false);
  53. var getGlobalScript = document.createElement('script');
  54. getGlobalScript.type = 'text/javascript';
  55. getGlobalScript.id = 'getGlobalScript';
  56. getGlobalScript.appendChild(
  57. document.createTextNode(
  58. '(' + this.dispatch.toString() + ')(' + variable + ', \'' + variable + '\');'
  59. + 'document.getElementById(\'getGlobalScript\').remove();'
  60. )
  61. );
  62. (document.body || document.documentElement).appendChild(getGlobalScript);
  63. document.removeEventListener('getGlobalVar_' + variable, this.receiveEvent, false);
  64. return output;
  65. };
  66.  
  67. this.set = function(variable, value) {
  68. switch (typeof value) {
  69. case 'string':
  70. value = '\'' + value + '\'';
  71. break;
  72. }
  73.  
  74. var setGlobalScript = document.createElement('script');
  75. setGlobalScript.type = 'text/javascript';
  76. setGlobalScript.id = 'setGlobalScript';
  77. setGlobalScript.appendChild(
  78. document.createTextNode(
  79. variable + ' = ' + value + ';'
  80. + 'document.getElementById(\'setGlobalScript\').remove();'
  81. )
  82. );
  83. (document.body || document.documentElement).appendChild(setGlobalScript);
  84. };
  85. }
  86.  
  87. // Initialize
  88.  
  89. var Globals = new GlobalHandler();
  90.  
  91. // End global variable constructor
  92.  
  93. // Classes constructor
  94.  
  95. function ClassHandler() {
  96. var self = this;
  97.  
  98. this.classList = function(elem) {
  99. return elem.className.trim().split(/[\b\s]/);
  100. };
  101.  
  102. this.hasClass = function(elem, className) {
  103. var classes = self.classList(elem),
  104. has = false,
  105. i = 0;
  106.  
  107. for (i = 0; i < classes.length; i++) {
  108. if (classes[i] === className) {
  109. has = true;
  110. break;
  111. }
  112. }
  113.  
  114. return (has);
  115. };
  116.  
  117. this.addClass = function(elem, className) {
  118. var classes;
  119.  
  120. if (!self.hasClass(elem, className)) {
  121. classes = self.classList(elem);
  122. classes.push(className);
  123. elem.className = classes.join(' ').trim();
  124. }
  125.  
  126. return self;
  127. };
  128.  
  129. this.removeClass = function(elem, className) {
  130. var classes = self.classList(elem),
  131. i = 0;
  132.  
  133. for (i = 0; i < classes.length; i++) {
  134. if (classes[i] === className) {
  135. classes.splice(i, 1);
  136. }
  137. }
  138.  
  139. elem.className = classes.join(' ').trim();
  140.  
  141. return self;
  142. };
  143.  
  144. this.toggleClass = function(elem, className) {
  145. var classes;
  146.  
  147. if (self.hasClass(elem, className)) {
  148. self.removeClass(elem, className);
  149. } else {
  150. classes = self.classList(elem);
  151. classes.push(className);
  152. elem.className = classes.join(' ').trim();
  153. }
  154.  
  155. return self;
  156. };
  157. }
  158.  
  159. // Initialize
  160.  
  161. var Classes = new ClassHandler();
  162.  
  163. // End Classes constructor
  164.  
  165. function fade(elem, type, speed) {
  166. var defaultOpacity,
  167. currentDisplay = elem.style.display || window.getComputedStyle(elem).display;
  168.  
  169. elem.style.opacity = '';
  170. defaultOpacity = window.getComputedStyle(elem).opacity;
  171. elem.style.opacity = 0;
  172.  
  173. // Default values:
  174.  
  175. switch (arguments.length) {
  176. case 1:
  177. type = 'toggle';
  178. case 2:
  179. speed = 300;
  180. break;
  181. }
  182.  
  183. switch (type) {
  184. case 'in':
  185. elem.style.display = '';
  186. setTimeout(function() {
  187. elem.style.transition = 'all ' + speed + 'ms ease-in-out';
  188. elem.style.opacity = defaultOpacity;
  189. setTimeout(function() {
  190. elem.style.transition = '';
  191. elem.style.opacity = '';
  192. }, speed + 10);
  193. }, 1);
  194. break;
  195. case 'out':
  196. elem.style.transition = '';
  197. elem.style.opacity = defaultOpacity;
  198. elem.style.transition = 'all ' + speed + 'ms ease-in-out';
  199. elem.style.opacity = 0;
  200. setTimeout(function() {
  201. elem.style.display = 'none';
  202. elem.style.transition = '';
  203. elem.style.opacity = '';
  204. }, speed + 10);
  205. break;
  206. case 'toggle':
  207. default:
  208. if (currentDisplay === 'none') {
  209. elem.style.display = '';
  210. setTimeout(function() {
  211. elem.style.transition = 'all ' + speed + 'ms ease-in-out';
  212. elem.style.opacity = defaultOpacity;
  213. setTimeout(function() {
  214. elem.style.transition = '';
  215. elem.style.opacity = '';
  216. }, speed + 10);
  217. }, 1);
  218. } else {
  219. elem.style.transition = '';
  220. elem.style.opacity = defaultOpacity;
  221. elem.style.transition = 'all ' + speed + 'ms ease-in-out';
  222. elem.style.opacity = 0;
  223. setTimeout(function() {
  224. elem.style.display = 'none';
  225. elem.style.transition = '';
  226. elem.style.opacity = '';
  227. }, speed + 10);
  228. }
  229. }
  230. }
  231.  
  232. function createElement(type, callback) {
  233. var element = document.createElement(type);
  234.  
  235. callback(element);
  236.  
  237. return element;
  238. }
  239.  
  240. function getUserName(context, userPings) {
  241. var userID = context.getElementsByClassName('ipsUserPhotoLink')[0].id.split('link_')[1],
  242. userName = context.getElementsByClassName('names')[0].getElementsByTagName('span')[0].title,
  243. newUserPings = [],
  244. i = 0,
  245. thisUserID,
  246. thisUserName;
  247.  
  248. for (i = 0; i < userPings.length; i++) {
  249. newUserPings.push({'id': userPings[i].id, 'name': (userPings[i].hasOwnProperty('name')) ? userPings[i].name : null});
  250. thisUserID = newUserPings[i].id;
  251. thisUserName = newUserPings[i].name;
  252. if (userID === thisUserID) {
  253. if (userName !== thisUserName) {
  254. newUserPings[i].name = userName;
  255. }
  256. }
  257. }
  258.  
  259. return newUserPings;
  260. }
  261.  
  262. function pingsInit() {
  263. var i = 0;
  264.  
  265. userName = Globals.get('userName');
  266. opts = (localStorage.getItem('MakazeScriptOptions')) ? JSON.parse(localStorage.getItem('MakazeScriptOptions')) : {};
  267. pingStyle = (opts.hasOwnProperty('ipc_ping_style')) ? opts.ipc_ping_style : defaultStyle;
  268. pings = (opts.hasOwnProperty('ipc_pings')) ? opts.ipc_pings : [userName];
  269. userPings = (opts.hasOwnProperty('ipc_user_pings')) ? opts.ipc_user_pings : [];
  270. audiblePing = (opts.hasOwnProperty('ipc_audible_ping')) ? opts.ipc_audible_ping : true;
  271. titlePing = (opts.hasOwnProperty('ipc_pings_in_title')) ? opts.ipc_pings_in_title : true;
  272. highlightPings = (opts.hasOwnProperty('ipc_highlight_pings')) ? opts.ipc_highlight_pings : true;
  273. audiblePingFile = (opts.hasOwnProperty('ipc_audible_ping_file')) ? opts.ipc_audible_ping_file : 'https://dl.dropboxusercontent.com/u/45569424/Saved_FE7.mp3';
  274. audiblePingOnFocus = (opts.hasOwnProperty('ipc_audible_ping_on_focus')) ? opts.ipc_audible_ping_on_focus : false;
  275.  
  276. pingSound = new Audio(audiblePingFile);
  277.  
  278. // Styling
  279.  
  280. if (document.getElementById('MakazeScriptStyles') == null) {
  281. MakazeScriptStyles = createElement('style', function(style) {
  282. style.id = 'MakazeScriptStyles';
  283. style.type = 'text/css';
  284. });
  285. document.head.appendChild(MakazeScriptStyles);
  286. }
  287.  
  288. styleElem = document.getElementById('MakazeScriptStyles');
  289.  
  290. if (styleElem.hasChildNodes()) {
  291. styleElem.childNodes[0].nodeValue += '\n\n';
  292. } else {
  293. styleElem.appendChild(document.createTextNode(''));
  294. }
  295.  
  296. if (!styleElem.childNodes[0].nodeValue.match('.MakazeScriptMenu')) {
  297. styleElem.childNodes[0].nodeValue += '.MakazeScriptMenu { position: fixed; z-index: 99999; top: 50%; left: 50%; padding: 10px; background-color: rgba(255, 255, 255, .85); box-shadow: 0px 0px 3px #888; border-radius: 5px; } .MakazeScriptMenu th { font-weight: bolder; } .MakazeScriptMenu th, .MakazeScriptMenu td { padding: 3px; } .MakazeScriptMenu .menu-save { text-align: center; margin-top: 6px; } .MakazeScriptMenu .menu-save > a { padding: 2px 10px; border: 1px solid #ccc; border-radius: 3px; font-weight: bolder; cursor: pointer; } .MakazeScriptMenu .menuTitle { margin-bottom: 10px; font-weight: bolder; } .MakazeScriptMenu .scrollableContent { width: 312px; height: 150px; overflow: auto; padding: 2px; } .MakazeScriptMenu textarea, .MakazeScriptMenu input[type=text], .MakazeScriptMenu input[type=number] { font-family: Consolas, Ubuntu Mono, sans-serif; font-size: 10px; color: #333; padding: 3px; box-sizing: border-box; }\n\n';
  298. }
  299.  
  300. styleElem.childNodes[0].nodeValue +=
  301. '#pingsettings {\n' +
  302. 'margin-top: -174px;\n' +
  303. 'margin-left: -235px;\n' +
  304. '}\n\n' +
  305.  
  306. '#pingsettings textarea {\n' +
  307. 'width: 144px;\n' +
  308. 'height: 144px;\n' +
  309. '}\n\n' +
  310.  
  311. '#pingsettings input {\n' +
  312. 'vertical-align: middle;\n' +
  313. '}';
  314.  
  315. // Menu creation
  316.  
  317. var pingMenu_options = createElement('table', function(table) {
  318. table.appendChild(createElement('thead', function(thead) {
  319. thead.appendChild(createElement('tr', function(row) {
  320. row.appendChild(createElement('th', function(cell) {
  321. cell.appendChild(document.createTextNode('Style'));
  322. }));
  323.  
  324. row.appendChild(createElement('th', function(cell) {
  325. cell.appendChild(document.createTextNode('Pings'));
  326. }));
  327.  
  328. row.appendChild(createElement('th', function(cell) {
  329. cell.appendChild(document.createTextNode('Pinged Users'));
  330. }));
  331. }));
  332. }));
  333.  
  334. table.appendChild(createElement('tbody', function(tbody) {
  335. tbody.appendChild(createElement('tr', function(row) {
  336. row.appendChild(createElement('td', function(cell) {
  337. cell.appendChild(createElement('textarea', function(input) {
  338. input.id = 'pingStyle';
  339. input.placeholder = 'Enter CSS for pinged word';
  340. input.value = pingStyle;
  341. }));
  342. }));
  343.  
  344. row.appendChild(createElement('td', function(cell) {
  345. cell.appendChild(createElement('textarea', function(input) {
  346. input.id = 'pingList';
  347. input.placeholder = 'Enter words to ping seperated by newlines';
  348. input.value = pings.join('\n');
  349. }));
  350. }));
  351.  
  352. row.appendChild(createElement('td', function(cell) {
  353. cell.appendChild(createElement('textarea', function(input) {
  354. input.id = 'userPingList';
  355. input.placeholder = 'Enter users to ping on join seperated by newlines';
  356.  
  357. var tempUserPingList = [];
  358.  
  359. for (i = 0; i < userPings.length; i++) {
  360. if (!userPings[i].hasOwnProperty('name') || userPings[i].name === null) {
  361. tempUserPingList.push(userPings[i].id);
  362. } else {
  363. tempUserPingList.push(userPings[i].id + '//' + userPings[i].name);
  364. }
  365. }
  366.  
  367. input.value = tempUserPingList.join('\n');
  368. }));
  369. }));
  370. }));
  371.  
  372. tbody.appendChild(createElement('tr', function(row) {
  373. row.appendChild(createElement('td', function(cell) {
  374. cell.setAttribute('colspan', 3);
  375. cell.style.textAlign = 'center';
  376.  
  377. cell.appendChild(createElement('div', function(cont) {
  378. cont.style.display = 'inline-block';
  379. cont.style.textAlign = 'left';
  380.  
  381. cont.appendChild(createElement('div', function(field) {
  382. field.appendChild(createElement('input', function(input) {
  383. input.id = 'audiblePingSwitch';
  384. input.type = 'checkbox';
  385. input.checked = audiblePing;
  386. }));
  387.  
  388. field.appendChild(document.createTextNode(' Play sound when pinged'));
  389. }));
  390.  
  391. cont.appendChild(createElement('div', function(field) {
  392. field.appendChild(createElement('input', function(input) {
  393. input.id = 'titlePingSwitch';
  394. input.type = 'checkbox';
  395. input.checked = titlePing;
  396. }));
  397.  
  398. field.appendChild(document.createTextNode(' Change page title when pinged'));
  399. }));
  400.  
  401. cont.appendChild(createElement('div', function(field) {
  402. field.appendChild(createElement('input', function(input) {
  403. input.id = 'highlightPingsSwitch';
  404. input.type = 'checkbox';
  405. input.checked = highlightPings;
  406. }));
  407.  
  408. field.appendChild(document.createTextNode(' Highlight pings in the chat'));
  409. }));
  410.  
  411. cont.appendChild(createElement('div', function(field) {
  412. field.appendChild(createElement('input', function(input) {
  413. input.id = 'audiblePingOnFocusSwitch';
  414. input.type = 'checkbox';
  415. input.checked = audiblePingOnFocus;
  416. }));
  417.  
  418. field.appendChild(document.createTextNode(' Play audible ping when the page is focused'));
  419. }));
  420.  
  421. cont.appendChild(createElement('div', function(field) {
  422. field.style.display = 'table';
  423. field.style.width = '100%';
  424. field.style.marginTop = '1em';
  425.  
  426. field.appendChild(createElement('span', function(name) {
  427. name.style.display = 'table-cell';
  428. name.style.whiteSpace = 'pre';
  429. name.appendChild(document.createTextNode('Audible ping file: '));
  430. }));
  431.  
  432. field.appendChild(createElement('span', function(content) {
  433. content.style.display = 'table-cell';
  434. content.style.width = '100%';
  435.  
  436. content.appendChild(createElement('input', function(input) {
  437. input.id = 'audiblePingFile';
  438. input.type = 'text';
  439. input.placeholder = 'Enter a sound file to play when pinged';
  440. input.style.width = '100%';
  441. input.value = audiblePingFile;
  442. }));
  443. }));
  444. }));
  445.  
  446. cont.appendChild(createElement('div', function(field) {
  447. field.style.display = 'table';
  448. field.style.width = '100%';
  449. field.style.marginTop = '1em';
  450.  
  451. field.appendChild(createElement('span', function(name) {
  452. name.style.display = 'table-cell';
  453. name.style.whiteSpace = 'pre';
  454. name.appendChild(document.createTextNode('Script delay (in ms): '));
  455. }));
  456.  
  457. field.appendChild(createElement('span', function(content) {
  458. content.style.display = 'table-cell';
  459. content.style.width = '100%';
  460.  
  461. content.appendChild(createElement('input', function(input) {
  462. input.id = 'pingScriptDelay';
  463. input.type = 'number';
  464. input.placeholder = '0';
  465. input.style.width = '100%';
  466. input.value = (script_delay) ? script_delay : '';
  467. }));
  468. }));
  469. }));
  470. }));
  471. }));
  472. }));
  473. }));
  474. }),
  475.  
  476. pingMenu_save = createElement('div', function(cont) {
  477. cont.className = 'menu-save';
  478.  
  479. cont.appendChild(createElement('a', function(link) {
  480. link.href = 'javascript:void(0)';
  481. link.id = 'pingsettings_save';
  482. link.appendChild(document.createTextNode('Save'));
  483. link.onclick = function() {
  484. var opts = (localStorage.getItem('MakazeScriptOptions')) ? JSON.parse(localStorage.getItem('MakazeScriptOptions')) : {},
  485. pingList = document.getElementById('pingList').value.split(/[\n\r]/),
  486. userPingList = document.getElementById('userPingList').value.split(/[\n\r]/),
  487. offset,
  488. split,
  489. elems,
  490. userElem,
  491. i = 0;
  492.  
  493. if (styleElem.hasChildNodes()) {
  494. styleElem.childNodes[0].nodeValue += '\n\n';
  495. } else {
  496. styleElem.appendChild(document.createTextNode(''));
  497. }
  498. styleElem.childNodes[0].nodeValue = styleElem.childNodes[0].nodeValue.replace(/\.ipc_highlight\s{[^]+?}/gi, '.ipc_highlight {\n' + document.getElementById('pingStyle').value + '\n' + '}');
  499.  
  500.  
  501. for (i = 0, offset = 0; i < pingList.length; i++) {
  502. if (!pingList[i - offset].length) {
  503. pingList.splice(i - offset, 1);
  504. offset++;
  505. }
  506. }
  507.  
  508. document.getElementById('pingList').value = pingList.join('\n');
  509.  
  510. // Make array of users
  511.  
  512. for (i = 0, offset = 0; i < userPingList.length; i++) {
  513. if (!userPingList[i - offset].length) {
  514. userPingList.splice(i - offset, 1);
  515. offset++;
  516. }
  517. if (userPingList.length) {
  518. if (userPingList[i].match('//')) {
  519. split = userPingList[i].split('//');
  520. userPingList[i] = {'id': split[0], 'name': split[1]};
  521. } else {
  522. userPingList[i] = {'id': userPingList[i]};
  523. }
  524. }
  525. }
  526.  
  527. // Get usernames
  528.  
  529. for (i = 0, elems = document.getElementById('chatters-online').getElementsByTagName('li'); i < elems.length; i++) {
  530. userElem = elems[i];
  531. userPingList = getUserName(userElem, userPingList);
  532. }
  533.  
  534. // Make array into list
  535.  
  536. var tempUserPingList = [];
  537.  
  538. for (i = 0; i < userPingList.length; i++) {
  539. if (!userPingList[i].hasOwnProperty('name') || userPingList[i].name === null) {
  540. tempUserPingList.push(userPingList[i].id);
  541. } else {
  542. tempUserPingList.push(userPingList[i].id + '//' + userPingList[i].name);
  543. }
  544. }
  545.  
  546. // Output to menu
  547.  
  548. document.getElementById('userPingList').value = tempUserPingList.join('\n');
  549.  
  550. opts.ipc_ping_style = document.getElementById('pingStyle').value;
  551. opts.ipc_pings = pingList;
  552. opts.ipc_user_pings = userPingList;
  553. opts.ipc_audible_ping = document.getElementById('audiblePingSwitch').checked;
  554. opts.ipc_pings_in_title = document.getElementById('titlePingSwitch').checked;
  555. opts.ipc_highlight_pings = document.getElementById('highlightPingsSwitch').checked;
  556. opts.ipc_audible_ping_on_focus = document.getElementById('audiblePingOnFocusSwitch').checked;
  557. opts.ipc_audible_ping_file = document.getElementById('audiblePingFile').value;
  558. opts.ipc_pings_script_delay = (document.getElementById('pingScriptDelay').value.length) ? parseInt(document.getElementById('pingScriptDelay').value) : 0;
  559.  
  560. localStorage.setItem('MakazeScriptOptions', JSON.stringify(opts));
  561.  
  562. if (document.getElementById('audiblePingSwitch').checked) {
  563. pingSound = new Audio(document.getElementById('audiblePingFile').value);
  564. }
  565.  
  566. fade(this.parentNode.parentNode, 'out');
  567. };
  568. }));
  569.  
  570. cont.appendChild(createElement('a', function(link) {
  571. link.href = 'javascript:void(0)';
  572. link.id = 'pingsettings_close';
  573. link.style.marginLeft = '10px';
  574. link.appendChild(document.createTextNode('Close'));
  575. link.onclick = function() {
  576. fade(this.parentNode.parentNode, 'out');
  577. };
  578. }));
  579. });
  580.  
  581. pingMenu = createElement('div', function(menu) {
  582. menu.id = 'pingsettings';
  583. menu.className = 'MakazeScriptMenu';
  584. menu.style.display = 'none';
  585.  
  586. menu.appendChild(pingMenu_options);
  587. menu.appendChild(pingMenu_save);
  588. });
  589.  
  590. document.body.appendChild(pingMenu);
  591.  
  592. // Button creation
  593.  
  594. if (document.getElementById('IPChatMenuItems') == null) {
  595. IPChatMenuItems = createElement('div', function(menu) {
  596. menu.id = 'IPChatMenuItems';
  597. menu.style.textAlign = 'right';
  598. });
  599. document.getElementById('chatters-online-wrap').nextSibling.nextSibling.getElementsByTagName('ul')[0].appendChild(IPChatMenuItems);
  600. }
  601.  
  602. if (document.getElementById('IPChatMenuItems').hasChildNodes()) {
  603. document.getElementById('IPChatMenuItems').appendChild(document.createElement('br'));
  604. }
  605.  
  606. menuButton = createElement('a', function(button) {
  607. button.id = 'pingMenuButton';
  608. button.className = 'ipsButton_secondary';
  609. button.href = 'javascript:void(0)';
  610. button.style.marginTop = '10px';
  611. button.appendChild(document.createTextNode('Ping Settings'));
  612.  
  613. button.onclick = function() {
  614. fade(document.getElementById('pingsettings'));
  615. };
  616. });
  617. document.getElementById('IPChatMenuItems').appendChild(menuButton);
  618.  
  619. // Apply highlight style
  620.  
  621. if (highlightPings) {
  622. if (styleElem.hasChildNodes()) {
  623. styleElem.childNodes[0].nodeValue += '\n\n';
  624. } else {
  625. styleElem.appendChild(document.createTextNode(''));
  626. }
  627. styleElem.childNodes[0].nodeValue +=
  628. '.ipc_highlight {\n' +
  629. pingStyle + '\n' +
  630. '}';
  631. }
  632.  
  633. document.addEventListener('DOMNodeInserted', function(event) {
  634. if (event.target.nodeType !== 1) {
  635. return false;
  636. }
  637.  
  638. var opts,
  639. userPings;
  640.  
  641. // Get usernames for user pings on joins
  642.  
  643. if (event.target.id.substr(0, 5) === 'user_') {
  644. opts = (localStorage.getItem('MakazeScriptOptions')) ? JSON.parse(localStorage.getItem('MakazeScriptOptions')) : {};
  645. userPings = (opts.hasOwnProperty('ipc_user_pings')) ? opts.ipc_user_pings : [];
  646. newUserPings = getUserName(event.target, userPings);
  647. opts.ipc_user_pings = newUserPings;
  648. localStorage.setItem('MakazeScriptOptions', JSON.stringify(opts));
  649. return false;
  650. }
  651.  
  652. if (event.target.id !== 'storage_chatroom') {
  653. return false;
  654. }
  655.  
  656. opts = (localStorage.getItem('MakazeScriptOptions')) ? JSON.parse(localStorage.getItem('MakazeScriptOptions')) : {};
  657. userPings = (opts.hasOwnProperty('ipc_user_pings')) ? opts.ipc_user_pings : [];
  658.  
  659. var latestMessage,
  660. textToCheck,
  661. pings = (opts.hasOwnProperty('ipc_pings')) ? opts.ipc_pings : [userName],
  662. audiblePing = (opts.hasOwnProperty('ipc_audible_ping')) ? opts.ipc_audible_ping : true,
  663. titlePing = (opts.hasOwnProperty('ipc_pings_in_title')) ? opts.ipc_pings_in_title : true,
  664. highlightPings = (opts.hasOwnProperty('ipc_highlight_pings')) ? opts.ipc_highlight_pings : true,
  665. audiblePingOnFocus = (opts.hasOwnProperty('ipc_audible_ping_on_focus')) ? opts.ipc_audible_ping_on_focus : false,
  666. ping,
  667. userPing,
  668. newUserPings,
  669. nameToCheck,
  670. nameNode,
  671. playSound = false,
  672. i = 0;
  673.  
  674. latestMessage = event.target.parentNode.getElementsByTagName('div')[event.target.parentNode.getElementsByTagName('div').length - 1];
  675.  
  676. if (!Classes.hasClass(latestMessage.parentNode, 'post')) {
  677. return false;
  678. }
  679.  
  680. if (Classes.hasClass(latestMessage.parentNode, 'chat-myown')) {
  681. return false;
  682. }
  683.  
  684. textToCheck = latestMessage.innerHTML;
  685.  
  686. if (Classes.hasClass(latestMessage.parentNode, 'chat-notice')) {
  687. if (!userPings.length) {
  688. return false;
  689. }
  690.  
  691. if (textToCheck !== ' has entered the room') {
  692. return false;
  693. }
  694.  
  695. nameNode = latestMessage.parentNode.getElementsByTagName('label')[0];
  696.  
  697. while (typeof nameToCheck === 'undefined') {
  698. if (nameNode.hasChildNodes()) {
  699. nameNode = nameNode.lastChild;
  700. } else {
  701. nameToCheck = nameNode.nodeValue;
  702. }
  703. }
  704.  
  705. for (i = 0; i < userPings.length; i++) {
  706. if (nameToCheck === userPings[i].name) {
  707. userPing = new RegExp('(' + userPings[i].name + ')', "g");
  708. if (titlePing) {
  709. if (!hasFocus) {
  710. if (document.title.match(/\(P:/g)) {
  711. if (!document.title.match(userPing)) {
  712. document.title = document.title.replace(/\(P:\s(.*?)\)/g, '(P: $1 ' + userPings[i].name + ')');
  713. }
  714. } else {
  715. document.title = '(P: ' + userPings[i].name + ') ' + document.title;
  716. }
  717. }
  718. }
  719.  
  720. if (highlightPings) {
  721. latestMessage.parentNode.className += ' ipc_highlight';
  722. }
  723.  
  724. if (audiblePing) {
  725. playSound = true;
  726. }
  727. }
  728. }
  729.  
  730. if (playSound) {
  731. if (!hasFocus || audiblePingOnFocus) {
  732. pingSound.play();
  733. }
  734. }
  735.  
  736. return false;
  737. }
  738.  
  739. for (i = 0; i < pings.length; i++) {
  740. ping = new RegExp('(' + pings[i] + ')', "gi");
  741. if (textToCheck.match(ping)) {
  742. if (titlePing) {
  743. if (!hasFocus) {
  744. if (document.title.match(/\(P:/g)) {
  745. if (!document.title.match(ping)) {
  746. document.title = document.title.replace(/\(P:\s(.*?)\)/g, '(P: $1 ' + pings[i] + ')');
  747. }
  748. } else {
  749. document.title = '(P: ' + pings[i] + ') ' + document.title;
  750. }
  751. }
  752. }
  753.  
  754. if (highlightPings) {
  755. Classes.addClass(latestMessage.parentNode, 'chat-myown');
  756. latestMessage.innerHTML = latestMessage.innerHTML.replace(ping, '<span class="ipc_highlight">$1</span>');
  757. }
  758.  
  759. if (audiblePing) {
  760. playSound = true;
  761. }
  762. }
  763. }
  764.  
  765. if (playSound) {
  766. if (!hasFocus || audiblePingOnFocus) {
  767. pingSound.play();
  768. }
  769. }
  770. });
  771.  
  772. window.onblur = function() {
  773. hasFocus = false;
  774. };
  775.  
  776. window.onfocus = function() {
  777. hasFocus = true;
  778. if (document.title.match(/\(P:/gi)) {
  779. document.title = document.title.replace(/\(P:\s.*?\)\s/gi, '');
  780. }
  781. };
  782. }
  783.  
  784. if (document.body.id === 'ipboard_body' && document.getElementById('storage_chatroom') != null) {
  785. opts = (localStorage.getItem('MakazeScriptOptions')) ? JSON.parse(localStorage.getItem('MakazeScriptOptions')) : {};
  786. script_delay = (opts.hasOwnProperty('ipc_pings_script_delay')) ? opts.ipc_pings_script_delay : 0;
  787.  
  788. if (script_delay) {
  789. setTimeout(function() {
  790. pingsInit();
  791. }, script_delay);
  792. } else {
  793. pingsInit();
  794. }
  795. }