おーぷん2ch無視設定変更スクリプト Fork

  • /*
     * @title おーぷん2ch無視設定変更スクリプト
     * @include http://*.open2ch.net/test/read.cgi/*
     * @license MIT License
     */
    //作った人 Awn
    //Forked from && Inspired by http://let.hatelabo.jp/TimeFires/let/hJmesYHtkMte
    
    (function (d) {
      //note:「Hatena::Let」の@includeが効かないようなので、
      //      URLが「http://*.open2ch.net/test/read.cgi/*」を満たさ無い場合、スクリプト内部で弾く
      let REGEXP_OPEN2CHREADCGI = new RegExp(/http:\/\/.*\.open2ch\.net\/test\/read\.cgi\/.*/);
      if (!REGEXP_OPEN2CHREADCGI.test(location.href)) {
        console.warn("available only under http://*.open2ch.net/test/read.cgi/*");
        return;
      }
    
      //member
      let appName = 'ignoreManager';
      let _ignores = ignores;
    
    
      //initializer
      _init();
    
    
      //function
      function _init() {
        _embedHTML();
        _assignEventListener();
      }
    
      function _embedHTML() {
        _embedBackgroundElm();
        _embedMainElm();
        _setIgnores();
      }
    
      function _assignEventListener() {
        AddBtnEventListener();
        DeleteAllBtnEventListener();
        DeleteWithoutTwitterBtnEventListener();
        DeleteSelectedBtnEventListener();
        CloseIgnoreManager();
      }
    
      function _embedBackgroundElm() {
        let bg = d.createElement('div');
        bg.id = `${appName}_bg`;
        bg.style = `
          background:black;
          position:fixed;
          top:0;
          left:0;
          width:100%;
          height:100%;
          opacity:0.5;
          z-index:30;
      `;
        d.body.appendChild(bg);
      }
    
      function _embedMainElm() {
        let main = d.createElement('div');
        main.id = `${appName}_main`;
        main.style = `
          background:#EFEFEF;
          position:fixed;
          top:30px;
          left:30px;
          width:calc(100% - 80px);
          height:calc(100% - 80px);
          z-index:31;
          border:solid black 1px;
          padding:10px;
        `;
        main.innerHTML = `
        <h1>無視id編集画面</h1>
        <hr>
        <form name="ign_form" style="width:500px" onsubmit="return false;">
          <fieldset>
            <legend>一括削除</legend>
            <input type="button" value="全て削除" id="b_deleteAll">
            <input type="button" value="TwitterID以外を削除" id="b_deleteWithoutTwitter">
          </fieldset>
          <fieldset>
            <legend>個別追加</legend>
            <label>
              追加するid <input type="text" id="t_input">
            </label>
            <input type="button" value="追加する" id="b_add">
          </fieldset>
        </form>
        <h2>無視id ↓</h2>
        <hr>
        <div id="ignoresView" style="height:200px;overflow:scroll;">
        </div>
        <hr>
        <input type="button" value="選択したidを削除する" id="b_deleteSelected">
        <span id="s_messageArea"></span>
        `;
        d.body.appendChild(main);
      }
    
      function _setIgnores() {
        let keys = Object.keys(_ignores);
        let arr = [];
        let id;
        for (key of keys) {
          [id, key] = _transformID(key);
          arr.push(`<label style="display: block;"><input type="checkbox" value="${key}">${id}</label>`);
        }
        let div = d.querySelector('#ignoresView');
        div.innerHTML = arr.join('');
      }
    
      function _transformID(key) {
        let id;
        if (key.length > 3 && key.startsWith('tw@')) {
          id = key;
          key.replace(/^tw@/, 'tw');
          return [id, key];
        }
        if (key.length > 3 && key.startsWith('tw')) {
          id = key.replace(/^tw/, 'tw@');
          return [id, key];
        }
        if (key.length > 3 && key.startsWith('@')) {
          id = key.replace(/^@/, 'tw@');
          key = key.replace(/^@/, 'tw');
          return [id, key];
        }
        id = key;
        return [id, key];
      }
    
      function _addIgnore(key) {
        let elm = d.createElement('label');
        elm.style = 'display:block';
        id = key;
        id = id.length > 3 && id.startsWith('tw') ? id.replace(/^tw/, 'tw@') : id;
        elm.innerHTML = `<input type="checkbox" value="${key}">${id}`;
        let div = d.querySelector('#ignoresView');
        div.appendChild(elm);
      }
    
      function _validateID(id) {
        return new Promise((resolve, reject) => {
          if (id.length < 3) {
            reject();
          }
    
          //note: idで利用できない文字は弾く
          if (/[^A-Za-z0-9@_]/.test(id)) {
            reject();
          }
    
          //note: @が2つ以上現れるidは存在しないので弾く
          if (id.includes('@') && id.match(/@/g).length > 1) {
            reject();
          }
    
          if (id.length === 3) {
            //note: 3文字の時はtwitterアカウント連携のidではないと「見做す」
            //     理論上(?)[1-3]文字のtwitterアカウントも存在しうるが、そんなレアな人が書き込む可能性は皆無であろう。
            if (id.includes('@') || id.includes('_')) {
              reject();
            }
            resolve(id);
          }
    
          //note: 3文字より大きい場合 -> twitterIDと見做す
          //     idが[10,9,8,7,6,5,4]桁の過去スレは諦めよう
          /*
            # 正常ケース
              tw@aidee_42 -> twaidee_42
              @aidee_42 -> twaidee_42
              aidee_42 -> twaidee_42
            # エラーケース
              正常ケース以外
          */
          if (id.length > 3) {
            if (id.includes('@')) {
              if (id.startsWith('tw@')) {
                id = id.replace(/^tw@/, 'tw');
                resolve(id);
              } else if (id.startsWith('@')) {
                id = id.replace(/@/, 'tw');
                resolve(id);
              } else {
                reject();
              }
            } else {
              id = 'tw' + id;
              resolve(id);
            }
          }
        });
      }
    
      //deleter
      function _deleteAll() {
        delStorage(cachekey);
        _ignores = new Object();
        ignores = _ignores;
        return;
      }
    
      function _deleteAllFromView() {
        let div = d.querySelector('#ignoresView');
        while (div.firstChild) {
          div.removeChild(div.firstChild);
        }
      }
    
    
      function _deleteWithoutTwitter() {
        let keys = Object.keys(_ignores);
        for (let key of keys) {
          if (key.length === 3) {
            delete _ignores[key];
          }
        }
        setStorage(cachekey, JSON.stringify(_ignores));
        ignores = _ignores;
      }
    
      function _deleteWithoutTwitterFromView() {
        let div = d.querySelector('#ignoresView');
        let elms = div.querySelectorAll('input[type="checkbox"]');
        for (let elm of elms) {
          if (elm.value.length === 3) {
            div.removeChild(elm.parentElement);
          }
        }
      }
    
      function _deleteSelected() {
        let div = d.querySelector('#ignoresView');
        let elms = div.querySelectorAll('input[type="checkbox"]');
        let obj = {};
        for (let elm of elms) {
          obj[elm.value] = 1;
        }
        _ignores = obj;
        ignores = _ignores;
        setStorage(cachekey, JSON.stringify(ignores));
        return;
      }
    
      function _deleteSelectedFromView() {
        let div = d.querySelector('#ignoresView');
        let elms = div.querySelectorAll('input[type="checkbox"]:checked');
        for (let elm of elms) {
          div.removeChild(elm.parentElement);
        }
        return;
      }
    
      //EventListener
      function AddBtnEventListener() {
        let elm = d.querySelector('#b_add');
        elm.addEventListener('click', function (ev) {
          ev.preventDefault();
          let id = d.querySelector('#t_input').value;
          id = id.trim();
          _validateID(id)
            .then((key) => {
              _ignores[key] = 1;
              _addIgnore(key);
              setStorage(cachekey, JSON.stringify(_ignores));
              updateIgnore();
              console.dir(_ignores);
            }, () => { alert(`${id}はidっぽくないみたい。。`); });
        });
      }
    
      function DeleteAllBtnEventListener() {
        let elm = d.querySelector('#b_deleteAll');
        elm.addEventListener('click', function (ev) {
          ev.preventDefault();
          if (confirm('消しますか?')) {
            _deleteAll();
            _deleteAllFromView();
          }
        });
      }
    
      function DeleteWithoutTwitterBtnEventListener() {
        let elm = d.querySelector('#b_deleteWithoutTwitter');
        elm.addEventListener('click', function (ev) {
          ev.preventDefault();
          if (confirm('消しますか?')) {
            _deleteWithoutTwitter();
            _deleteWithoutTwitterFromView();
          }
        });
      }
    
      function DeleteSelectedBtnEventListener() {
        let elm = d.querySelector('#b_deleteSelected');
        elm.addEventListener('click', function (ev) {
          ev.preventDefault();
          if (confirm('消しますか?')) {
            _deleteSelectedFromView();
            _deleteSelected();
          }
        })
      }
    
      function CloseIgnoreManager() {
        let elm = document.querySelector('#ignoreManager_bg');
        elm.addEventListener('click', function (ev) {
          if (confirm('閉じますか?')) {
            let main = d.querySelector(`#${appName}_main`);
            let bg = d.querySelector(`#${appName}_bg`);
            d.body.removeChild(main);
            d.body.removeChild(bg);
          }
        });
      }
    
      return;
    })(document);
  • Permalink
    このページへの個別リンクです。
    RAW
    書かれたコードへの直接のリンクです。
    Packed
    文字列が圧縮された書かれたコードへのリンクです。
    Userscript
    Greasemonkey 等で利用する場合の .user.js へのリンクです。
    Loader
    @require やソースコードが長い場合に多段ロードする Loader コミのコードへのリンクです。
    Metadata
    コード中にコメントで @xxx と書かれたメタデータの JSON です。