cytube user highlight

highlight users in chat

// ==UserScript==
// @name         cytube user highlight
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  highlight users in chat
// @author       unrealfag
// @match        https://cytu.be/r/*
// @grant        none
// ==/UserScript==
'use strict';

const defaultColor = '#2c902c99';
const toggleOnClass = 'glyphicon glyphicon-heart';
const toggleOffClass = 'glyphicon glyphicon-heart-empty';
const storageId = 'unrealfags-usercolor-menu';
const openMessage = `<i class="glyphicon glyphicon-list"></i> Highlights `;
const closeMessage = `<i class="glyphicon glyphicon-floppy-disk"></i> Save! `;

const storage = (name, value) => {
	if (typeof value === 'undefined') {
  	return localStorage[name] ? JSON.parse(localStorage[name]) : undefined;
  }
  localStorage[name] = JSON.stringify(value);
};

const createElement = (tag, inner, style) => {
  const el = document.createElement(tag);
  if (style) Object.keys(style).forEach(key => { el.style[key] = style[key]; });
  if (typeof inner === 'object' && inner !== null) el.appendChild(inner);
  else el.innerHTML = inner || '';
  return el;
};

const Menu = createElement('ul', null, {
  display: 'none',
  'white-space': 'nowrap',
  padding: '5px',
});
const MenuHelpers = {
  MenuHandlers: [],
  getNameListInput: (nameList) => {
    const NamesInput = createElement('input', null, {
      height: '11px',
      display: 'inline-block',
      width: 'initial',
    });
    NamesInput.type = 'text';
    NamesInput.className = 'form-control';
    NamesInput.value = nameList;
    NamesInput.placeholder = 'user1 user2 userName...';
    return NamesInput;
  },
  getColorInput: (color) => {
    const ColorInput = createElement('input', null, {
      height: '11px',
      display: 'inline-block',
      color: 'white',
      width: '100px',
      'font-family': 'monospace',
      margin: '0px 5px',
    });
    ColorInput.addEventListener('input', MenuHelpers.onColorInputChanged);
    ColorInput.className = 'form-control';
    ColorInput.value = color || defaultColor;
    ColorInput.style.background = color || defaultColor;
    return ColorInput;
  },
  onColorInputChanged: (target) => {
    const color = target.target.value.match(/#[a-fA-F0-9]{8}/g);
    if (color) {
      target.target.style.background = color;
      target.target.style['border-color'] = 'initial';
    } else {
      target.target.style.background = 'transparent';
      target.target.style['border-color'] = 'red';
    }
  },
  getToggleButton: (isOn) => {
    const ToggleButton = document.createElement('i');
    ToggleButton.addEventListener('click', MenuHelpers.toggleRow);
    ToggleButton.className = isOn ? toggleOnClass : toggleOffClass;
    return ToggleButton;
  },
  toggleRow: (target) => {
    const isOn = target.target.className === toggleOnClass;
    target.target.className = isOn ? toggleOffClass : toggleOnClass;
  },
  getMenuRow: (isOn, color, nameList) => {
    const ToggleButton = MenuHelpers.getToggleButton(isOn);
    const ColorInput = MenuHelpers.getColorInput(color);
    const NamesInput = MenuHelpers.getNameListInput(nameList);
    const MenuRow = createElement('div');
    MenuRow.appendChild(ToggleButton);
    MenuRow.appendChild(ColorInput);
    MenuRow.appendChild(NamesInput);
    const MenuItem = createElement('li', MenuRow);
    return {
      element: MenuItem,
      isEnabled: () => ToggleButton.className === toggleOnClass,
      getColor: () => ColorInput.value || defaultColor,
      getNameList: () => NamesInput.value || '',
    };
  },
  openMenu: () => {
    const menuItems = storage(storageId) || [];
    menuItems.push({
      isOn: true,
      color: defaultColor,
      names: '',
    });
    menuItems.forEach(item => {
      const itemData = MenuHelpers.getMenuRow(item.isOn, item.color, item.names);
      MenuHelpers.MenuHandlers.push(itemData);
      Menu.appendChild(itemData.element);
    });
    MenuButton.innerHTML = closeMessage;
    Menu.style.display = 'block';
  },
  closeMenu: () => {
    const listData = MenuHelpers.MenuHandlers.map(menuData => {
      const isOn = menuData.isEnabled();
      const color = menuData.getColor();
      const names = menuData.getNameList();
      if (names && color) {
        return { isOn, color, names };
      }
      return null;
    }).filter(i => i !== null);
    storage(storageId, listData);
    MenuHelpers.MenuHandlers.length = 0;
    while (Menu.firstChild) { Menu.removeChild(Menu.firstChild); }
    MenuButton.innerHTML = openMessage;
    Menu.style.display = 'none';
    applyColors();
  }
};
Menu.className = 'dropdown-menu';

const MenuButton = createElement('button', openMessage, {
  padding: '2px 5px 2px 5px',
  'font-size': '11px',
  height: '20px',
  'vertical-align': 'top',
});
MenuButton.addEventListener('click', () => {
  const isClosed = Menu.style.display === 'none';
  if (isClosed) MenuHelpers.openMenu();
  else MenuHelpers.closeMenu();
});
MenuButton.className = 'btn btn-primary';

const Container = createElement('div');
Container.className = 'dropdown pull-right';
Container.appendChild(MenuButton);
Container.appendChild(Menu);

const applyColors = () => {
  if (!head) { return; }
  const styleClass = `${storageId}_style`;
  var oldStyles = head.getElementsByClassName(styleClass);
  while (oldStyles[0]) {
    head.removeChild(oldStyles[0]);
  }

  const userColorData = storage(storageId);
  userColorData.forEach(colorData => {
    if (colorData.isOn) {
      const names = colorData.names.split(' ');
      const style = createElement('style', `\
${names.map(name => `.chat-msg-${name}>:not(:last-of-type)`).join(', ')} {\
    display: inline-block;
    vertical-align: middle;
    line-height: 20px;
    background-color: ${colorData.color};\
}`);
      style.type = 'text/css';
      style.className = styleClass;
      head.appendChild(style);
    }
  });
};

const ChatHeader = document.getElementById('chatheader');
ChatHeader.appendChild(Container);
const head = document.getElementsByTagName('head')[0];
applyColors();