hnOsmium0001

irccloud-sws with strikethrough support (userscript)

Feb 1st, 2021
1,063
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // @name        Send with Style
  3. // @namespace   dogancelik.com
  4. // @description Enables font styles in IRCCloud
  5. // @include     https://www.irccloud.com/*
  6. // @version     4.4.0
  7. // @grant       none
  8. // @updateURL   https://github.com/dogancelik/irccloud-sws/raw/master/build/send_with_style.meta.js
  9. // @downloadURL https://github.com/dogancelik/irccloud-sws/raw/master/build/send_with_style.user.js
  10. // ==/UserScript==
  11.  
  12. (function () {
  13.  
  14. 'use strict';
  15.  
  16. var Settings = {
  17.   keyPrefix: 'sws.',
  18.   get: function(key, def) {
  19.     var getVal = localStorage.getItem(this.keyPrefix + key);
  20.     if (typeof def !== 'undefined' && getVal == null) {
  21.       this.set(key, def);
  22.       return def;
  23.     }
  24.     return getVal;
  25.   },
  26.   set: function(key, value) {
  27.     localStorage.setItem(this.keyPrefix + key, value);
  28.   },
  29.   remove: function (keys) {
  30.     var keys = [].concat(keys);
  31.     keys.forEach((function (key) {
  32.       localStorage.removeItem(this.keyPrefix + key);
  33.     }).bind(this));
  34.   }
  35. };
  36.  
  37. function upgradeOldSettings() {
  38.   var settingsTable = {
  39.     'swsEnabled': 'sws.enabled',
  40.     'swsAlias': 'sws.alias',
  41.     'swsKeyboard': 'sws.key.enabled',
  42.     'swsKeyCtrl': 'sws.key.ctrl',
  43.     'swsKeyAlt': 'sws.key.alt',
  44.     'swsKeyShift': 'sws.key.shift',
  45.     'swsKeyChar': 'sws.key.char',
  46.     'swsMarkdown': 'sws.markdown',
  47.     'swsColorsTable': 'sws.colorsTable'
  48.   };
  49.   for (var oldKey in settingsTable) {
  50.     var newKey = settingsTable[oldKey];
  51.     var oldVal = localStorage[oldKey];
  52.     var newVal = localStorage[newKey];
  53.     if (typeof oldVal !== 'undefined') {
  54.       localStorage.setItem(newKey, oldVal);
  55.       localStorage.removeItem(oldKey);
  56.     }
  57.   }
  58. }
  59.  
  60. var isChrome = /chrome/.test(navigator.userAgent.toLowerCase());
  61.  
  62. var swsEnabled, swsAlias, swsMarkdown, swsKeyboard, swsKeyCtrl, swsKeyAlt, swsKeyShift, swsKeyChar, shortcutWaiting, swsColorsTable, swsSpecialFuncs, colorsTable, last2Keys;
  63.  
  64. var fontStyles = {
  65.   color: '\u0003',
  66.   bold: '\u0002',
  67.   reset: '\u000f',
  68.   italic: '\u001d',
  69.   underline: '\u001f',
  70.   strikethrough: '\u001e',
  71. };
  72.  
  73. function replaceFontStyles (str) {
  74.   return str.replace(/%B/g, fontStyles.bold)
  75.     .replace(/%R/g, fontStyles.reset)
  76.     .replace(/%I/g, fontStyles.italic)
  77.     .replace(/%U/g, fontStyles.underline)
  78.     .replace(/%X/g, fontStyles.strikethrough)
  79.     .replace(/%C/g, fontStyles.color);
  80. }
  81.  
  82. function replaceMarkdown (str) {
  83.   if (/^\/mode/.test(str)) return str;
  84.   if (/^\\/.test(str)) return str.substr(1);
  85.  
  86.   return str.replace(/\*{3}([^\*]+)\*{3}/g, fontStyles.bold + fontStyles.italic + '$1' + fontStyles.italic + fontStyles.bold)
  87.     .replace(/\*{2}([^\*]+)\*{2}/g, fontStyles.bold + '$1' + fontStyles.bold)
  88.     .replace(/\*{1}([^\*]+)\*{1}/g, fontStyles.italic + '$1' + fontStyles.italic)
  89.     .replace(/\_{2}([^\_]+)\_{2}/g, fontStyles.underline + '$1' + fontStyles.underline)
  90.     .replace(/\_{1}([^\_]+)\_{1}/g, fontStyles.italic + '$1' + fontStyles.italic)
  91.     .replace(/\~{2}([^\~]+)\~{2}/g, fontStyles.strikethrough + '$1' + fontStyles.strikethrough);
  92. }
  93.  
  94. function replaceAliases (str) {
  95.   if (swsAlias.val().trim() === "") {
  96.     return str;
  97.   } else {
  98.     swsAlias.val().split('\n').forEach(function (i) {
  99.       var keyval = i.split(/,(.*)/g);
  100.       str = str.split(keyval[0]).join(keyval[1]);
  101.     });
  102.     return str;
  103.   }
  104. }
  105.  
  106. function toggleShortcutProgress (input, toggle) {
  107.   if (toggle) {
  108.     input.css('outline', '1px solid blue');
  109.     shortcutWaiting = true;
  110.   } else {
  111.     input.css('outline', '');
  112.     shortcutWaiting = false;
  113.   }
  114. }
  115.  
  116. function insertTo(input, text) {
  117.   var cursorPos = input.prop('selectionStart');
  118.   var val = input.val();
  119.   var before = val.substring(0, cursorPos);
  120.   var after  = val.substring(cursorPos, val.length);
  121.   input.val(before + text + after);
  122.   input.prop('selectionStart', cursorPos + 1);
  123.   input.prop('selectionEnd', cursorPos + 1);
  124. }
  125.  
  126. // colorsTable start
  127. var currentInput, currentColorsTable, origColorsTable; // required for colorsTable click
  128.  
  129. function toggleColorsTable(input, toggle) {
  130.   var offset = input.offset();
  131.  
  132.   if (currentColorsTable.data('sws') !== '1') {
  133.     currentColorsTable.find('td').on('click', function() {
  134.       var number = $(this).children().first().text();
  135.       var text = currentInput.val();
  136.       currentInput.val(text + number);
  137.       toggleColorsTable(currentInput, false);
  138.     });
  139.     currentColorsTable.data('sws', '1');
  140.   }
  141.  
  142.   currentColorsTable.css({
  143.     display: (toggle ? 'block' : 'none'),
  144.     left: offset.left + 'px',
  145.     top: (offset.top - 40) + 'px'
  146.   });
  147. }
  148.  
  149. // required for showing colorsTable in normal mode
  150. function trackLast2Keys(key) {
  151.   last2Keys += key;
  152.   if (last2Keys.length > 2) {
  153.     last2Keys = last2Keys.substring(1,3);
  154.   }
  155. }
  156.  
  157. function createColorsTable() {
  158.   var scroll = currentInput.parents('.buffermain').find('.scroll');
  159.   var colorsTable = $('#sws-current-colors-table');
  160.  
  161.   if (colorsTable.length === 0) {
  162.     colorsTable = origColorsTable.clone();
  163.     colorsTable.attr('id', 'sws-current-colors-table');
  164.     scroll.append(colorsTable);
  165.     colorsTable.css({
  166.       position: 'fixed',
  167.       display: 'none'
  168.     });
  169.   }
  170.  
  171.   return colorsTable.detach().appendTo(scroll);
  172. }
  173. // colorsTable end
  174.  
  175. // specialFunctions start
  176. function rainbow(text, match) {
  177.   var output = '';
  178.   var colors = ['05', '04', '07', '08', '09', '03', '11', '10', '12', '02', '06', '13', '15', '14'];
  179.   var startIndex = Math.floor(Math.random() * colors.length);
  180.  
  181.   for (var i = 0; i < match.length; i++) {
  182.     var char = match[i];
  183.     if (char !== ' ') {
  184.       output += fontStyles.color + colors[startIndex++] + char + fontStyles.color;
  185.     } else {
  186.       output += char;
  187.     }
  188.     if (startIndex >= colors.length) {
  189.       startIndex = 0;
  190.     }
  191.   }
  192.  
  193.   return output;
  194. }
  195.  
  196. var specialFunctions = [
  197.   {
  198.     regex: /<rainbow>(.*)<\/rainbow>/g,
  199.     func: rainbow
  200.   }
  201. ];
  202.  
  203. function replaceSpecials(text) {
  204.   var oldText = text;
  205.   var newText = oldText;
  206.   for (var i = 0; i < specialFunctions.length; i++) {
  207.     var item = specialFunctions[i];
  208.     newText = oldText.replace(item.regex, item.func);
  209.   }
  210.   return newText;
  211. }
  212. // specialFunctions end
  213.  
  214. function bindTextarea () {
  215.   if (cb() == null) {
  216.     return false;
  217.   }
  218.  
  219.   var input = $('#bufferInputView' + cb().bid());
  220.   currentInput = input;
  221.   currentColorsTable = createColorsTable();
  222.  
  223.   if (input.data('sws') !== '1') {
  224.     input.on('keypress', function (e) {
  225.       var lowerKey = String.fromCharCode(e.which).toLowerCase();
  226.       if (e.which > 31) {
  227.         trackLast2Keys(lowerKey);
  228.       }
  229.     });
  230.  
  231.     input.on('keyup', function (e) {
  232.       var keyboardEnabled = swsKeyboard.prop('checked');
  233.       var colorsEnabled = swsColorsTable.prop('checked');
  234.       if (colorsEnabled && !keyboardEnabled && last2Keys === '%c') {
  235.         toggleColorsTable(input, true);
  236.       }
  237.     });
  238.  
  239.     input.on('keydown', function (e) {
  240.       var mainEnabled = swsEnabled.prop('checked');
  241.       var keyboardEnabled = swsKeyboard.prop('checked');
  242.       var markdownEnabled = swsMarkdown.prop('checked');
  243.       var colorsEnabled = swsColorsTable.prop('checked');
  244.       var specialEnabled = swsSpecialFuncs.prop('checked');
  245.       var lowerKey = (isChrome ? String.fromCharCode(e.which) : e.key).toLowerCase();
  246.  
  247.       if (colorsEnabled) {
  248.         toggleColorsTable(input, false);
  249.       }
  250.  
  251.       if (keyboardEnabled) {
  252.         var enabledCtrl = swsKeyCtrl.prop('checked');
  253.         var enabledAlt = swsKeyAlt.prop('checked');
  254.         var enabledShift = swsKeyShift.prop('checked');
  255.         var activateChar = swsKeyChar.val().trim().substr(0, 1).toLowerCase();
  256.  
  257.         if (e.ctrlKey === enabledCtrl && e.altKey === enabledAlt && e.shiftKey === enabledShift && lowerKey == activateChar) {
  258.           toggleShortcutProgress(input, true);
  259.           return;
  260.         }
  261.       }
  262.  
  263.       if (e.keyCode === 13 && mainEnabled) {
  264.         var val = input.val();
  265.         val = replaceAliases(val);
  266.         input.val(val);
  267.  
  268.         if (specialEnabled) {
  269.           var val = input.val();
  270.           val = replaceSpecials(val);
  271.           input.val(val);
  272.         }
  273.  
  274.         if (!keyboardEnabled) {
  275.           var val = input.val();
  276.           val = replaceFontStyles(val);
  277.           input.val(val);
  278.         }
  279.  
  280.         if (markdownEnabled) {
  281.           var val = input.val();
  282.           val = replaceMarkdown(val);
  283.           input.val(val);
  284.         }
  285.       }
  286.  
  287.       if (shortcutWaiting && keyboardEnabled) {
  288.         var noInput = false;
  289.         switch (lowerKey) {
  290.           case "c":
  291.             insertTo(input, fontStyles.color);
  292.             if (colorsEnabled) {
  293.               toggleColorsTable(input, true);
  294.             }
  295.             noInput = true;
  296.             break;
  297.           case "b":
  298.             insertTo(input, fontStyles.bold);
  299.             noInput = true;
  300.             break;
  301.           case "i":
  302.             insertTo(input, fontStyles.italic);
  303.             noInput = true;
  304.             break;
  305.           case "u":
  306.             insertTo(input, fontStyles.underline);
  307.             noInput = true;
  308.             break;
  309.           case 'x':
  310.             insertTo(input, fontStyles.strikethrough);
  311.             noInput = true;
  312.             break;
  313.           case "r":
  314.             insertTo(input, fontStyles.reset);
  315.             noInput = true;
  316.             break;
  317.         }
  318.         toggleShortcutProgress(input, false);
  319.         if (noInput) return false;
  320.       }
  321.     });
  322.     input.data('sws', '1');
  323.   }
  324. }
  325.  
  326. function embedStyle() {
  327.   return $('<style>').prop('type', 'text/css').html('#sws-container{font-size:18px}.sws-bold{font-weight:bold}.sws-info-table{border:1px solid rgba(0,0,0,0.1);border-radius:.2em;}.sws-info-table th,.sws-info-table td{padding:.2em .4em}.sws-colors-table td{background-color:#fff;height:20px;width:20px;line-height:20px;font-size:12px;border:1px solid #000;border-left:0;text-align:center;padding:1px;cursor:pointer}.sws-colors-table td:first-child{border-left:1px solid #000}.sws-colors-table span{display:inline-block;height:20px;width:20px}#sws-colors-box{display:none}#sws-colors-anchor{cursor:pointer}.sws-key-box{display:inline-block;background-color:rgba(0,0,0,0.1);border-radius:.25em;padding:.25em .5em;margin-right:.25em}#sws-key-char{width:30px}#sws-custom-alias{height:60px;width:100%}#sws-enabled-label{font-weight:normal}#sws-enabled-check:not(:checked) ~ #sws-enabled-label{color:#f00;}#sws-enabled-check:not(:checked) ~ #sws-enabled-label::after{content:"Not enabled"}#sws-enabled-check:checked ~ #sws-enabled-label{color:#008000;}#sws-enabled-check:checked ~ #sws-enabled-label::after{content:"Enabled"}').appendTo('head:first');
  328. }
  329.  
  330. function createMenu() {
  331.   return $('<div id="sws-bar" class="settingsMenu__item settingsMenu__item__sendwithstyle"><a class="settingsMenu__link" href="/?/settings=sendwithstyle">Send with Style</a></div>').insertAfter('.settingsContainer .settingsMenu .settingsMenu__item:last');
  332. }
  333.  
  334. function createContainer() {
  335.   return $('<div id="sws-container" data-section="sendwithstyle" class="settingsContents settingsContents__sendwithstyle"><h2 class="settingsTitle"><span>Send with Style&nbsp;</span><input id="sws-enabled-check" type="checkbox"/>&nbsp;<label id="sws-enabled-label" for="sws-enabled-check"></label></h2><p class="explanation">Type your text as you normally would, use the codes to style your text.</p><p class="explanation sws-bold">If your settings are lost, please&nbsp;<a href="https://github.com/dogancelik/irccloud-sws/wiki/Help#my-custom-settings-have-disappeared-in-new-version-what-do-i-do" target="_blank">read this page</a>&nbsp;to learn how to recover it.</p><table class="sws-info-table"><tr><th>Code</th><th>Example</th></tr><tr><td><code>%C</code>&nbsp;for&nbsp;<a id="sws-colors-anchor" title="Click here to show color numbers" style="border-bottom: 1px dashed black;"><font color="#ff0000">c</font><font color="#cc8f33">o</font><font color="#99ed66">l</font><font color="#66f899">o</font><font color="#33accc">r</font></a></td><td><code>%C2This is blue</code>&nbsp;→&nbsp;<code><span style="color: blue">This is blue</span></code></td></tr><tr id="sws-colors-box"><td colspan="2"><table class="sws-colors-table"><tr><td><span class="bg-white black">0</span></td><td><span class="bg-black white">1</span></td><td><span class="bg-navy white">2</span></td><td><span class="bg-green white">3</span></td><td><span class="bg-red black">4</span></td><td><span class="bg-maroon white">5</span></td><td><span class="bg-purple white">6</span></td><td><span class="bg-orange black">7</span></td><td><span class="bg-yellow black">8</span></td><td><span class="bg-lime black">9</span></td><td><span class="bg-teal white">10</span></td><td><span class="bg-cyan black">11</span></td><td><span class="bg-blue white">12</span></td><td><span class="bg-magenta black">13</span></td><td><span class="bg-grey black">14</span></td><td><span class="bg-silver black">15</span></td></tr></table></td></tr><tr><td><code>%B</code>&nbsp;for&nbsp;<b>bold</b></td><td><code>%BVery bold</code>&nbsp;→&nbsp;<code><b>Very bold</b></code></td></tr><tr><td><code>%I</code>&nbsp;for&nbsp;<i>italic</i></td><td><code>%IPizza</code>&nbsp;→&nbsp;<code><i>Pizza</i></code></td></tr><tr><td><code>%U</code>&nbsp;for&nbsp;<u>underline</u></td><td><code>%UBeep</code>&nbsp;→&nbsp;<code><u>Beep</u></code></td></tr><tr><td><code>%R</code>&nbsp;for reset</td><td><code>%C4Wo%Rrd</code>&nbsp;→&nbsp;<code><span style="color: red">Wo</span>rd</code></td></tr></table><p class="explanation"><input id="sws-keyboard-mode" type="checkbox"/><label for="sws-keyboard-mode">&nbsp;Keyboard Mode (Disables %C, %B etc.)&nbsp;</label><span class="sws-key-box"><label for="sws-key-ctrl">Ctrl:&nbsp;</label><input id="sws-key-ctrl" type="checkbox"/></span><span class="sws-key-box"><label for="sws-key-alt">Alt:&nbsp;</label><input id="sws-key-alt" type="checkbox"/></span><span class="sws-key-box"><label for="sws-key-alt">Shift:&nbsp;</label><input id="sws-key-shift" type="checkbox"/></span><span class="sws-key-box"><label for="sws-key-char">Key:&nbsp;</label><input id="sws-key-char" type="text"/></span></p><p class="explanation"><input id="sws-colors-table" type="checkbox"/><label for="sws-colors-table">&nbsp;Show Colors Table (when you are about to type color numbers)</label></p><p class="explanation"><input id="sws-markdown-mode" type="checkbox"/><label for="sws-markdown-mode">&nbsp;Markdown Mode (Enables <code>*</code> and <code>_</code> for <i>italic text</i>, <code>**</code> for <b>bold text</b>, and <code>__</code> for <u>underlined text</u>.)</label></p><p class="explanation"><input id="sws-special-funcs" type="checkbox"/><label for="sws-special-funcs">&nbsp;Special Functions (Enables <code>&lt;rainbow&gt;</code> tag)</label></p><h3>Custom aliases</h3><textarea id="sws-custom-alias"></textarea><hr/><p id="sws-donate" class="explanation sws-bold">If you like this script, please&nbsp;<a href="http://dogancelik.com/donate.html" target="_blank">consider a donation</a></p><p class="explanation"><a href="https://github.com/dogancelik/irccloud-sws" target="_blank">Source code</a>&nbsp;-&nbsp;<a href="https://github.com/dogancelik/irccloud-sws/issues" target="_blank">Report bug / Request feature</a>&nbsp;-&nbsp;<a href="https://github.com/dogancelik/irccloud-sws/wiki/Help" target="_blank">Help</a></p></div>').insertAfter('.settingsContentsWrapper .settingsContents:last');
  336. }
  337.  
  338. function init() {
  339.   embedStyle();
  340.   upgradeOldSettings(); // for version 4.0.3 and below
  341.  
  342.   var menu = createMenu();
  343.   var container = createContainer();
  344.  
  345.   var hashName = 'sendwithstyle';
  346.   if (window.location.search === '?/settings=' + hashName) {
  347.     SESSIONVIEW.showSettings(hashName);
  348.   }
  349.  
  350.   swsEnabled = container.find('#sws-enabled-check').change(function () {
  351.     Settings.set('enabled', this.checked);
  352.   }).prop('checked', JSON.parse(Settings.get('enabled', true)));
  353.  
  354.   var colorsBox = container.find('#sws-colors-box');
  355.   container.find('#sws-colors-anchor').click(function () {
  356.     colorsBox.toggle();
  357.   });
  358.  
  359.   swsAlias = container.find("#sws-custom-alias");
  360.   swsAlias.val(Settings.get('alias'))
  361.   .on('change', function () {
  362.     Settings.set('alias', swsAlias.val());
  363.   });
  364.  
  365.   swsKeyboard = container.find('#sws-keyboard-mode').change(function () {
  366.     Settings.set('key.enabled', this.checked);
  367.   }).prop('checked', JSON.parse(Settings.get('key.enabled')) || false);
  368.  
  369.   swsKeyCtrl = container.find('#sws-key-ctrl').change(function () {
  370.     Settings.set('key.ctrl', this.checked);
  371.   }).prop('checked', JSON.parse(Settings.get('key.ctrl')) || true);
  372.  
  373.   swsKeyAlt = container.find('#sws-key-alt').change(function () {
  374.     Settings.set('key.alt', this.checked);
  375.   }).prop('checked', JSON.parse(Settings.get('key.alt')) || false);
  376.  
  377.   swsKeyShift = container.find('#sws-key-shift').change(function () {
  378.     Settings.set('key.shift', this.checked);
  379.   }).prop('checked', JSON.parse(Settings.get('key.shift')) || true);
  380.  
  381.   swsKeyChar = container.find('#sws-key-char').change(function () {
  382.     Settings.set('key.char', this.value);
  383.   }).val(Settings.get('key.char', 'z'));
  384.  
  385.   swsMarkdown = container.find('#sws-markdown-mode').change(function () {
  386.     Settings.set('markdown', this.checked);
  387.   }).prop('checked', JSON.parse(Settings.get('markdown', false)));
  388.  
  389.   swsColorsTable = container.find('#sws-colors-table').change(function () {
  390.     Settings.set('colorsTable', this.checked);
  391.     if (!this.checked) {
  392.       colorsTable.css('display', 'none');
  393.     }
  394.   }).prop('checked', JSON.parse(Settings.get('colorsTable', false)));
  395.  
  396.   origColorsTable = container.find('.sws-colors-table');
  397.  
  398.   swsSpecialFuncs = container.find('#sws-special-funcs').change(function () {
  399.     Settings.set('specialFuncs', this.checked);
  400.   }).prop('checked', JSON.parse(Settings.get('specialFuncs', false)));
  401.  
  402.   bindTextarea();
  403. }
  404.  
  405. (function checkSession () {
  406.   if (window.hasOwnProperty('SESSION')) {
  407.     window.SESSION.bind('init', function () {
  408.       init();
  409.  
  410.       window.SESSION.buffers.on('doneSelected', function () {
  411.         bindTextarea();
  412.       });
  413.     });
  414.   } else {
  415.     setTimeout(checkSession, 100);
  416.   }
  417. })();
  418.  
  419. })();
  420.  
Advertisement
Add Comment
Please, Sign In to add comment