NGA Filter

troll must die

As of 2019-09-03. See the latest version.

// ==UserScript==
// @name      NGA Filter
// @namespace https://greasyfork.org/users/263018
// @version    0.6
// @author     snyssss
// @description troll must die
// @match        *bbs.nga.cn/thread.php?fid=*
// @match        *bbs.nga.cn/read.php?tid=*
// @match        *ngabbs.com/thread.php?fid=*
// @match        *ngabbs.com/read.php?tid=*
// @grant       GM_registerMenuCommand
// @noframes
// ==/UserScript==

(function () {
  'use strict';

  const dataKey = 'troll_data';
  const modeKey = 'troll_mode';
  const keywordKey = 'troll_keyword';

  let trollMap = (function () {
    try {
      return JSON.parse(localStorage.getItem(dataKey)) || {};
    } catch (e) {
      localStorage.setItem(dataKey, '{}');
    }
    return {};
  })();

  let filterMode = ~~localStorage.getItem(modeKey);

  let filterKeyword = localStorage.getItem(keywordKey) || '';

  const isTroll = function (uid) {
    uid = ~~uid;
    if (uid) {
      return trollMap[uid];
    }
    return false;
  };

  const isMatch = function (text) {
    if (!!filterKeyword &&
      text.search(filterKeyword) >= 0) {
      return true;
    }
    return false;
  };

  const toggleTroll = function (uid, tag) {
    uid = ~~uid;
    if (uid) {
      if (trollMap[uid] &&
        tag === null) {
        delete trollMap[uid];
      } else {
        trollMap[uid] = tag ? [tag] : [];
      }
      localStorage.setItem(dataKey, JSON.stringify(trollMap));
    }
  };

  const getUID = function (e) {
    let ele = e.getElementsByClassName('author')[0];
    if (ele) {
      return ele.search.match(/uid=(\S*)/)[1];
    }
  };

  const getLink = function (e) {
    let ele = e.getElementsByClassName('topic')[0];
    ele.hide = function () {
      if (filterMode) {
        e.remove();
      } else {
        ele.style.textDecoration = 'line-through';
      }
    }
    return ele;
  };

  const getToggleButton = function (e) {
    let ele = e.getElementsByClassName('author')[0].nextElementSibling;
    if (ele.nextElementSibling) {
      ele = ele.nextElementSibling;
    }
    let uid = ~~ele.text;
    if (uid) {
      if (isTroll(uid)) {
        ele.style.background = '#CB4042';
      } else {
        ele.style.background = '#AAA';
      }
      return ele;
    }
    else {
      ele.onclick = null;
    }
  };

  const getAvatar = function (e) {
    let ele = e.getElementsByClassName('avatar')[0] || { style: { display: '' } };
    ele.show = ele.show || function () {
      ele.style.display = '';
    }
    ele.hide = ele.hide || function () {
      ele.style.display = 'none';
    }
    return ele;
  };

  const getContent = function (e) {
    let uid = getUID(e);
    let name = '$troll_' + uid;
    let ele = e.getElementsByClassName('postcontent')[0] || { innerHTML: '' };
    ele.content = ele.content || ele.innerHTML;
    ele.show = ele.show || function () {
      if (filterMode) {
        e.style.display = '';
      } else {
        ele.innerHTML = ele.content;
      }
    }
    ele.hide = ele.hide || function () {
      if (filterMode) {
        e.style.display = 'none';
      } else {
        ele.innerHTML =
          '<div class="lessernuke" style="background: #81C7D4; border-color: #66BAB7;">' +
          '<span class="crimson">Troll must die.</span> ' +
          '<a href="javascript:void(0)" onclick="var x = document.getElementsByName(&quot;' + name + '&quot;);for(var i=0;i<x.length;i++){x[i].style.display=&quot;&quot;}">点击查看</a>' +
          '<div style="display:none" name="' + name + '">' + ele.content + '</div>' +
          '</div>';
      }
    }
    return ele;
  };

  const getTag = function (e) {
    let container = e.getElementsByClassName('posterinfo')[0];
    let ele = container.children[1];
    if (ele.tagName === 'img') {
      ele = container.children[2];
    }
    if (ele.className !== 'crimson') {
      let t = document.createElement('div');
      t.className = 'crimson';
      t.style = 'display: none;';
      if (ele.getAttribute('name') === 'honor') {
        t.honor = ele;
      }
      ele.before(t);
      ele = t;
    }
    let uid = getUID(e);
    if (isTroll(uid)) {
      if (typeof (trollMap[uid]) === 'object' &&
        trollMap[uid].length) {
        ele.innerHTML = trollMap[uid][0];
      } else {
        ele.innerHTML = '';
      }
    }
    ele.show = ele.show || function () {
      if (ele.innerHTML) {
        ele.style.display = '';
      }
      if (ele.honor) {
        ele.honor.style.display = 'none';
      }
    }
    ele.hide = ele.hide || function () {
      ele.style.display = 'none';
      if (ele.honor) {
        ele.honor.style.display = '';
      }
    }
    return ele;
  };

  const observerElements = [
    (function () {
      let container = document.getElementById('topicrows');
      let func = function (e) {
        if (e.tagName == 'SCRIPT') return;
        let uid = getUID(e);
        let link = getLink(e);
        if (isTroll(uid) ||
          isMatch(link.innerHTML)) {
          link.hide();
        }
      }
      return [
        container,
        func
      ]
    })(),
    (function () {
      let container = document.getElementById('m_posts_c');
      let func = function (e) {
        if (e.tagName == 'SCRIPT') return;
        let uid = getUID(e);
        let toggle = getToggleButton(e);
        if (toggle) {
          toggle.onclick = function (e) {
            let tag = null;
            if (e.ctrlKey) {
              tag = window.prompt('标签', (trollMap[uid] || {})[0]);
              if (tag === null) {
                return;
              }
            }
            toggleTroll(uid, tag);
            container.refilter();
          };
        } else {
          return;
        }
        let avatar = getAvatar(e);
        let content = getContent(e);
        let tag = getTag(e);
        if (isTroll(uid)) {
          avatar.hide();
          content.hide();
          tag.show();
        }
        else {
          avatar.show();
          content.show();
          tag.hide();
        }
      }
      return [
        container,
        func
      ]
    })()
  ];

  [].slice.call(observerElements).forEach(function (e) {
    if (!e[0]) return;

    e[0].refilter = function () {
      [].slice.call(e[0].children).forEach(function (c) {
        e[1](c);
      });
    }

    e[0].refilter();

    let observer = new MutationObserver(function (mutations) {
      mutations.forEach(function (mutation) {
        if (mutation.addedNodes.length) {
          e[1](mutation.addedNodes[0]);
        }
      });
    });

    observer.observe(e[0], {
      childList: true
    });
  });

  if (filterMode) {
    GM_registerMenuCommand('过滤模式:删除', () => {
      localStorage.setItem(modeKey, 0);
      location.reload();
    });
  } else {
    GM_registerMenuCommand('过滤模式:标记', () => {
      localStorage.setItem(modeKey, 1);
      location.reload();
    });
  }

  GM_registerMenuCommand('修改过滤关键词', () => {
    let result = window.prompt('过滤关键词,用\"|\"隔开', filterKeyword);
    if (result === null ||
      result === filterKeyword) {
      return;
    }
    localStorage.setItem(keywordKey, result);
    location.reload();
  });
})();