Advertisement
Degritone

BBS Colorful Chatroom

Nov 2nd, 2021 (edited)
779
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // @name             BBS Chatroom
  3. // @namespace        dollars-bbs.org
  4. // @author           Degritone
  5. // @description      Adds back in limited functionality for the chatroom for the Dollars BBS
  6. // @match            *://*.dollars-bbs.org/*
  7. // @match            *://qchat.rizon.net/
  8. // @grant            GM.setValue
  9. // @grant            GM.getValue
  10. // @grant            GM.deleteValue
  11. // ==/UserScript==
  12.  
  13. function request(url){
  14.   let xmlHttp = new XMLHttpRequest();
  15.   xmlHttp.open("GET",url,false);
  16.   xmlHttp.send(null);
  17.   return xmlHttp.responseText;
  18. }
  19.  
  20. let prefixes = /^\+?%?@?&?~?/;
  21. let icons = [];
  22. let iconColors = [];
  23. let aoonline;
  24.  
  25. if(window.location.href.startsWith("https://dollars-bbs.org/chatroom")){
  26.   document.title = "Dollars BBS | Chatroom";
  27.   //window.location.href = "https://qchat.rizon.net";
  28.   let ip = request("https://api.ipify.org/");
  29.   console.log(ip);
  30.   let dhrip = request("https://dhr.ddns.net/ip");
  31.   console.log(dhrip);
  32.   let frameSrc = ip==dhrip?"https://localhost":"https://dhr.ddns.net";
  33.   let iframe = document.createElement("iframe");
  34.   iframe.src = frameSrc;
  35.   iframe.style.width = "100%";
  36.   iframe.style.height = "100%";
  37.   iframe.style.border = "none";
  38.   iframe.style.margin = "0px";
  39.   iframe.style.position = "fixed";
  40.   iframe.style.top = "0px";
  41.   iframe.style.left = "0px";
  42.   document.body.innerHTML = "";
  43.   document.body.appendChild(iframe);
  44. } if(window.location.href.startsWith("https://dollars-bbs.org")){
  45.   chatLink();
  46. } else if(window.location.href == "https://qchat.rizon.net/"){
  47.   document.title = "Dollars BBS | Chatroom";
  48.   checkForLoaded();
  49.   loadIcon(0);
  50.   iconReloadButton();
  51. }
  52.  
  53. async function f(readerResult,i){
  54.   if(!readerResult)
  55.     return;
  56.   if(readerResult.length<"data:1".length)
  57.     return;
  58.   await GM.setValue("bbsChatroomIcon."+i,readerResult);
  59.   loadIcon(i,false);
  60. }
  61.  
  62. async function requestb64(url,i){
  63.   let xmlHttp = new XMLHttpRequest();
  64.   xmlHttp.open("GET",url,true);
  65.   xmlHttp.responseType = "blob";
  66.   xmlHttp.onload = function () {
  67.     let reader = new FileReader();
  68.     reader.onloadend = function () {
  69.       f(reader.result,i);
  70.     }
  71.     reader.readAsDataURL(xmlHttp.response);
  72.   };
  73.   xmlHttp.send(null);
  74. }
  75.  
  76. async function getAOOnline(){
  77.   let xmlHttp = new XMLHttpRequest();
  78.   xmlHttp.open("GET","https://api.allorigins.win/raw?url=https://archive.org/",false);
  79.   let t;
  80.   try{
  81.     t = setTimeout(xmlHttp.abort,10000);
  82.     xmlHttp.send(null);
  83.   }catch(e){
  84.     if(t)
  85.       clearTimeout(t);
  86.     return false;
  87.   }
  88.   if(t)
  89.     clearTimeout(t);
  90.   return xmlHttp.status==200;
  91. }
  92.  
  93. function iconReloadButton(){
  94.   let reloadButton = document.createElement("div");
  95.   reloadButton.onclick = ()=>{icons = [];loadIcon(0,true);};
  96.   reloadButton.style.position = "fixed";
  97.   reloadButton.style.right = "20px";
  98.   reloadButton.style.top = "0px";
  99.   reloadButton.style.border = "2px #000000 solid";
  100.   reloadButton.style.borderRadius = "10px";
  101.   reloadButton.style.fontSize = "18px";
  102.   reloadButton.style.background = "#EEEEEE";
  103.   reloadButton.style.lineHeight = "26px";
  104.   reloadButton.style.paddingLeft = "3px";
  105.   reloadButton.style.paddingRight = "3px";
  106.   reloadButton.innerHTML = "Refresh Icons";
  107.   reloadButton.title = "This may take multiple minutes";
  108.   document.body.appendChild(reloadButton);
  109. }
  110.  
  111. async function loadIcon(i,skipGM=false){
  112.   let icon = document.createElement("img");
  113.   icon.style.width = "58px";
  114.   icon.style.margin = "auto";
  115.   icon.width = 58;
  116.   icon.height = 58;
  117.   icon.setAttribute("class","drrrIcon");
  118.   let image = "https://archive.org/download/drrr-like-chat-icons/"+i+".png";
  119.   let colorless = false;
  120.   let gmv = await GM.getValue("bbsChatroomIcon."+i);
  121.   if(!gmv || skipGM)
  122.     aoonline = await getAOOnline();
  123.   if(gmv){
  124.     if(gmv.length<"data:1".length || skipGM){
  125.       await GM.deleteValue("bbsChatroomIcon."+i);
  126.       loadIcon(i);
  127.       return;
  128.     }
  129.     image = gmv;
  130.   }else if(aoonline){
  131.     let allorigins = "https://api.allorigins.win/raw?url=";
  132.     image = allorigins+image;
  133.     requestb64(image,i);
  134.     return;
  135.   }else{
  136.     colorless = true;
  137.     icon.crossOrigin = null;
  138.   }
  139.   icon.src = image;
  140.   icon.onload = function(){
  141.     getIconColors(icon,i,colorless);
  142.     loadIcon(i+1,skipGM);
  143.     icons[i] = icon;
  144.     iconLoader();
  145.     let colless = document.createAttribute("colorless");
  146.     colless.value = colorless;
  147.     icon.setAttributeNode(colless);
  148.   };
  149. }
  150.  
  151. function getIconColors(icon,i,colorless){
  152.   if(colorless){
  153.     iconColors[i] = [63,63,63,1];
  154.     return;
  155.   }
  156.   let canvas = document.createElement("canvas");
  157.   canvas.width = 58;
  158.   canvas.height = 58;
  159.   let context = canvas.getContext("2d");
  160.  
  161.   context.drawImage(icon,0,0,58,58);
  162.   iconColors[i] = [];
  163.   let imageData = context.getImageData(0,0,58,58).data;
  164.   iconColors[i][0] = imageData[58*6*4+48*4];
  165.   iconColors[i][1] = imageData[58*6*4+48*4+1];
  166.   iconColors[i][2] = imageData[58*6*4+48*4+2];
  167.   if(iconColors[i][0]<63 && iconColors[i][1]<63 && iconColors[i][2]<63){
  168.     iconColors[i][0] = 63;
  169.     iconColors[i][1] = 63;
  170.     iconColors[i][2] = 63;
  171.   }
  172.   iconColors[i][3] = 1;
  173. }
  174.  
  175. function chatLink(){
  176.   let menu = document.getElementById("pagemenu");
  177.   if(!menu){
  178.     setTimeout(chatLink,100);
  179.     return;
  180.   }
  181.   let chatroom = document.createElement("li");
  182.   chatroom.innerHTML = "<a href='https://dollars-bbs.org/chatroom'>Chatroom</a>";
  183.   menu.children[2].children[0].innerHTML = "Other Chats";
  184.   menu.insertBefore(chatroom,menu.children[2]);
  185.   let sidebar = document.getElementById("sidebar");
  186.   let a = sidebar.getElementsByTagName("a");
  187.   a = a[2%a.length];
  188.   a.href = "https://qchat.rizon.net";
  189. }
  190.  
  191. function checkForLoaded(){
  192.   let loaded = document.getElementsByClassName("tr2").length;
  193.   if(!loaded)
  194.     setTimeout(checkForLoaded,100);
  195.   else
  196.     setTimeout(login,100);
  197. }
  198.  
  199. function login(){
  200.   document.title = "Dollars BBS | Chatroom";
  201.  
  202.   let topNode = document.getElementsByClassName("dynamicpanel qwebirc-qui topboundpanel outertabbar outertabbar_top")[0];
  203.   topNode.style.display = "none";
  204.  
  205.   let favicon = document.createElement("link");
  206.   favicon.href = "https://dollars-bbs.org/random/favicon.ico";
  207.   favicon.rel = "shortcut icon";
  208.   document.head.appendChild(favicon);
  209.  
  210.   let bg = document.getElementsByClassName("dynamicpanel qwebirc-qui middleboundpanel lines")[0];
  211.   bg.style.background = "#000000";
  212.   bg.style.color = "#DDDDDD";
  213.   bg.style.top = "0px";
  214.   bg.style.bottom = "0px";
  215.   bg.style.left = "0px";
  216.   bg.style.right = "0px";
  217.   bg.style.height = "";
  218.  
  219.   let form = document.getElementsByTagName("table")[1];
  220.   form.style.top = "0px";
  221.   form.style.left = "50%";
  222.   form.style.transform = "translateX(-50%)";
  223.   form.style.position = "absolute";
  224.   form.children[0].removeChild(form.children[0].children[0]);
  225.  
  226.   let startButton = document.getElementsByTagName("input");
  227.   for(let i=0;i<startButton.length;i++){
  228.     if(startButton[i].value == "Connect"){
  229.       startButton = startButton[i];
  230.       break;
  231.     }
  232.   }
  233.   startButton.style.width = "148px";
  234.  
  235.   startButton.onclick = ()=>{waitForChat(false,document.getElementsByTagName("input")[0].value);};
  236.  
  237.   inputs();
  238.   tipsBox();
  239. }
  240.  
  241. function iconLoader(){
  242.   let name = document.getElementsByTagName("input")[0];
  243.   let bg = document.getElementsByClassName("dynamicpanel qwebirc-qui middleboundpanel lines")[0];
  244.   let iconHolder = document.getElementById("iconHolder");
  245.   if(!iconHolder){
  246.     iconHolder = document.createElement("div");
  247.     bg.appendChild(iconHolder);
  248.     iconHolder.id = "iconHolder";
  249.     iconHolder.style.width = (13*60)+"px";
  250.     iconHolder.style.position = "absolute";
  251.     iconHolder.style.top = "112px";
  252.     iconHolder.style.bottom = "0px";
  253.     iconHolder.style.left = "50%";
  254.     iconHolder.style.transform = "translateX(-50%)";
  255.     iconHolder.style.display = "flex";
  256.     iconHolder.style.flexWrap = "wrap";
  257.     iconHolder.style.flexDirection = "row";
  258.     iconHolder.style.justifyContent = "center";
  259.     iconHolder.style.overflowY = "scroll";
  260.   }
  261.   let start = 0;
  262.   if(name.value.match(/^\[[0-9]+\]/))
  263.     start = parseInt(name.value.replace("[","").replace(/\].+/,""));
  264.   for(let i=iconHolder.children.length;i<icons.length;i++){
  265.     let selection = document.createElement("div");
  266.     selection.style.width = "60px";
  267.     selection.style.height = "75px";
  268.     selection.style.display = "inline-block";
  269.     selection.style.position = "relative";
  270.     selection.style.margin = "0px";
  271.     selection.style.alignSelf = "center";
  272.  
  273.     let radio = document.createElement("input");
  274.     radio.type = "radio";
  275.     radio.id = "icon"+i;
  276.     radio.name = "icon";
  277.     radio.value = i;
  278.     radio.style.left = "23px";
  279.     radio.style.bottom = "2px";
  280.     radio.style.position = "absolute";
  281.     radio.style.margin = "0px";
  282.     if(i==start)
  283.       radio.checked = "checked";
  284.  
  285.     let label = document.createElement("label");
  286.     label.htmlFor = "icon"+i;
  287.  
  288.     label.appendChild(icons[i].cloneNode());
  289.     selection.appendChild(label);
  290.     selection.appendChild(radio);
  291.     selection.onclick = ()=>{adjustName();};
  292.  
  293.     iconHolder.appendChild(selection);
  294.   }
  295.   inputs();
  296. }
  297.  
  298. function inputs(){
  299.   let nameInput = document.getElementsByTagName("input")[0];
  300.   if(nameInput.value == ""){
  301.     let cookies = document.cookie.split(";");
  302.     for(let i=0;i<cookies.length;i++){
  303.       let pair = cookies[i].split("=");
  304.       if(pair[0] == " name" && nameInput.value == "")
  305.         nameInput.value = pair[1];
  306.     }
  307.   }
  308.  
  309.   if(!document.getElementById("typingName")){
  310.     let name = document.createElement("input");
  311.     name.autocomplete = "off";
  312.     name.autocorrect = "off";
  313.     name.autocapitalize = "off";
  314.     name.spellcheck = false;
  315.     name.style = window.getComputedStyle(nameInput);
  316.     name.id = "typingName";
  317.     name.value = nameInput.value.replace(/\[[0-9]+\]/,"");
  318.     name.oninput = ()=>adjustName();
  319.     nameInput.parentNode.appendChild(name);
  320.  
  321.     let channelInput = document.getElementsByTagName("input")[2];
  322.     channelInput.value = "#dollars-bbs";
  323.     channelInput.parentNode.parentNode.style.display = "none";
  324.   }
  325.   nameInput.style.display = "none";
  326.  
  327.   let iconHolder = document.getElementById("iconHolder");
  328.   if(iconHolder){
  329.     let w = Math.ceil(icons.length/Math.floor((window.innerHeight-parseInt(iconHolder.style.top.replace("px","")))/75))*60;
  330.     iconHolder.style.width = Math.min(w,window.innerWidth)+"px";
  331.   }
  332. }
  333.  
  334. function tipsBox(){
  335.   let tips = document.createElement("div");
  336.   tips.style.width = "250px";
  337.   tips.style.height = "100px";
  338.   tips.style.position = "fixed";
  339.   tips.style.left = "200px";
  340.   tips.style.top = "5px";
  341.   tips.style.backgroundColor = "#EEEEEE";
  342.   tips.style.border = "2px solid #FFFFFF";
  343.   tips.style.borderRadius = "10px";
  344.   tips.style.textAlign = "center";
  345.   tips.id = "tipsBox";
  346.   tips.innerHTML = "Click this box to get cycling tips on things you can do with the script!";
  347.   document.body.appendChild(tips);
  348.   let tip = [];
  349.   tip[0] = "You can type %@ to begin formatting text. %@&lt;0-15> is colored text. Other valid formatting characters are I, M, B, S, U, K, R.";
  350.   tip[1] = "You can press CTRL and a valid formatting character to type that character in 2 less button presses.";
  351.   tip[2] = "You can use %@&lt;0-15>,&lt;0-15> to color both the text and its background or just %@,&lt;number> to color just the background.";
  352.   tip[3] = "You can end already set formatting from your message with %@R.";
  353.   tip[4] = "You can change your name with /nick. This also allows you to change your icon by changing your name to [&lt;0-15>]<name>.";
  354.   tip[5] = "You can PM people by pressing either the circular button right of the textbox or using /query &lt;name>.";
  355.   tip[6] = "You can add someone's name to the textbox by clicking their name.";
  356.   tip[7] = "Don't do /help.";
  357.   tip[8] = "If you ever get lost, you can return to a known channel with the channel picker in the top right.";
  358.   tip[9] = "You can join other channels by doing /join #&lt;channel>.";
  359.   tip[10] = "You can drag a file onto the textbox to upload it!<br><br>The generated links do not work in Chrome, but you can still upload your file.";
  360.   tip = shuffle(tip);
  361.   tips.setAttribute("class","-1");
  362.   tips.addEventListener("click",()=>{
  363.     let i = parseInt(tips.getAttribute("class"))%tip.length;
  364.     i++;
  365.     tips.innerHTML = tip[i];
  366.     tips.setAttribute("class",i);
  367.   });
  368. }
  369.  
  370. function shuffle(array) {
  371.   let currentIndex = array.length,  randomIndex;
  372.   while(currentIndex != 0){
  373.     randomIndex = Math.floor(Math.random() * currentIndex);
  374.     currentIndex--;
  375.     [array[currentIndex], array[randomIndex]] = [
  376.       array[randomIndex], array[currentIndex]];
  377.   }
  378.   return array;
  379. }
  380.  
  381. let ownName = "";
  382.  
  383. function adjustName(){
  384.   let name = document.getElementsByTagName("input")[0];
  385.   let radios = document.getElementsByName("icon");
  386.   let value = 0;
  387.   for(let i=0;i<radios.length;i++){
  388.     if(radios[i].checked){
  389.       value = radios[i].value
  390.       break;
  391.     }
  392.   }
  393.  
  394.   name.value = "["+value+"]"+document.getElementById("typingName").value;
  395.   name.dispatchEvent(new Event("input"));
  396.   ownName = name.value;
  397. }
  398.  
  399. function waitForChat(once=false,name=""){
  400.   if(!once){
  401.     once = true;
  402.     let cover = document.createElement("div");
  403.     cover.id = "loadingCover";
  404.     cover.style.position = "fixed";
  405.     cover.style.top = "0px";
  406.     cover.style.bottom = "0px";
  407.     cover.style.left = "0px";
  408.     cover.style.right = "0px";
  409.     cover.style.background = "#000000";
  410.     cover.style.color = "#FFFFFF";
  411.     cover.innerHTML = "LOADING";
  412.     document.body.appendChild(cover);
  413.     let date = new Date();
  414.     date.setTime(date.getTime()+(1000*60*60*24*365));
  415.     document.cookie = "name="+name+"; expires="+encodeURIComponent(date.toUTCString())+";";
  416.     ownName = name;
  417.     document.body.removeChild(document.getElementById("tipsBox"));
  418.   }
  419.   if(!document.getElementsByClassName("nicklist tab-invisible dynamicpanel qwebirc-qui rightboundpanel")[0]){
  420.     setTimeout(waitForChat,100,once);
  421.     return;
  422.   }
  423.   chat(false,false);
  424. }
  425.  
  426. let sound = getCookie("sound")?(getCookie("sound").split("-")[0]=="on"):false;
  427. let messageSound = new Audio("https://archive.org/download/DRRR-message-sound/message%20sound.mp3");
  428. let logoutSound = new Audio("https://archive.org/download/DRRR-message-sound/logout%20sound.mp3");
  429. messageSound.crossOrigin = "anonymous";
  430. logoutSound.crossOrigin = "anonymous";
  431. let augain;
  432. document.body.addEventListener("click",audioInitiate);
  433. function audioInitiate(){
  434.   let auctx = new AudioContext();
  435.   let aumessage = auctx.createMediaElementSource(messageSound);
  436.   let aulogout = auctx.createMediaElementSource(logoutSound);
  437.   augain = auctx.createGain();
  438.   augain.gain.value = 3;
  439.   aumessage.connect(augain);
  440.   aulogout.connect(augain);
  441.   augain.connect(auctx.destination);
  442.   document.body.removeEventListener("click",audioInitiate);
  443. }
  444.  
  445. let textColor = [];
  446. textColor[0] = "rgb(255,255,255)";
  447. textColor[1] = "rgb(0,0,0)";
  448. textColor[2] = "rgb(0,0,139)";
  449. textColor[3] = "rgb(0,100,0)";
  450. textColor[4] = "rgb(255,0,0)";
  451. textColor[5] = "rgb(139,0,0)";
  452. textColor[6] = "rgb(128,0,128)";
  453. textColor[7] = "rgb(255,165,0)";
  454. textColor[8] = "rgb(255,255,0)";
  455. textColor[9] = "rgb(0,128,0)";
  456. textColor[10] = "rgb(0,128,128)";
  457. textColor[11] = "rgb(0,255,255)";
  458. textColor[12] = "rgb(0,0,255)";
  459. textColor[13] = "rgb(255,0,255)";
  460. textColor[14] = "rgb(169,169,169)";
  461. textColor[15] = "rgb(128,128,128)";
  462.  
  463. let ctrlDown = false;
  464. document.body.addEventListener("keydown",(e)=>{
  465.   if(e.keyCode == 17 || e.keyCode == 91)
  466.     ctrlDown = true;
  467. });
  468. document.body.addEventListener("keyup",(e)=>{
  469.   if(e.keyCode == 17 || e.keyCode == 91)
  470.     ctrlDown = false;
  471. });
  472.  
  473. function chat(once,loaded){
  474.   document.title = "Dollars BBS | Chatroom";
  475.   let linkTags = document.getElementsByTagName("link");
  476.   linkTags[linkTags.length-1].href = "https://dollars-bbs.org/random/favicon.ico";
  477.   if(!(document.getElementsByClassName("dynamicpanel qwebirc-qui topicboundpanel topic tab-invisible colourline")[0] || document.getElementsByTagName("input")[0]) && !once){
  478.     setTimeout(chat,100,false,false);
  479.     return;
  480.   }
  481.   if(!loaded){
  482.     setTimeout(chat,100,false,true);
  483.     document.body.removeChild(document.getElementById("loadingCover"));
  484.     return;
  485.   }
  486.  
  487.   setTimeout(chat,100,true,true);
  488.  
  489.   let input = document.getElementsByClassName("dynamicpanel qwebirc-qui bottomboundpanel input")[0];
  490.   input.style.position = "relative";
  491.   input.style.top = "0px";
  492.  
  493.   let messageList = document.getElementsByClassName("dynamicpanel qwebirc-qui middleboundpanel lines ircwindow")[0];
  494.   if(!messageList)
  495.     messageList = document.getElementsByClassName("drrrMessageList")[0];
  496.   messageList.style.background = "rgba(0,0,0,1)";
  497.   messageList.style.overflowY = "scroll";
  498.   messageList.style.overflowX = "hidden";
  499.   messageList.style.width = "100%";
  500.   messageList.style.bottom = "0px";
  501.   messageList.style.position = "fixed";
  502.  
  503.   let pmListsList = document.getElementsByClassName("drrrPmList");
  504.  
  505.   let bufferDivs = messageList.getElementsByClassName("bufferDiv");
  506.   if(!bufferDivs[0])
  507.     bufferDivs = [];
  508.   for(let i=bufferDivs.length;i<3;i++){
  509.     let d = document.createElement("div");
  510.     messageList.prepend(d);
  511.     d.style.display = "none";
  512.     d.setAttribute("class","bufferDiv");
  513.   }
  514.   bufferDivs = messageList.getElementsByClassName("bufferDiv");
  515.  
  516.   let messages = messageList.getElementsByClassName("colourline");
  517.  
  518.   for(let i=0;i<messages.length;i++){
  519.     let slashMe = 0;
  520.     let spans = messages[i].getElementsByTagName("span");
  521.     let mpm = false;
  522.     if(spans.length<4){
  523.       if(spans.length<3){
  524.         continue;
  525.       }
  526.       slashMe = 1;
  527.     }
  528.     if((spans[1].innerHTML.startsWith("-") && !spans[1].innerHTML.startsWith('-<span class="hyperlink-whois">Onee-chan</span>-')) || spans[1].innerHTML.startsWith("[notice("))
  529.       mpm = true;
  530.  
  531.     let timestamp = document.createElement("div");
  532.     timestamp.innerHTML = spans[0].innerHTML;
  533.     let reply = document.createElement("div");
  534.     reply.setAttribute("class","drrrReply");
  535.     reply.style.width = (600+58+25)+"px";
  536.     reply.style.margin = "auto";
  537.     reply.style.position = "relative";
  538.     reply.style.display = "flex";
  539.     let personHolder = document.createElement("div");
  540.     personHolder.style.width = "58px";
  541.     personHolder.style.position = "relative";
  542.     personHolder.style.display = "flex";
  543.     reply.appendChild(personHolder);
  544.     let replyHolder = document.createElement("div");
  545.     replyHolder.style.width = "600px";
  546.     replyHolder.style.display = "flex";
  547.     let replyBubble = document.createElement("div");
  548.     replyBubble.style.alignSelf = "center";
  549.     replyBubble.style.display = "flex";
  550.     let replyText = document.createElement("div");
  551.     replyText.style.display = "flex";
  552.     replyBubble.appendChild(replyText);
  553.     replyHolder.appendChild(replyBubble);
  554.     reply.appendChild(replyHolder);
  555.  
  556.     let name = "";
  557.     let hlwi = messages[i].getElementsByClassName("hyperlink-whois")[0]
  558.     name = hlwi?hlwi:spans[3-slashMe];
  559.     let self = name.parentNode.getAttribute("class") == "Xu";
  560.     let m = self?name.parentNode.nextSibling:name.parentNode;
  561.     if(!m)
  562.       m = name.parentNode;
  563.     if(m.innerHTML == "@" || m.innerHTML == "%" || m.innerHTML == "~")
  564.       m = spans[3+(self?2:0)-slashMe];
  565.     let mh = m;
  566.     let opmm = !m.innerHTML.startsWith("-");
  567.     if(self)
  568.       m.innerHTML = m.innerHTML.replace(/.*?&gt;(<span>.+?<\/span>)? ?/,"");
  569.     else if(!slashMe)
  570.       m.innerHTML = m.innerHTML.replace(/.*?&gt;(<span>.+?<\/span>)? ?/,"");
  571.     else
  572.       m.innerHTML = m.innerHTML.replace(/.+<\/span> /,"");
  573.     if(mpm){
  574.       if(m.innerHTML.startsWith("-"))
  575.         m.innerHTML = m.innerHTML.replace(/.+?- /,"");
  576.       else
  577.         m.innerHTML = m.innerHTML.replace(/.+?\)\] /,"");
  578.     }
  579.     m = formatSpan(m);
  580.     for(let j=0;mh.nextSibling && j<2000;j++){
  581.       mh = mh.nextSibling;
  582.       if(mh == name)
  583.         mh = mh.nextSibling;
  584.       if(!mh)
  585.         break;
  586.       m+=formatSpan(mh);
  587.     }
  588.     name = name.innerHTML;
  589.     replyText.innerHTML = "<span style='overflow-wrap: break-word; width: 100%;'>"+m+"</span>";
  590.  
  591.     let id = 0;
  592.     for(let j=0;j<name.replace(prefixes,"").length;j++)
  593.       id+=name.replace(prefixes,"").charCodeAt(j);
  594.     id = id%icons.length;
  595.  
  596.     let qjl = m.match(/\[.+?@.+?\] has (quit \[.*?\]<\/span>)?(joined <span class="hyperlink-channel">#.+)?(left <span class="hyperlink-channel">#.+)?$/);
  597.     if(qjl){
  598.       let ip = m.match(/\[.+?\]/g);
  599.       for(let j=0;j<ip.length;j++){
  600.         if(ip[j].match(/\[.+?@.+?\]/)){
  601.           ip = ip[j];
  602.           break;
  603.         }
  604.       }
  605.       replyText.innerHTML = "<span>——"+m.replace(ip,"").replace("  "," ")+"</span>";
  606.       bufferDivs[2].after(replyText);
  607.       replyText.style.color = "#FFFFFF";
  608.       replyText.style.width = "683px";
  609.       replyText.style.margin = "auto";
  610.       messageList.removeChild(messages[i]);
  611.       if(m.match(/quit \[.*?\]<\/span>$/) || m.match(/left <span class="hyperlink-channel">#.+$/))
  612.         logoutSound.play();
  613.       else
  614.         messageSound.play();
  615.       continue;
  616.     }
  617.  
  618.     if(!mpm)
  619.       bufferDivs[2].after(reply);
  620.     else{
  621.       let mlist = null;
  622.       for(let j=0;j<pmListsList.length;j++){
  623.         if(pmListsList[j].id == name){
  624.           mlist = pmListsList[j];
  625.           continue;
  626.         }
  627.       }
  628.       if(mlist == null){
  629.         mlist = createPmList(name);
  630.         messageList.parentNode.appendChild(mlist);
  631.         pmListsList = document.getElementsByClassName("drrrPmList");
  632.       }
  633.       mlist.prepend(reply);
  634.       mlist.setAttribute("unread",opmm?0:parseInt(mlist.getAttribute("unread"))+1);
  635.     }
  636.     if(opmm && mpm)
  637.       name = ownName;
  638.  
  639.     let iconHolder = document.createElement("div");
  640.     personHolder.appendChild(iconHolder);
  641.     if(name.match(/\[[0-9]+\]/)){
  642.       id = parseInt(name.replace(/\[/,"").replace(/\].+/,""));
  643.     }
  644.  
  645.     if(!icons[id]){
  646.       loadIcon(id);
  647.       setTimeout(setIcon,5000,id,iconHolder,mpm);
  648.       id = 0;
  649.       for(let j=0;j<name.replace(prefixes,"").length;j++)
  650.         id+=name.replace(prefixes,"").charCodeAt(j);
  651.       id = id%icons.length;
  652.       setIcon(id,iconHolder,mpm);
  653.     } else
  654.       setIcon(id,iconHolder,mpm);
  655.  
  656.     let namePlate = document.createElement("div");
  657.     namePlate.innerHTML = name.replace(/\[[0-9]+\]/,"");
  658.     namePlate.style.margin = "auto";
  659.     namePlate.style.width = "90px";
  660.     namePlate.style.textAlign = "center";
  661.     namePlate.style.color = "#FFFFFF";
  662.     namePlate.style.position = "absolute";
  663.     namePlate.style.transform = "translateX(-50%) translateY(-6px)"
  664.     namePlate.style.overflowWrap = "break-word";
  665.     namePlate.style.left = "29px";
  666.     namePlate.style.top = "calc(50% + 39px)";
  667.     iconHolder.style.display = "block";
  668.     iconHolder.appendChild(namePlate);
  669.  
  670.     timestamp.style.position = "relative";
  671.     timestamp.style.color = "#000000";
  672.     timestamp.style.right = "65px";
  673.     iconHolder.appendChild(timestamp);
  674.  
  675.     let topColor = iconColors[id][0]+","+iconColors[id][1]+","+iconColors[id][2]+","+iconColors[id][3];
  676.     let topMiddleColor = iconColors[id][0]+","+iconColors[id][1]+","+iconColors[id][2]+","+(iconColors[id][3]-0.05);
  677.     let bottomMiddleColor = iconColors[id][0]+","+iconColors[id][1]+","+iconColors[id][2]+","+(iconColors[id][3]-0.15);
  678.     let bottomColor = iconColors[id][0]+","+iconColors[id][1]+","+iconColors[id][2]+","+(iconColors[id][3]-0.5);
  679.     if(mpm){
  680.       topColor = "255,255,255,1";
  681.       topMiddleColor = "255,255,255,1";
  682.       bottomMiddleColor = "255,255,255,1";
  683.       bottomColor = "255,255,255,1";
  684.     }
  685.     replyBubble.style.background = "linear-gradient(to bottom,rgba("+topColor+"),rgba("+topMiddleColor+") 50%,rgba("+bottomMiddleColor+") 50%,rgba("+bottomColor+"))";
  686.     replyBubble.style.border = "solid #FFFFFF 4px";
  687.     replyBubble.style.borderRadius = "13px";
  688.     replyBubble.style.maxWidth = Math.min(window.innerWidth,600)+"px";
  689.     replyBubble.style.minWidth = (18*3)+"px";
  690.     replyBubble.style.width = "auto";
  691.     replyBubble.style.left = "30px";
  692.     replyBubble.style.position = "relative";
  693.  
  694.     replyText.style.color = "#FFFFFF";
  695.     if(iconColors[id][0]+iconColors[id][1]+iconColors[id][2]>230*3){
  696.       replyText.style.color = "#050505";
  697.       replyBubble.style.borderColor = "#888888";
  698.     }
  699.     if(mpm){
  700.       replyText.style.color = "#000000";
  701.       replyBubble.style.borderColor = "rgba("+iconColors[id][0]+","+iconColors[id][1]+","+iconColors[id][2]+",1)";
  702.     }
  703.     replyText.style.position = "relative";
  704.     replyText.style.fontSize = "18px";
  705.     replyText.style.margin = "18px";
  706.     replyText.style.marginTop = "14px";
  707.     replyText.style.lineHeight = "20px";
  708.     replyText.style.width = "-moz-max-content";
  709.     replyText.style.maxWidth = (Math.min(window.innerWidth,600)-18*2)+"px";
  710.  
  711.     reply.style.minHeight = (Math.max(replyBubble.offsetHeight,58)+16)+"px";
  712.     reply.parentNode.style.display = "block";
  713.     reply.mb = Math.min(namePlate.offsetHeight,Math.max(0,(58+(namePlate.offsetHeight+8)*1.5)-parseInt(reply.style.minHeight.replace("px",""))));
  714.     if(mpm){
  715.       let isPm = document.getElementsByClassName("drrrToggle")[0].getAttribute("on")=="on";
  716.       let pmsel = document.getElementById("pmSelector");
  717.       let cpm = pmsel.options[pmsel.selectedIndex];
  718.       if(cpm)
  719.         cpm = cpm.value.replace(/\[[0-9]+\]/,"");
  720.       if(!(namePlate.innerHTML == cpm || namePlate.innerHTML == ownName.replace(/\[[0-9]+\]/,"")) || !isPm){
  721.         reply.parentNode.style.display = "none";
  722.       }
  723.     }
  724.     reply.style.marginBottom = reply.mb+"px";
  725.  
  726.     let arrowGradient = document.createElement("div");
  727.     arrowGradient.style.width = "25px";
  728.     arrowGradient.style.height = "12px";
  729.     arrowGradient.style.background = "#000000";
  730.     arrowGradient.style.top = "calc(50% - 1px)";
  731.     arrowGradient.style.transform = "translateY(-50%)";
  732.     arrowGradient.style.left = "-25px";
  733.     arrowGradient.style.position = "absolute";
  734.  
  735.     let arrow = document.createElement("div");
  736.     arrow.style.width = "25px";
  737.     arrow.style.height = "13px";
  738.     let h = replyBubble.offsetHeight/13*100;
  739.     let arrowBackground = "linear-gradient(10deg,rgba(0,0,0,1),rgba(0,0,0,1) calc(40% - 3px),"+replyBubble.style.borderColor+" calc(40% - 3px),"+replyBubble.style.borderColor+" calc(40% + 1px),rgba(0,0,0,0) calc(40% + 1px),rgba(0,0,0,0)),"+
  740.         "linear-gradient(170deg,rgba(0,0,0,1),rgba(0,0,0,1) calc(40% - 3px),"+replyBubble.style.borderColor+" calc(40% - 3px),"+replyBubble.style.borderColor+" calc(40% + 1px),rgba(0,0,0,0) calc(40% + 1px),rgba(0,0,0,0)),"+
  741.         "linear-gradient(to bottom,rgba("+topColor+") -"+h+"%,rgba("+topMiddleColor+") calc(50% + 0.5px),rgba("+bottomMiddleColor+") calc(50% + 0.5px),rgba("+bottomColor+") "+h+"%)";
  742.     arrow.style.background = arrowBackground;
  743.     arrowGradient.appendChild(arrow);
  744.     replyBubble.appendChild(arrowGradient);
  745.  
  746.     if(document.getElementById("inflateSetting") && !mpm)
  747.       if(document.getElementById("inflateSetting").checked)
  748.         animateNewMessage(reply,replyBubble,reply.mb,replyBubble.offsetHeight,replyBubble.offsetWidth-8,namePlate.offsetHeight,0);
  749.  
  750.     messageList.removeChild(messages[i]);
  751.  
  752.     if(window.scrollY>0){
  753.       window.scroll(0,0);
  754.       messageList.scroll(0,0);
  755.     }
  756.  
  757.     if(sound)
  758.       messageSound.play();
  759.   }
  760.  
  761.   let separator = document.getElementsByClassName("lastpos")[0];
  762.   if(separator)
  763.     separator.parentNode.removeChild(separator);
  764.  
  765.   let onlineUsers = getOnlineUsers();
  766.   let onlineDiv = document.getElementById("drrrOnline");
  767.   if(!onlineDiv){
  768.     onlineDiv = document.createElement("div");
  769.     onlineDiv.style.display = "flex";
  770.     onlineDiv.style.flexDirection = "row";
  771.     onlineDiv.style.position = "relative";
  772.     onlineDiv.style.width = "725px";
  773.     onlineDiv.style.justifyContent = "center";
  774.     onlineDiv.style.flexWrap = "wrap";
  775.     onlineDiv.style.display = "none";
  776.     onlineDiv.id = "drrrOnline";
  777.   }
  778.   for(let i=0;i<onlineUsers.length;i++){
  779.     if(onlineDiv.children[i]){
  780.       if(onlineUsers[i].id == onlineDiv.children[i].id)
  781.         continue;
  782.     }
  783.     let div = onlineDiv.children[i]?onlineDiv.children[i]:document.createElement("div");
  784.     if(!div.id)
  785.       onlineDiv.appendChild(div);
  786.     div.innerHTML = "";
  787.     div.style.width = "-moz-max-content";
  788.     div.style.maxWidth = "fit-content";
  789.     div.style.marginTop = "2px";
  790.     div.id = onlineUsers[i].id;
  791.     if(i!=0)
  792.       div.style.marginLeft = "10px";
  793.     div.onclick = ()=>{
  794.       let t = document.getElementsByTagName("textarea")[0];
  795.       let tstart = t.value.slice(0,t.selectionStart);
  796.       let tend = t.value.slice(t.selectionStart);
  797.       t.value = tstart+(tstart.match(/ $/)||tstart.match(/^$/)?"":" ")+onlineUsers[i].id+(tend.match(/^ /)||tend.match(/^$/)?"":" ")+tend;
  798.       t.oninput();
  799.       t.focus();
  800.     };
  801.     div.style.cursor = "pointer";
  802.     let oui = null;
  803.     let ouiid = parseInt(onlineUsers[i].id.replace("[","").replace(/\].+/,""));
  804.     if(icons[ouiid])
  805.       oui = icons[ouiid].cloneNode();
  806.     else{
  807.       ouiid = 0;
  808.       for(let j=0;j<onlineUsers[i].id.replace(prefixes,"").length;j++)
  809.         ouiid+=onlineUsers[i].id.replace(prefixes,"").charCodeAt(j);
  810.       ouiid = ouiid%icons.length;
  811.       oui = icons[ouiid].cloneNode();
  812.     }
  813.     div.appendChild(oui);
  814.     oui = div.children[0];
  815.     oui.style.height = "18px";
  816.     oui.style.width = "18px";
  817.     oui.style.marginRight = "3px";
  818.     let np = document.createElement("div");
  819.     np.innerHTML = onlineUsers[i].display;
  820.     np.style.color = "#000000";
  821.     np.style.lineHeight = "18px";
  822.     np.style.display = "inline-block";
  823.     np.style.top = "-3px";
  824.     np.style.position = "relative";
  825.     div.appendChild(np);
  826.  
  827.     if(!document.getElementById(onlineUsers[i].id)){
  828.       let mlist = createPmList(onlineUsers[i].id);
  829.       messageList.parentNode.appendChild(mlist);
  830.       pmListsList = document.getElementsByClassName("drrrPmList");
  831.     }
  832.   }
  833.   for(let i=onlineUsers.length;i<onlineDiv.children.length;i++)
  834.     onlineDiv.removeChild(onlineDiv.children[i]);
  835.  
  836.   if(!once){
  837.     let header = document.getElementsByClassName("dynamicpanel qwebirc-qui topicboundpanel topic tab-invisible colourline")[0];
  838.     if(header)
  839.       header.style.display = "none";
  840.  
  841.     document.body.prepend(input);
  842.     document.body.style.background = "rgba(238,238,238,1)";
  843.     input.style.paddingLeft = "24px";
  844.     input = document.getElementsByTagName("input")[0];
  845.     let inputBox = document.createElement("textarea");
  846.     input.parentNode.style.width = "725px";
  847.     input.parentNode.style.margin = "auto";
  848.     input.parentNode.style.background = "#EEEEEE";
  849.     input.style.height = "0px";
  850.     input.style.width = "0px";
  851.     input.style.margin = "0px";
  852.     input.style.border = "0px";
  853.     input.style.padding = "0px";
  854.     inputBox.style.width = "590px";
  855.     inputBox.style.height = "65px";
  856.     inputBox.style.overflowWrap = "break-word";
  857.     inputBox.style.overflowX = "hidden";
  858.     inputBox.style.whiteSpace = "normal";
  859.     inputBox.style.background = "#FFFFFF";
  860.     inputBox.style.position = "relative";
  861.     inputBox.style.top = "0px";
  862.     inputBox.style.left = "88px";
  863.     inputBox.style.border = "2px solid #333333";
  864.     inputBox.style.borderRadius = "10px";
  865.     inputBox.style.fontSize = "18px";
  866.     inputBox.placeholder = "";
  867.     inputBox.ondrop = (e)=>{upload(e);};
  868.     inputBox.oninput = (e)=>{
  869.       let isPm = document.getElementsByClassName("drrrToggle")[0].getAttribute("on")=="on";
  870.       let pmsel = document.getElementById("pmSelector");
  871.       let cpm = pmsel.options[pmsel.selectedIndex];
  872.       if(cpm)
  873.         cpm = cpm.value;
  874.       input.value = (isPm && cpm?"/notice "+cpm+" ":"")+inputBox.value.replace(/%@[iI]/g,String.fromCharCode(0x1D))
  875.                                                                .replace(/%@[bB]/g,String.fromCharCode(0x02))
  876.                                                                .replace(/%@[uU]/g,String.fromCharCode(0x1F))
  877.                                                                .replace(/%@[sS]/g,String.fromCharCode(0x1E))
  878.                                                                .replace(/%@[mM]/g,String.fromCharCode(0x11))
  879.                                                                .replace(/%@[rR]/g,String.fromCharCode(0x0F))
  880.                                                                .replace(/%@/g,String.fromCharCode(3));
  881.     };
  882.     inputBox.addEventListener("keydown",function(e){
  883.                                           if(ctrlDown){
  884.                                             switch(e.keyCode){
  885.                                               case 75:
  886.                                                 e.preventDefault();
  887.                                                 inputBox.value+="%@";
  888.                                                 break;
  889.                                               case 73:
  890.                                                 e.preventDefault();
  891.                                                 inputBox.value+="%@I";
  892.                                                 break;
  893.                                               case 77:
  894.                                                 e.preventDefault();
  895.                                                 inputBox.value+="%@M";
  896.                                                 break;
  897.                                               case 66:
  898.                                                 e.preventDefault();
  899.                                                 inputBox.value+="%@B";
  900.                                                 break;
  901.                                               case 83:
  902.                                                 e.preventDefault();
  903.                                                 inputBox.value+="%@S";
  904.                                                 break;
  905.                                               case 85:
  906.                                                 e.preventDefault();
  907.                                                 inputBox.value+="%@U";
  908.                                                 break;
  909.                                               case 82:
  910.                                                 e.preventDefault();
  911.                                                 inputBox.value+="%@R";
  912.                                                 break;
  913.                                             }
  914.                                           }
  915.                                           if(e.code=="Enter"){
  916.                                             let isPm = document.getElementsByClassName("drrrToggle")[0].getAttribute("on")=="on";
  917.                                             let pmsel = document.getElementById("pmSelector");
  918.                                             let cpm = pmsel.options[pmsel.selectedIndex];
  919.                                             if(cpm)
  920.                                               cpm = cpm.value;
  921.                                             if(inputBox.value.startsWith("/nick ")){
  922.                                               ownName = inputBox.value.replace(/^\/nick /,"");
  923.                                               modifyUserPlate();
  924.                                             }
  925.                                             input.value = (isPm && cpm?"/notice "+cpm+" ":"")+inputBox.value.replace(/%@[iI]/g,String.fromCharCode(0x1D))
  926.                                                                                                      .replace(/%@[bB]/g,String.fromCharCode(0x02))
  927.                                                                                                      .replace(/%@[uU]/g,String.fromCharCode(0x1F))
  928.                                                                                                      .replace(/%@[sS]/g,String.fromCharCode(0x1E))
  929.                                                                                                      .replace(/%@[mM]/g,String.fromCharCode(0x11))
  930.                                                                                                      .replace(/%@[rR]/g,String.fromCharCode(0x0F))
  931.                                                                                                      .replace(/%@/g,String.fromCharCode(3));
  932.                                             inputBox.value = "";
  933.                                             input.focus();
  934.                                           }
  935.                                         });
  936.     input.onkeydown = function(){
  937.                         inputBox.value = "";
  938.                         messageList.scroll(0,0);
  939.                         window.scroll(0,0);
  940.                         inputBox.focus();
  941.                       };
  942.     input.parentNode.appendChild(inputBox);
  943.  
  944.     document.getElementById("ircui").style.top = "4000px";
  945.  
  946.     let user = document.createElement("div");
  947.     user.style.width = "58px";
  948.     user.style.display = "inline-block";
  949.     user.style.position = "absolute";
  950.     user.style.top = "0px";
  951.     user.id = "userPlate";
  952.     input.parentNode.prepend(user);
  953.     modifyUserPlate();
  954.  
  955.     inputBox.style.height = (user.offsetHeight-4)+"px";
  956.  
  957.     input.parentNode.appendChild(onlineDiv);
  958.  
  959.     for(let i=0;i<3;i++){
  960.     }
  961.     let toggleBar = document.createElement("div");
  962.     let toggleIconSrcs = [];
  963.     toggleIconSrcs[0] = "https://archive.org/download/drrrchat-toggles/pm%20off.png";
  964.     toggleIconSrcs[1] = "https://archive.org/download/drrrchat-toggles/pm%20on.png";
  965.     toggleIconSrcs[2] = "https://archive.org/download/drrrchat-toggles/online%20off.png";
  966.     toggleIconSrcs[3] = "https://archive.org/download/drrrchat-toggles/online%20on.png";
  967.     toggleIconSrcs[4] = "https://archive.org/download/drrrchat-toggles/sound%20off.png";
  968.     toggleIconSrcs[5] = "https://archive.org/download/drrrchat-toggles/sound%20on.png";
  969.     toggleIconSrcs[6] = "https://archive.org/download/drrrchat-toggles/settings%20off.png";
  970.     toggleIconSrcs[7] = "https://archive.org/download/drrrchat-toggles/settings%20on.png";
  971.  
  972.     let toggleIcons = [];
  973.     for(let i=0;i<toggleIconSrcs.length/2;i++){
  974.       toggleIcons[i] = document.createElement("img");
  975.       toggleIcons[i].style.margin = "0px";
  976.       toggleIcons[i].style.marginLeft = "5px";
  977.       toggleIcons[i].style.cursor = "pointer";
  978.       toggleIcons[i].setAttribute("class","drrrToggle");
  979.       toggleIcons[i].src = toggleIconSrcs[i*2];
  980.       toggleBar.appendChild(toggleIcons[i]);
  981.       let o = document.createAttribute("on");
  982.       o.value = "off";
  983.       toggleIcons[i].setAttributeNode(o);
  984.     }
  985.     if(sound){
  986.       toggleIcons[2].src = toggleIconSrcs[5];
  987.       toggleIcons[2].setAttribute("on","on");
  988.     }else{
  989.       toggleIcons[2].setAttribute("on","off");
  990.     }
  991.     toggleBar.style.position = "absolute";
  992.     toggleBar.style.marginLeft = "690px";
  993.     toggleBar.style.width = (20*toggleIcons.length)+"px";
  994.  
  995.     input.parentNode.prepend(toggleBar);
  996.  
  997.     toggleIcons[0].onclick = ()=>{
  998.       toggleIcons[0].setAttribute("on",toggleIcons[0].getAttribute("on")=="on"?"off":"on");
  999.       let on = toggleIcons[0].getAttribute("on")=="on";
  1000.       let r = 0;
  1001.       for(let i=0;i<pmListsList.length;i++){
  1002.         let rev = pmListsList[i].getAttribute("revealed")=="true";
  1003.         if(rev)
  1004.           r = i;
  1005.         pmListsList[i].style.display = (rev&&on)?"block":"none";
  1006.       }
  1007.       toggleIcons[0].src = toggleIconSrcs[on?1:0];
  1008.       if(on){
  1009.         if(icons[userID].getAttribute("colorless")=="false"){
  1010.           if(user.children[0].outerHTML.startsWith("<img"))
  1011.             user.prepend(invertIcon(user.children[0],userID));
  1012.           else
  1013.             user.children[0].style.display = "block";
  1014.           user.children[1].style.display = "none";
  1015.         }
  1016.         pmListsList[r].style.display = "block";
  1017.         pmListsList[r].setAttribute("revealed",true);
  1018.       }else{
  1019.         if(icons[userID].getAttribute("colorless")=="false"){
  1020.           user.children[0].style.display = "none";
  1021.           user.children[1].style.display = "block";
  1022.         }
  1023.       }
  1024.     };
  1025.     toggleIcons[1].onclick = ()=>{onlineDiv.style.display = onlineDiv.style.display=="none"?"flex":"none"; toggleIcons[1].src = toggleIconSrcs[onlineDiv.style.display=="none"?2:3];};
  1026.     toggleIcons[2].onclick = ()=>{
  1027.       sound = !sound;
  1028.       toggleIcons[2].src = toggleIconSrcs[sound?5:4];
  1029.       toggleIcons[2].setAttribute("on",sound?"on":"off");
  1030.       saveCookie("sound",toggleIcons[2].getAttribute("on")+"-"+document.getElementById("volumeSlider").value);
  1031.     };
  1032.  
  1033.     let online = document.getElementsByClassName("nicklist tab-invisible dynamicpanel qwebirc-qui rightboundpanel")[0];
  1034.     if(online)
  1035.       online.style.display = "none";
  1036.  
  1037.     let settingsWindow = createSettingsWindow();
  1038.  
  1039.     toggleIcons[3].onclick = ()=>{
  1040.       settingsWindow.style.display = settingsWindow.style.display=="none"?"block":"none";
  1041.       toggleIcons[3].src = toggleIconSrcs[settingsWindow.style.display=="none"?6:7];
  1042.     };
  1043.  
  1044.     let postButton = document.createElement("div");
  1045.     postButton.style.margin = "auto";
  1046.     postButton.style.marginTop = "3px";
  1047.     postButton.style.marginBottom = "3px";
  1048.     postButton.style.color = "#000000";
  1049.     postButton.style.fontWeight = "bold";
  1050.     postButton.style.textAlign = "center";
  1051.     postButton.style.lineHeight = "26px";
  1052.     postButton.style.width = "250px";
  1053.     postButton.style.height = "26px";
  1054.     postButton.style.background = "linear-gradient(to bottom,#FAF7F8,#F9F9F5 50%,#F2F2EE 50%,#F1F1ED)";
  1055.     postButton.style.border = "2px solid #333333";
  1056.     postButton.style.borderRadius = "10px";
  1057.     postButton.style.cursor = "pointer";
  1058.     postButton.innerHTML = "POST!"
  1059.     postButton.onclick = ()=>{inputBox.focus();};
  1060.     inputBox.after(postButton);
  1061.  
  1062.     let topNode = document.getElementsByClassName("dynamicpanel qwebirc-qui topboundpanel outertabbar outertabbar_top")[0];
  1063.     topNode.style.display = "block";
  1064.     topNode.style.position = "fixed";
  1065.     topNode.style.width = (input.parentNode.getBoundingClientRect().left-10)+"px";
  1066.     topNode.style.backgroundColor = "#EEEEEE";
  1067.     topNode.style.borderBottom = "none";
  1068.     let topAs = topNode.getElementsByTagName("a");
  1069.     for(let i=0;i<topAs.length;i++){
  1070.       topAs[i].style.backgroundColor = topAs[i].getAttribute("class")=="tab tab-unselected"?"#E3EFFA":"#FFFFFE";;
  1071.       let mut = new MutationObserver((mutations)=>{
  1072.                                        if(mutations[0].attributeName == "class")
  1073.                                          mutations[0].target.style.backgroundColor = mutations[0].target.getAttribute("class")=="tab tab-unselected"?"#E3EFFA":"#FFFFFE";
  1074.                                      });
  1075.       mut.observe(topAs[i],{attributes:true});
  1076.     }
  1077.   }
  1078.  
  1079.   messageList.style.top = input.offsetHeight+"px";
  1080.   messageList.style.height = "calc(100% - "+messageList.style.top+")";
  1081.   for(let i=0;i<pmListsList.length;i++){
  1082.     pmListsList[i].style.top = input.offsetHeight+"px";
  1083.   }
  1084.   messageList.setAttribute("class","drrrMessageList");
  1085.  
  1086.   let pmSelector = document.getElementById("pmSelector");
  1087.   if(!pmSelector){
  1088.     pmSelector = document.createElement("select");
  1089.     pmSelector.style.position = "absolute";
  1090.     pmSelector.style.top = "20px";
  1091.     let w = 120;
  1092.     pmSelector.style.marginLeft = "690px";
  1093.     pmSelector.style.width = w+"px";
  1094.     pmSelector.id = "pmSelector";
  1095.     document.getElementsByTagName("input")[0].parentNode.prepend(pmSelector);
  1096.     pmSelector.onchange = ()=>{
  1097.       let selected = pmSelector.options[pmSelector.selectedIndex].value;
  1098.       for(let i=0;i<pmListsList.length;i++){
  1099.         pmListsList[i].setAttribute("revealed",pmListsList[i].id==selected);
  1100.         pmListsList[i].style.display = pmListsList[i].getAttribute("revealed")=="true"?"block":"none";
  1101.         if(pmListsList[i].getAttribute("revealed")=="true")
  1102.           pmListsList[i].setAttribute("unread",0);
  1103.       }
  1104.       input.value = "/notice "+selected.replace(/^%?@?~?/,"");
  1105.       input.parentNode.getElementsByTagName("textarea")[0].focus();
  1106.     };
  1107.   }
  1108.   pmSelector.style.display = (document.getElementsByClassName("drrrToggle")[0].getAttribute("on")=="on")?"block":"none";
  1109.   for(let i=0;i<onlineUsers.length;i++){
  1110.     if(pmSelector.children[i])
  1111.       if(pmSelector.children[i].innerHTML == onlineUsers[i].display)
  1112.         continue;
  1113.     let option = pmSelector.children[i]?pmSelector.children[i]:document.createElement("option");
  1114.     option.value = onlineUsers[i].id;
  1115.     option.innerHTML = onlineUsers[i].display;
  1116.     if(!pmSelector.children[i])
  1117.       pmSelector.appendChild(option);
  1118.   }
  1119.   for(let i=onlineUsers.length;i<pmSelector.children.length;i++)
  1120.     pmSelector.removeChild(pmSelector.children[i]);
  1121.   for(let i=0;i<pmSelector.children.length;i++){
  1122.     let op = pmSelector.children[i].value;
  1123.     let unread = parseInt(document.getElementById(op).getAttribute("unread"));
  1124.     if(unread){
  1125.       if(pmSelector.children[i].innerHTML.match(/ \([0-9]+\)$/))
  1126.         pmSelector.children[i].innerHTML = pmSelector.children[i].innerHTML.replace(/ \([0-9]+\)$/," ("+unread+")");
  1127.       else
  1128.         pmSelector.children[i].innerHTML = pmSelector.children[i].innerHTML+" ("+unread+")";
  1129.     }else
  1130.       pmSelector.children[i].innerHTML = pmSelector.children[i].innerHTML.replace(/ \([0-9]+\)$/,"");
  1131.   }
  1132. }
  1133.  
  1134. function modifyUserPlate(){
  1135.   let user = document.getElementById("userPlate");
  1136.   let userID = parseInt(ownName.replace("[","").replace(/\].+/,""));
  1137.   if(!icons[userID]){
  1138.     userID = 0;
  1139.     for(let j=0;j<ownName.replace(prefixes,"").length;j++)
  1140.       userID+=ownName.replace(prefixes,"").charCodeAt(j);
  1141.     userID = userID%icons.length;
  1142.   }
  1143.   let namePlate = document.getElementById("nameUnderIcon");
  1144.   if(!namePlate){
  1145.     user.appendChild(icons[userID].cloneNode());
  1146.     namePlate = document.createElement("div");
  1147.     user.appendChild(namePlate);
  1148.     namePlate.outerHTML = "<div id='nameUnderIcon'>"+ownName.replace(/\[[0-9]+\]/,"")+"</div>";
  1149.     namePlate = document.getElementById("nameUnderIcon");
  1150.     namePlate.style.position = "relative";
  1151.     namePlate.style.left = "50%";
  1152.     namePlate.style.top = "-4px";
  1153.     namePlate.style.transform = "translateX(-50%)";
  1154.     namePlate.style.width = "100px";
  1155.     namePlate.style.overflow = "visible";
  1156.     namePlate.style.overflowWrap = "break-word";
  1157.     namePlate.style.height = "auto";
  1158.     namePlate.style.lineHeight = "18px";
  1159.     namePlate.style.textAlign = "center";
  1160.   }else{
  1161.     namePlate.innerHTML = ownName.replace(/\[[0-9]+\]/,"");
  1162.     console.log(userID);
  1163.     console.log(icons.length);
  1164.     console.log(icons[userID]);
  1165.     namePlate.previousSibling.outerHTML = icons[userID].outerHTML;
  1166.   }
  1167. }
  1168.  
  1169. function setIcon(id,icon,isPms){
  1170.   if(!icons[id]){
  1171.     loadIcon(id);
  1172.     setTimeout(setIcon,5000,id,icon,isPms);
  1173.     return;
  1174.   }
  1175.   icon.appendChild(icons[id].cloneNode());
  1176.   if(isPms && icons[id].getAttribute("colorless")=="false"){
  1177.     let c = invertIcon(icon.children[0],id);
  1178.     icon.innerHTML = ""
  1179.     icon.appendChild(c);
  1180.   }
  1181.   icon.children[0].style.transform = "translateY(-50%)";
  1182.   icon.children[0].style.top = "50%";
  1183.   icon.children[0].style.position = "relative";
  1184.   icon.children[0].style.width = "58px";
  1185. }
  1186.  
  1187. function invertIcon(icon,id){
  1188.   let canvas = document.createElement("canvas");
  1189.   canvas.width = 58;
  1190.   canvas.height = 58;
  1191.   let ctx = canvas.getContext("2d");
  1192.   ctx.drawImage(icon,0,0,58,58);
  1193.   let imgdata = ctx.getImageData(0,0,58,58);
  1194.   let iconColor = iconColors[id];
  1195.   if(arrayEqual(iconColor,[63,63,63,1],false))
  1196.     iconColor = [0,0,0,1];
  1197.   for(let i=0;i<imgdata.data.length;i+=4){
  1198.     let color = [];
  1199.     color[0] = imgdata.data[i]
  1200.     color[1] = imgdata.data[i+1]
  1201.     color[2] = imgdata.data[i+2]
  1202.     color[3] = 1;
  1203.     if(arrayEqual(color,iconColor,true)){
  1204.       let c = 255;
  1205.       if(arrayEqual(color,[255,255,255,1],true))
  1206.         c = 0;
  1207.       imgdata.data[i] = c;
  1208.       imgdata.data[i+1] = c;
  1209.       imgdata.data[i+2] = c;
  1210.     } else if(arrayEqual(color,[255,255,255,1],true) || arrayEqual(color,[0,0,0,1],true)){
  1211.       imgdata.data[i] = iconColor[0];
  1212.       imgdata.data[i+1] = iconColor[1];
  1213.       imgdata.data[i+2] = iconColor[2];
  1214.     }else{
  1215.       imgdata.data[i] = 255-imgdata.data[i];
  1216.       imgdata.data[i+1] = 255-imgdata.data[i+1];
  1217.       imgdata.data[i+2] = 255-imgdata.data[i+2];
  1218.     }
  1219.   }
  1220.   ctx.putImageData(imgdata,0,0);
  1221.   return canvas;
  1222. }
  1223.  
  1224. function arrayEqual(a,b,fudge=false){
  1225.   if(a.length!=b.length)
  1226.     return false;
  1227.   if(fudge && deltaE(a,b)<10)
  1228.     return true;
  1229.   for(let i=0;i<a.length;i++)
  1230.     if(a[i]!=b[i] && !(fudge && deltaE(a,b)<10))
  1231.       return false;
  1232.   return true;
  1233. }
  1234.  
  1235. function deltaE(rgbA, rgbB) {
  1236.   let labA = rgb2lab(rgbA);
  1237.   let labB = rgb2lab(rgbB);
  1238.   let deltaL = labA[0] - labB[0];
  1239.   let deltaA = labA[1] - labB[1];
  1240.   let deltaB = labA[2] - labB[2];
  1241.   let c1 = Math.sqrt(labA[1] * labA[1] + labA[2] * labA[2]);
  1242.   let c2 = Math.sqrt(labB[1] * labB[1] + labB[2] * labB[2]);
  1243.   let deltaC = c1 - c2;
  1244.   let deltaH = deltaA * deltaA + deltaB * deltaB - deltaC * deltaC;
  1245.   deltaH = deltaH < 0 ? 0 : Math.sqrt(deltaH);
  1246.   let sc = 1.0 + 0.045 * c1;
  1247.   let sh = 1.0 + 0.015 * c1;
  1248.   let deltaLKlsl = deltaL / (1.0);
  1249.   let deltaCkcsc = deltaC / (sc);
  1250.   let deltaHkhsh = deltaH / (sh);
  1251.   let i = deltaLKlsl * deltaLKlsl + deltaCkcsc * deltaCkcsc + deltaHkhsh * deltaHkhsh;
  1252.   return i < 0 ? 0 : Math.sqrt(i);
  1253. }
  1254.  
  1255. function rgb2lab(rgb){
  1256.   let r = rgb[0] / 255, g = rgb[1] / 255, b = rgb[2] / 255, x, y, z;
  1257.   r = (r > 0.04045) ? Math.pow((r + 0.055) / 1.055, 2.4) : r / 12.92;
  1258.   g = (g > 0.04045) ? Math.pow((g + 0.055) / 1.055, 2.4) : g / 12.92;
  1259.   b = (b > 0.04045) ? Math.pow((b + 0.055) / 1.055, 2.4) : b / 12.92;
  1260.   x = (r * 0.4124 + g * 0.3576 + b * 0.1805) / 0.95047;
  1261.   y = (r * 0.2126 + g * 0.7152 + b * 0.0722) / 1.00000;
  1262.   z = (r * 0.0193 + g * 0.1192 + b * 0.9505) / 1.08883;
  1263.   x = (x > 0.008856) ? Math.pow(x, 1/3) : (7.787 * x) + 16/116;
  1264.   y = (y > 0.008856) ? Math.pow(y, 1/3) : (7.787 * y) + 16/116;
  1265.   z = (z > 0.008856) ? Math.pow(z, 1/3) : (7.787 * z) + 16/116;
  1266.   return [(116 * y) - 16, 500 * (x - y), 200 * (y - z)]
  1267. }
  1268.  
  1269. function getOnlineUsers(){
  1270.   let onlineList = document.getElementsByClassName("nicklist tab-invisible dynamicpanel qwebirc-qui rightboundpanel")[0];
  1271.   let online = onlineList.getElementsByTagName("a");
  1272.   let people = [];
  1273.   for(let i=0;i<online.length;i++){
  1274.     let p = {id:"",display:""};
  1275.     p.id = online[i].children[0].innerHTML.replace(prefixes,"");
  1276.     p.display = p.id.replace(prefixes,"").replace(/^\[[0-9]+\]/,"");
  1277.     people[i] = p;
  1278.   }
  1279.   return people;
  1280. }
  1281.  
  1282. function createPmList(name){
  1283.   let mlist = document.createElement("div");
  1284.   mlist.style.background = "rgba(0,0,0,0.75)";
  1285.   mlist.style.overflowY = "scroll";
  1286.   mlist.style.overflowX = "hidden";
  1287.   mlist.style.width = "100%";
  1288.   mlist.style.height = ((18*2+20*2)*4+160)+"px";;
  1289.   mlist.style.position = "fixed";
  1290.   mlist.style.display = "none";
  1291.   mlist.setAttribute("class","drrrPmList");
  1292.   mlist.id = name;
  1293.   let r = document.createAttribute("revealed");
  1294.   r.value = false;
  1295.   mlist.setAttributeNode(r);
  1296.   let u = document.createAttribute("unread");
  1297.   u.value = 0;
  1298.   mlist.setAttributeNode(u);
  1299.   return mlist;
  1300. }
  1301.  
  1302. function createSettingsWindow(){
  1303.   let settingsWindow = document.createElement("div");
  1304.   settingsWindow.style.position = "fixed";
  1305.   settingsWindow.style.left = (document.getElementsByClassName("drrrToggle")[0].getBoundingClientRect().left)+"px";
  1306.   settingsWindow.style.width = "170px";
  1307.   settingsWindow.style.top = "16px";
  1308.   settingsWindow.style.display = "none";
  1309.   settingsWindow.style.background = "#EEEEEE";
  1310.   settingsWindow.style.border = "4px solid #FEFEFE";
  1311.   document.body.appendChild(settingsWindow);
  1312.  
  1313.   let label = document.createElement("div");
  1314.   label.innerHTML = "Volume";
  1315.   label.style.position = "relative";
  1316.   label.style.transform = "translate(-50%)";
  1317.   label.style.left = "50%";
  1318.   label.style.width = "-moz-max-content";
  1319.   label.style.maxWidth = "fit-content";
  1320.   settingsWindow.appendChild(label);
  1321.   let volumeSlider = document.createElement("input");
  1322.   volumeSlider.type = "range";
  1323.   volumeSlider.step = "any";
  1324.   volumeSlider.min = 1;
  1325.   volumeSlider.max = 9;
  1326.   volumeSlider.value = 3;
  1327.   volumeSlider.style.width = "160px";
  1328.   volumeSlider.style.position = "relative";
  1329.   volumeSlider.style.transform = "translate(-50%)";
  1330.   volumeSlider.style.left = "50%";
  1331.   volumeSlider.id = "volumeSlider";
  1332.   settingsWindow.appendChild(volumeSlider);
  1333.   let volumeBox = document.createElement("input");
  1334.   volumeBox.type = "number";
  1335.   volumeBox.step = "any";
  1336.   volumeBox.max = 300;
  1337.   volumeBox.min = 100/3;
  1338.   volumeBox.value = 100;
  1339.   volumeBox.style.width = "66px";
  1340.   volumeBox.style.position = "relative";
  1341.   volumeBox.style.transform = "translate(-50%)";
  1342.   volumeBox.style.left = "50%";
  1343.   settingsWindow.appendChild(volumeBox);
  1344.  
  1345.   volumeSlider.oninput = ()=>{volumeBox.value = volumeSlider.value*100/3;};
  1346.   volumeBox.oninput = ()=>{volumeSlider.value = volumeBox.value*3/100;};
  1347.   volumeSlider.onchange = ()=>{augain.gain.value = volumeSlider.value; saveCookie("sound",(document.getElementsByClassName("drrrToggle")[2].getAttribute("on"))+"-"+volumeSlider.value);};
  1348.   volumeBox.onchange = volumeSlider.onchange;
  1349.  
  1350.   let soundSetting = getCookie("sound");
  1351.   if(soundSetting)
  1352.     soundSetting = soundSetting.split("-")[1];
  1353.   else{
  1354.     soundSetting = "1";
  1355.     saveCookie("sound","off-1");
  1356.   }
  1357.   volumeSlider.value = parseFloat(soundSetting);
  1358.   volumeBox.value = volumeSlider.value*100/3;
  1359.   volumeSlider.onchange();
  1360.  
  1361.   let inflateSetting = getCookie("inflate");
  1362.   let inflateOn = "";
  1363.   let inflateFPS = 0;
  1364.   if(inflateSetting){
  1365.     inflateOn = inflateSetting.split("-")[0];
  1366.     inflateFPS = inflateSetting.split("-")[1];
  1367.   }else{
  1368.     saveCookie("inflate","true");
  1369.     inflateOn = "true";
  1370.     inflateFPS = 30;
  1371.   }
  1372.  
  1373.   let br = document.createElement("br");
  1374.   settingsWindow.appendChild(br);
  1375.  
  1376.   let inflateBox = document.createElement("input");
  1377.   inflateBox.type = "checkbox";
  1378.   inflateBox.name = "inflateSetting";
  1379.   inflateBox.checked = inflateOn=="true";
  1380.   inflateBox.id = "inflateSetting";
  1381.   let inflateLabel = document.createElement("label");
  1382.   inflateLabel.forHTML = "inflateSetting";
  1383.   inflateLabel.innerHTML = "Inflating Bubbles";
  1384.   let inflateTable = document.createElement("table");
  1385.   let inflateTr = document.createElement("tr");
  1386.   let inflateTd1 = document.createElement("td");
  1387.   let inflateTd2 = document.createElement("td");
  1388.   inflateTd1.appendChild(inflateLabel);
  1389.   inflateTd2.appendChild(inflateBox);
  1390.   inflateTr.appendChild(inflateTd1);
  1391.   inflateTr.appendChild(inflateTd2);
  1392.   inflateTable.appendChild(inflateTr);
  1393.   settingsWindow.appendChild(inflateTable);
  1394.   let inflateFPSLabel = document.createElement("div");
  1395.   inflateFPSLabel.innerHTML = "FPS";
  1396.   inflateFPSLabel.style.position = "relative";
  1397.   inflateFPSLabel.style.transform = "translate(-50%)";
  1398.   inflateFPSLabel.style.left = "50%";
  1399.   inflateFPSLabel.style.width = "-moz-max-content";
  1400.   inflateFPSLabel.style.maxWidth = "fit-content";
  1401.   settingsWindow.appendChild(inflateFPSLabel);
  1402.   let inflateFPSSlider = document.createElement("input");
  1403.   inflateFPSSlider.type = "range";
  1404.   inflateFPSSlider.step = 1;
  1405.   inflateFPSSlider.min = 5;
  1406.   inflateFPSSlider.max = 250;
  1407.   inflateFPSSlider.value = inflateFPS?inflateFPS:30;
  1408.   inflateFPSSlider.style.width = "160px";
  1409.   inflateFPSSlider.style.position = "relative";
  1410.   inflateFPSSlider.style.transform = "translate(-50%)";
  1411.   inflateFPSSlider.style.left = "50%";
  1412.   inflateFPSSlider.id = "inflateFPSSlider";
  1413.   settingsWindow.appendChild(inflateFPSSlider);
  1414.   let inflateFPSBox = document.createElement("input");
  1415.   inflateFPSBox.type = "number";
  1416.   inflateFPSBox.step = "any";
  1417.   inflateFPSBox.max = 250;
  1418.   inflateFPSBox.min = 5;
  1419.   inflateFPSBox.value = inflateFPS?inflateFPS:30;
  1420.   inflateFPSBox.style.width = "66px";
  1421.   inflateFPSBox.style.position = "relative";
  1422.   inflateFPSBox.style.transform = "translate(-50%)";
  1423.   inflateFPSBox.style.left = "50%";
  1424.   settingsWindow.appendChild(inflateFPSBox);
  1425.  
  1426.   inflateBox.onchange = ()=>{saveCookie("inflate",""+inflateBox.checked+"-"+inflateFPSSlider.value);};
  1427.   inflateFPSBox.oninput = ()=>{inflateFPSSlider.value = inflateFPSBox.value;};
  1428.   inflateFPSSlider.oninput = ()=>{inflateFPSBox.value = inflateFPSSlider.value;};
  1429.   inflateFPSBox.onchange = ()=>{inflateBox.onchange();};
  1430.   inflateFPSSlider.onchange = ()=>{inflateBox.onchange();};
  1431.  
  1432.   return settingsWindow;
  1433. }
  1434.  
  1435. function getCookie(name){
  1436.   let cookies = document.cookie.split(";");
  1437.   for(let i=0;i<cookies.length;i++){
  1438.     let pair = cookies[i].split("=");
  1439.     if(pair[0] == " "+name){
  1440.       return pair[1];
  1441.     }
  1442.   }
  1443.   return null;
  1444. }
  1445.  
  1446. function saveCookie(name,value){
  1447.   let date = new Date();
  1448.   date.setTime(date.getTime()+(1000*60*60*24*365));
  1449.   document.cookie = name+"="+value+"; expires="+encodeURIComponent(date.toUTCString())+";"
  1450. }
  1451.  
  1452. async function animateNewMessage(reply,replyBubble,mb,height,width,nameHeight,i,j=0,startTime=new Date()){
  1453.   let thisTime = new Date();
  1454.   let fps = document.getElementById("inflateFPSSlider")?document.getElementById("inflateFPSSlider").value:30;
  1455.   let ms = Math.floor(1000/fps);
  1456.   if(thisTime.value<=startTime.value)
  1457.     thisTime = new Date(startTime.value+ms);
  1458.   if(i>200){
  1459.     reply.style.marginBottom = mb+"px";
  1460.     replyBubble.style.width = "auto";
  1461.     replyBubble.style.height = "auto";
  1462.     replyBubble.style.borderWidth = "4px";
  1463.     replyBubble.children[0].style.fontSize = "18px";
  1464.     replyBubble.children[0].style.lineHeight = "20px";
  1465.     replyBubble.children[0].style.display = "block";
  1466.     replyBubble.children[1].style.display = "block";
  1467.     return;
  1468.   }
  1469.   let overpop = 1.1;
  1470.   setTimeout(animateNewMessage,ms,reply,replyBubble,mb,height,width,nameHeight,i+6*(thisTime-startTime)/4,j,thisTime);
  1471.   replyBubble.style.width = (width*overpop*i/200)+"px"
  1472.   replyBubble.style.height = (height*overpop*i/200)+"px";
  1473.   replyBubble.style.borderWidth = (4*overpop*i/200)+"px"
  1474.   replyBubble.children[0].style.display = "none";
  1475.   replyBubble.children[1].style.display = "none";
  1476.   if(height*overpop*i/200>18*2){
  1477.     if(j == 0)
  1478.       j = i;
  1479.     replyBubble.children[0].style.display = "block";
  1480.     replyBubble.children[1].style.display = "block";
  1481.     replyBubble.children[0].style.fontSize = (18*overpop*(i-j)/(200-j))+"px";
  1482.     replyBubble.children[0].style.lineHeight = (20*overpop*(i-j)/(200-j))+"px";
  1483.   }
  1484.   reply.style.marginBottom = Math.min(nameHeight,Math.max(58+(nameHeight+8)*1.5-replyBubble.offsetHeight,0))+"px";
  1485. }
  1486.  
  1487. function formatSpan(m){
  1488.   let strike = String.fromCharCode(0x1E);
  1489.   let italic = String.fromCharCode(0x1D);
  1490.   let mono = String.fromCharCode(0x11);
  1491.   let mo = m.getAttribute("class")?m.getAttribute("class"):"";
  1492.   m = m.innerHTML;
  1493.   if(m.match(new RegExp("("+mono+"|"+italic+"|"+strike+")"))){
  1494.     let ind = Math.min(io(m,mono),io(m,italic),io(m,strike));
  1495.     let ms = m.slice(ind);
  1496.     let mc = mo.match(/Xc[0-9][0-9]*/)?textColor[parseInt(mo.match(/Xc[0-9][0-9]*/)[0].replace(/Xb*c/,""))]:"";
  1497.     let mb = mo.match(/Xbc[0-9][0-9]*/)?textColor[parseInt(mo.match(/Xbc[0-9][0-9]*/)[0].replace(/Xb*c/,""))]:"";
  1498.     m = m.slice(0,ind)+getFormatted(ms,mo.match(/Xu/),mo.match(/Xb$/),mc,mb);
  1499.   }else{
  1500.     let mc = mo.match(/Xc[0-9][0-9]*/)?textColor[parseInt(mo.match(/Xc[0-9][0-9]*/)[0].replace(/Xb*c/,""))]:"";
  1501.     let mb = mo.match(/Xbc[0-9][0-9]*/)?textColor[parseInt(mo.match(/Xbc[0-9][0-9]*/)[0].replace(/Xb*c/,""))]:"";
  1502.     let mtd = ""+(mo.match(/Xu/)?" text-decoration: underline;":"");
  1503.     let mf = ""+mtd+(mo.match(/Xb$/)?" font-weight: bold;":"");
  1504.     m = "<span style='color:"+mc+"; background-color:"+mb+";"+mf+"'>"+m+"</span>";
  1505.   }
  1506.   return m;
  1507. }
  1508.  
  1509. function io(m,f){
  1510.   return Math.sign(m.indexOf(f))>-1?m.indexOf(f):100000;
  1511. }
  1512.  
  1513. function getFormatted(m,u,b,cf,cb){
  1514.   let strike = String.fromCharCode(0x1E);
  1515.   let italic = String.fromCharCode(0x1D);
  1516.   let mono = String.fromCharCode(0x11);
  1517.   if(!m)
  1518.     return "";
  1519.   let c = m.charAt(0);
  1520.   let sp = "<span style='text-decoration:"+((c==strike?"line-through ":"")+(u?"underline":"")+";")+(c==italic?"font-style: italic; ":"")+(c==mono?"font-family: monospace;":"")+(cf?" color: "+cf+";":"")+(cb?" background-color: "+cb+";":"")+"'>";
  1521.   m = m.substring(1);
  1522.   if(m.match(new RegExp("("+strike+"|"+italic+"|"+mono+")"))){
  1523.     let ind = Math.min(io(m,mono),io(m,italic),io(m,strike));
  1524.     let ms = m.slice(ind);
  1525.     m = m.slice(0,ind)+getFormatted(ms,false,false,false,false);
  1526.   }
  1527.   return sp+m+"</span>";
  1528. }
  1529.  
  1530. async function upload(e){
  1531.   e.preventDefault();
  1532.   if(!e.dataTransfer.files[0])
  1533.     return;
  1534.   let r = new FileReader();
  1535.   r.readAsDataURL(e.dataTransfer.files[0]);
  1536.   r.onload = ()=>{
  1537.     let l = request("https://tinyurl.com/api-create.php?url="+r.result);
  1538.     let t = document.getElementsByTagName("textarea")[0];
  1539.     let tstart = t.value.slice(0,t.selectionStart);
  1540.     let tend = t.value.slice(t.selectionStart);
  1541.     t.value = tstart+(tstart.match(/ $/)&&tstart!=""?"":" ")+l+(tend.match(/^ /)?"":" ")+tend;
  1542.   }
  1543. }
  1544.  
  1545.  
  1546.  
  1547.  
  1548.  
  1549.  
  1550.  
  1551.  
  1552.  
  1553.  
  1554.  
  1555.  
  1556.  
  1557.  
  1558.  
  1559.  
  1560.  
  1561.  
  1562.  
  1563.  
  1564.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement