Muting+α on Twitter

Muting texts/links/tags/userIDs on "Twitter Web Client" and changing tweets' style

اعتبارا من 12-08-2014. شاهد أحدث إصدار.

// ==UserScript==
// @name        Muting+α on Twitter
// @namespace   https://github.com/mosaicer
// @author      mosaicer
// @description Muting texts/links/tags/userIDs on "Twitter Web Client" and changing tweets' style
// @version     4.0
// @include     https://twitter.com/
// @include     https://twitter.com/search?*
// @grant       GM_getValue
// @grant       GM_setValue
// @grant       GM_registerMenuCommand
// ==/UserScript==
(function () {
  var Init = function() {
        this.menu_jp = {
          // オブジェクトは、キー:フラグ名+"Change",値:メニューの関数
          mute_text_flag: ["ツイート本文についてのミュートを", {}],
          mute_link_flag: ["リンクについてのミュートを", {}],
          mute_tag_flag: ["ハッシュタグについてのミュートを", {}],
          mute_userId_flag: ["ユーザーIDについてのミュートを", {}],
          style_flag: ["各ツイートの装飾を", {}]
          // lang_flag: ["英語に切り替える", {}]
        };
        this.menu_en = {
          // オブジェクトは、キー:フラグ名+"Change",値:メニューの関数
          mute_text_flag: [" mute for texts in tweet", {}],
          mute_link_flag: [" mute for links in tweet", {}],
          mute_tag_flag: [" mute for hashtags in tweet", {}],
          mute_userId_flag: [" mute for userIDs in tweet", {}],
          style_flag: [" changing tweet style", {}]
          // lang_flag: ["Change the language you're using to Japanese", {}]
        };
        this.msgFlag = false;
        this.msg = "";
        this.muteNameArray = {
          mute_words: [],
          mute_links: [],
          mute_tags: [],
          mute_ids: []
        };
      },
      setting,
      HeaderStruct = function() {
        this.contentHeader = document.querySelector(".content-header");
        this.headerInner = document.querySelector(".header-inner");
        this.previousNode = pageURL === "https://twitter.com/" ?
          document.querySelector("[class='DashboardProfileCard  module']") :
          document.querySelector("[class='module'][role='navigation']");
        this.parentFormNode = pageURL === "https://twitter.com/" ?
          document.querySelector("[class='dashboard dashboard-left ']") :
          document.querySelector("[class='dashboard dashboard-left']");
        this.formNode = document.createElement("div");
        this.formContainer = "";
        this.headerWidth = pageURL === "https://twitter.com/" ? 418 : 440;
        this.openClose_msg = {
          ja: "▶ フォーム欄の開閉 ◀",
          en: "▶ Open/Close input form ◀"
        };
        this.openClose_btn = document.createElement("div");
        this.btnAry = {
          ja: ["追加", "削除", "確認"],
          en: ["Add", "Del", "Conf"]
        };
        this.placeholderAry = {
          ja: [
                "ミュートする文字を入力してください",
                "テキスト",
                "リンク",
                "ハッシュタグ",
                "ユーザーID",
                "ミュートするタイプを選んでください"
              ],
          en: [
                "Please input letters you want mute in tweet",
                "texts",
                "links",
                "hashtags",
                "userIDs",
                "Please choose a type of muting"
              ]
        };
      },
      header,
      ButtonSet = function() {
        this.muteFlag = 0;
        this.pluralFlag = 0;
        this.btnFlag = "";
        this.muteListTemp = "";
        this.altMsgAry = {
          ja: [
                "ミュートしたい文字列はすでに設定されています",
                "ミュートしたい文字列は削除できません",
                "ミュートしたい文字列は設定した文字列とマッチしませんでした",
                "↓ミュートする文字列をカンマ区切りで表示しています↓\n\n",
                "ミュートする文字列が設定されていません",
                "申し訳ないですが、ミュートする文字列に,/は使うことができません"
              ],
          en: [
                "The word is already set for mute word",
                "The word can not be deleted",
                "The word is not set for mute word",
                "↓The mute words separated by conmma↓\n\n",
                "The mute words are not found",
                "Sorry, the mute words which contains the word ',/' can not be set"
              ]
        };
      },
      buttonAction,
      MuteFeatures = function() {
        this.homeTweets = "";
        this.replyPrnt = ""; // リプライツイートの親要素
        this.flag = "";
        this.i = 0;
        this.j = 0;
        // 要素を判断する時に参照する
        this.tweetPrnt = "";
        this.tweetElement = "";
      },
      muteAction,
      key = "",
      pageURL = location.href,
      userLang = window.navigator.language === "ja" ? "ja" : "en",
      // 各ツイートを装飾する、コンストラクタではない
      tweetStyleChange = function() {
        // ツイートの文字を太字に
        if (pageURL === "https://twitter.com/") {
          Array.prototype.slice.call(document.querySelectorAll("[class='js-tweet-text tweet-text']")).forEach(
            function (targetNode) {
              targetNode.style.fontWeight = "bold";
            }
          );
        }
        // ユーザー名を赤く
        Array.prototype.slice.call(document.querySelectorAll("[class*='js-action-profile-name']")).forEach(
          function (targetNode) {
            targetNode.style.color = "red";
          }
        );
        // 時間経過を青く
        Array.prototype.slice.call(document.querySelectorAll("[data-long-form='true']")).forEach(
          function (targetNode) {
            targetNode.style.color = "blue";
          }
        );
        // リンクは必ず新しいタブに飛ばす
        Array.prototype.slice.call(document.querySelectorAll("[class='twitter-timeline-link']")).forEach(
          function (targetNode) {
            targetNode.setAttribute("target", "_blank");
          }
        );
      },
      // MutationObserver用
      MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver,
      observer;

  Init.prototype = {
    // アクセス時の処理
    accessSet: function() {
      // if (GM_getValue("lang_flag") === true) {
      if (userLang === "ja") {
        for (key in this.menu_jp) {
          if (this.menu_jp.hasOwnProperty(key)) {
            // 初アクセス時のみに実行、フラグの設定
            if (typeof GM_getValue(key) === "undefined") {
              // if (key !== "lang_flag") { // 引用符必要?
                GM_setValue(key, true);
              // } else {
              //   if (window.navigator.language === "ja") {
              //     GM_setValue(key, true);
              //   } else {
              //     GM_setValue(key, false);
              //   }
              // }
            }
            // ユーザースクリプトコマンドメニューを構成
            // if (key !== "lang_flag") { // 引用符必要?
              this.msgFlag = GM_getValue(key) === true ? "無効" : "有効";
              this.msg = this.menu_jp[key][0] + this.msgFlag + "にする";
            // } else {
            //   this.msg = this.menu_jp[key][0];
            // }
            GM_registerMenuCommand(this.msg, this.featuresChg.bind(this.menu_jp[key][1][key + "Change"], key));
          }
        }
      } else {
        for (key in this.menu_en) {
          if (this.menu_jp.hasOwnProperty(key)) {
            // 初アクセス時のみに実行、フラグの設定
            if (typeof GM_getValue(key) === "undefined") {
              // if (key !== "lang_flag") { // 引用符必要?
                GM_setValue(key, true);
              // } else {
              //   if (window.navigator.language === "ja") {
              //     GM_setValue(key, true);
              //   } else {
              //     GM_setValue(key, false);
              //   }
              // }
            }
            // ユーザースクリプトコマンドメニューを構成
            // if (key !== "lang_flag") { // 引用符必要?
              this.msgFlag = GM_getValue(key) === true ? "Disable" : "Enable";
              this.msg = this.msgFlag + this.menu_en[key][0];
            // } else {
            //   this.msg = this.menu_en[key][0];
            // }
            GM_registerMenuCommand(this.msg, this.featuresChg.bind(this.menu_en[key][1][key + "Change"], key));
          }
        }
      }
      for (key in this.muteNameArray) {
        if (this.muteNameArray.hasOwnProperty(key) && typeof GM_getValue(key) !== "undefined") {
          if (GM_getValue(key).indexOf(",/") >= 0) {
            this.muteNameArray[key] = GM_getValue(key).split(",/");
          } else {
            this.muteNameArray[key].push(GM_getValue(key));
          }
        }
      }
      if (typeof GM_getValue("form_flag") === "undefined") {
        GM_setValue("form_flag", true);
      }
      if (typeof GM_getValue("style_flag") === "undefined") {
        GM_setValue("style_flag", true);
      }
    },
    // ユーザースクリプトコマンドメニューで実行する関数、有効/無効の切り替え
    featuresChg: function(flagName) {
      this.msgFlag = GM_getValue(flagName) === true ? false : true;
      GM_setValue(flagName, this.msgFlag);
      location.href = pageURL;
    }
  };

  HeaderStruct.prototype.styleSet = function () {
    // ヘッダーのスタイルを変更する
    if (pageURL === "https://twitter.com/") {
      this.contentHeader.style.borderStyle = "hidden";
      this.headerInner.style.height = "65px";
      this.headerInner.style.backgroundColor = "transparent";
    }
    // フォーム欄の開閉を操作できるボタンを置く
    this.openClose_btn.setAttribute("id", "open_close");
    this.openClose_btn.style.backgroundColor = "#FFD700";
    this.openClose_btn.style.cursor = "pointer";
    this.openClose_btn.style.width = "290px";
    this.openClose_btn.style.textAlign = "center";
    this.openClose_btn.style.marginBottom = "15px";
    this.openClose_btn.appendChild(document.createTextNode(this.openClose_msg[userLang]));
    this.parentFormNode.insertBefore(this.openClose_btn, this.previousNode); // 検索とホームで別のノードを参照する必要がある
    // 各テキストボックスとボタンを設置
    this.formContainer = "<form onsubmit='return false;'>" +
          "<input type='text' id='mLtrForm' class='form_btn' value='' placeholder='" +
          this.placeholderAry[userLang][0] + "' style='width: " + this.headerWidth + "px;'>" +
          "<input type='button' id='mLtrAdd' class='form_btn' value='" + this.btnAry[userLang][0] + "'>" +
          "<input type='button' id='mLtrRmv' class='form_btn' value='" + this.btnAry[userLang][1] + "'>" +
          "<input type='button' id='mLtrConf' value='" + this.btnAry[userLang][2] + "' style='float:right; color:black;'>" +
          "</form><div style='background-color:white; margin-top:8px; font-size:12px; color:black; height:23px;'>" +
          "<span style='color:green;'>" + this.placeholderAry[userLang][5] + ": </span>" +
          "<label style='margin-right: 17px;'><input type='radio' name='muteLetter' value='mute_words' checked>" +
          this.placeholderAry[userLang][1] + "</label>" +
          "<label style='margin-right: 17px;'><input type='radio' name='muteLetter' value='mute_links'>" +
          this.placeholderAry[userLang][2] + "</label>" +
          "<label style='margin-right: 17px;'><input type='radio' name='muteLetter' value='mute_tags'>" +
          this.placeholderAry[userLang][3] + "</label>" +
          "<label style='margin-right: 17px;'><input type='radio' name='muteLetter' value='mute_ids'>" +
          this.placeholderAry[userLang][4] + "</label></div>";
    if (pageURL === "https://twitter.com/") {
      document.getElementById("content-main-heading").innerHTML = this.formContainer;
    } else {
      this.formNode.style.marginBottom = "10px";
      this.formNode.style.textAlign = "center";
      this.formNode.innerHTML = this.formContainer;
      document.getElementById("timeline").insertBefore(this.formNode, this.contentHeader);
    }
    Array.prototype.slice.call(document.querySelectorAll(".form_btn")).forEach(
      function (targetNode) {
        targetNode.setAttribute("float", "left");
        targetNode.style.marginRight = "10px";
        targetNode.style.color = "black";
      }
    );
    // フォーム欄のフラグをチェック
    if (GM_getValue("form_flag") === false) {
      if (pageURL === "https://twitter.com/") {
        this.contentHeader.style.display = "none";
      } else {
        this.formNode.style.display = "none";
      }
    }
  };

  ButtonSet.prototype = {
    // ミュートする文字列を追加する
    addMuteLtr: function (btn_flag, theLetter) {
      this.btnFlag = btn_flag;
      this.pluralFlag = 0;
      if (theLetter !== "") {
        if (theLetter.indexOf(",/,/") < 0) {
          if (theLetter.indexOf(",/") >= 0) {
            this.pluralFlag = 1;
            this.muteListTemp = [];
            theLetter.split(",/").forEach(this.addFunc, buttonAction);
          } else {
            this.muteListTemp = "";
            this.addFunc(theLetter);
          }
          if (this.muteListTemp[0] !== "" && this.pluralFlag === 1 || this.muteListTemp !== "" && this.pluralFlag === 0) {
            if (this.pluralFlag === 0) {
              GM_setValue(btn_flag, this.muteListTemp);
            } else {
              if (typeof GM_getValue(btn_flag) === "undefined" || setting.muteNameArray[btn_flag][0] === "") {
                GM_setValue(btn_flag, this.muteListTemp.join(",/"));
              } else {
                GM_setValue(btn_flag, setting.muteNameArray[btn_flag].join(",/") + ",/" + this.muteListTemp.join(",/"));
              }
            }
            location.href = pageURL;
          }
        } else {
          alert(this.altMsgAry[userLang][5]);
        }
      }
    },
    addFunc: function (targetLtr) {
      this.targetText = targetLtr;
      this.muteFlag = 0;
      // 未入力の場合ではない時
      if (this.targetText !== "") {
        // 初めてor空に、追加する時
        if (typeof GM_getValue(this.btnFlag) === "undefined" || setting.muteNameArray[this.btnFlag][0] === "") {
          if (this.pluralFlag === 1) {
            this.muteListTemp.push(this.targetText);
          } else {
            this.muteListTemp = this.targetText;
          }
        }
        // すでに入ってる状態の時
        else {
          setting.muteNameArray[this.btnFlag].forEach(this.completeComp, buttonAction);
          if (this.muteFlag === 0) {
            if (this.pluralFlag === 1) {
              this.muteListTemp.push(this.targetText);
            } else {
              this.muteListTemp = setting.muteNameArray[this.btnFlag].join(",/") + ",/" + this.targetText;
            }
          } else {
            alert(this.altMsgAry[userLang][0]);
          }
        }
      }
    },
    // ミュートする文字列を削除する
    delMuteLtr: function (btn_flag, theLetter) {
      this.btnFlag = btn_flag;
      this.muteListTemp = setting.muteNameArray[btn_flag];
      if (theLetter !== "") {
        if (theLetter.indexOf(",/,/") < 0) {
          if (theLetter.indexOf(",/") >= 0) {
            theLetter.split(",/").forEach(this.deleteFunc, buttonAction);
          } else {
            this.deleteFunc(theLetter);
          }
          if (this.muteListTemp !== setting.muteNameArray[btn_flag]) {
            GM_setValue(this.btnFlag, this.muteListTemp.join(",/"));
            location.href = pageURL;
          }
        } else {
          alert(this.altMsgAry[userLang][5]);
        }
      }
    },
    deleteFunc: function (targetLtr) {
      this.targetText = targetLtr;
      this.muteFlag = 0;
      // 未入力ではない時
      if (this.targetText !== "") {
        // 文字列が入ってない時
        if (typeof GM_getValue(this.btnFlag) === "undefined" || this.muteListTemp[0] === "") {
          alert(this.altMsgAry[userLang][1]);
        }
        // 文字列がセットされている時
        else {
          this.muteListTemp.forEach(this.completeComp, buttonAction);
          if (this.muteFlag === 1) {
            this.muteListTemp = this.muteListTemp.filter(this.filterFunc, buttonAction);
          } else {
            alert(this.altMsgAry[userLang][2]);
          }
        }
      }
    },
    // ミュートする文字列を確認する
    confMuteLtr: function (btn_flag) {
      // ミュートする文字列が設定されていた時
      if (typeof GM_getValue(btn_flag) !== "undefined" && setting.muteNameArray[btn_flag][0] !== "") {
        alert(this.altMsgAry[userLang][3] + setting.muteNameArray[btn_flag]);
      }
      // ミュートする文字列が設定されていなかった時
      else {
        alert(this.altMsgAry[userLang][4]);
      }
    },
    completeComp: function (targetLtr) {
      if (this.muteFlag === 0 && this.targetText === targetLtr) {
        this.muteFlag = 1;
      }
    },
    filterFunc: function (targetLtr) {
      return (this.targetText !== targetLtr);
    }
  };

  MuteFeatures.prototype = {
    // ミュート機能を始動
    muteTweet: function (addedTweets) {
      // プロモーションを消去
      if (document.querySelector("[data-promoted='true']") !== null) {
        document.querySelector("[data-promoted='true']").parentNode.style.display = "none";
      }
      // 人と繋がるバナーを消去
      // if (document.querySelector("[class='promptbird promptbird-below-black-bar']") !== null) {
      //   document.querySelector("[class='promptbird promptbird-below-black-bar']").style.display = "none";
      // }

      // ノードが追加された時
      if (typeof addedTweets !== "undefined") {
        this.homeTweets = Array.prototype.slice.call(addedTweets);
      }
      // ノードが追加されなかった時
      else {
        this.homeTweets = Array.prototype.slice.call(document.querySelectorAll("[data-item-type]"));
      }
      this.homeTweets.forEach(this.nodeCheck, muteAction);
    },
    // ツイートが返信かどうかなどの判断
    nodeCheck: function (targetNode) {
      var tweetPtag;
      if (targetNode.hasAttribute("data-item-type")) {
        this.tweetPrnt = targetNode;
        // <LI>タグ内が空ではない時
        if (typeof this.tweetPrnt.childNodes[1].childNodes[3] !== "undefined") {
          tweetPtag = this.tweetPrnt.childNodes[1].childNodes[3].childNodes[3];
        }
        // 返信のツイートである時
        if (typeof tweetPtag === "undefined") {
          // ホームの場合
          if (pageURL === "https://twitter.com/") {
            // 要素がある場合
            for (this.i = 3; typeof this.tweetPrnt.childNodes[1].childNodes[this.i] !== "undefined"; this.i++) {
              this.replyPrnt = this.tweetPrnt.childNodes[1].childNodes[this.i];
              if (
                typeof this.replyPrnt.childNodes[1] !== "undefined" &&
                this.replyPrnt.childNodes[1].getAttribute("data-you-block")
              ) {
                this.tweetPrnt = this.replyPrnt; // リプライを消すときに参照する親ノードを変更
                tweetPtag = this.replyPrnt.childNodes[1].childNodes[3].childNodes[3];
                this.tweetElmCheck(tweetPtag);
                this.tweetPrnt = targetNode; // 値を元に戻す
              }
            }
          }
          // 検索ページの時、返信は無いため気にする必要はなくこのイレギュラーなツイートのみを判断する
          else {
            // すべてのトップで余計なノードを通さない
            if (
              this.tweetPrnt.childNodes[1].className !== "account-group js-account-group js-user-profile-link" &&
              this.tweetPrnt.childNodes[1].className !== "avatar size32 js-user-profile-link"
            ) {
              tweetPtag = this.tweetPrnt.childNodes[1].childNodes[1].childNodes[1].childNodes[3].childNodes[3];
              this.tweetElmCheck(tweetPtag);
            }
          }
        }
        // 返信ではない場合
        else {
          // タイムライン検索の時
          if (tweetPtag.className === "fullname js-action-profile-name show-popup-with-id") {
            tweetPtag = this.tweetPrnt.childNodes[1].childNodes[5];
          }
          this.tweetElmCheck(tweetPtag);
        }
      }
    },
    // ツイート内の要素を判断
    tweetElmCheck: function(twtPtag) {
      // <P>タグのthis.j番目の要素がある場合
      for (this.j = 0; typeof twtPtag.childNodes[this.j] !== "undefined"; this.j++) {
        this.tweetElement = twtPtag.childNodes[this.j];
        // <A>タグの時
        if (this.tweetElement.nodeName === "A") {
          // pic.twitter.com
          if (this.tweetElement.getAttribute("data-pre-embedded")) {
            this.tweetElement.href = "http://" + this.tweetElement.childNodes[0].nodeValue; // 元のURLでジャンプさせる
            this.muteLtrCheck("mute_links");
          }
          // pic.twitter.com以外のリンク
          else if (this.tweetElement.getAttribute("title")) {
            this.tweetElement.href = this.tweetElement.getAttribute("title");
            this.muteLtrCheck("mute_links");
          }
          // ハッシュタグ
          else if (this.tweetElement.getAttribute("data-query-source")) {
            this.muteLtrCheck("mute_tags");
          }
          // ユーザーID
          else if (this.tweetElement.childNodes[0].childNodes[0].nodeValue === "@") {
            this.muteLtrCheck("mute_ids");
          }
        }
        // テキストか<STRONG>タグの時
        else if (this.tweetElement.nodeName === "#text" || this.tweetElement.nodeName === "STRONG") {
          this.muteLtrCheck("mute_words");
        }
      }
    },
    // ミュートする文字を決定する
    muteLtrCheck: function (mute_flag) {
      if (typeof GM_getValue(mute_flag) !== "undefined" && setting.muteNameArray[mute_flag][0] !== "") {
        this.flag = mute_flag;
        setting.muteNameArray[mute_flag].forEach(this.muteFunc, muteAction);
      }
    },
    // ツイートの各対象についてミュートする
    muteFunc: function (targetLtr) {
      var nodeValTemp = "";
      switch (this.flag) {
        case "mute_words":
          if (GM_getValue("mute_text_flag") === true) {
            // テキスト
            if (this.tweetElement.nodeName === "#text") {
              if (this.tweetElement.nodeValue.indexOf(targetLtr) >= 0) {
                this.tweetPrnt.style.display = "none";
              }
            }
            // <STRONG>タグ
            else {
              // 前のテキストノードがあれば加える
              if (this.tweetElement.previousSibling !== null && this.tweetElement.previousSibling.nodeName === "#text") {
                nodeValTemp = this.tweetElement.previousSibling.nodeValue;
              }
              // <STRONG>タグ内のテキストを取得
              nodeValTemp += this.tweetElement.childNodes[0].nodeValue;
              // 後ろのテキストノードがあれば加える
              if (this.tweetElement.nextSibling !== null && this.tweetElement.nextSibling.nodeName === "#text") {
                nodeValTemp += this.tweetElement.nextSibling.nodeValue;
              }
              if (nodeValTemp.indexOf(targetLtr) >= 0) {
                this.tweetPrnt.style.display = "none";
              }
            }
          }
          break;
        case "mute_links":
          if (GM_getValue("mute_link_flag") === true) {
            // pic.twitter.com以外のリンク
            if (this.tweetElement.getAttribute("title")) {
              if (this.tweetElement.getAttribute("title").indexOf(targetLtr) >= 0) {
                this.tweetPrnt.style.display = "none";
              }
            }
            // pic.twitter.com
            else if (this.tweetElement.innerHTML.replace(/<strong>|<\/strong>/g, "").indexOf(targetLtr) >= 0) {
              this.tweetPrnt.style.display = "none";
            }
          }
          break;
        case "mute_tags":
          if (
            GM_getValue("mute_tag_flag") === true &&
            this.tweetElement.childNodes[1].innerHTML.replace(/<strong>|<\/strong>/g, "").indexOf(targetLtr) >= 0
          ) {
            this.tweetPrnt.style.display = "none";
          }
          break;
        case "mute_ids":
          if (
            GM_getValue("mute_userId_flag") === true &&
            this.tweetElement.childNodes[1].innerHTML.replace(/<strong>|<\/strong>/g, "").indexOf(targetLtr) >= 0
          ) {
            this.tweetPrnt.style.display = "none";
          }
          break;
      }
    }
  };

  // インスタンス化
  setting = new Init();
  header = new HeaderStruct();
  buttonAction = new ButtonSet();
  muteAction = new MuteFeatures();

  setting.accessSet(); // DBの初期設定、メニューの構築、ミュートリストの取得
  header.styleSet(); // ヘッダー部分の構築
  muteAction.muteTweet(); // ツイートのミュート処理

  if (GM_getValue("style_flag") === true) {
    tweetStyleChange(); // ツイートの装飾
  }

  // ボタンイベント---------------------------------------------------------------------------------------------
  document.addEventListener("click", function (e) {
    var tgtNode = e.target; // クリックしたノード
    switch (tgtNode.id) {
      // フォーム欄の開閉
      case "open_close":
        if (GM_getValue("form_flag") === true) {
          if (pageURL === "https://twitter.com/") {
            header.contentHeader.style.display = "none";
          } else {
            header.formNode.style.display = "none";
          }
          GM_setValue("form_flag", false);
        } else {
          if (pageURL === "https://twitter.com/") {
            header.contentHeader.style.display = "block";
          } else {
            header.formNode.style.display = "block";
          }
          GM_setValue("form_flag", true);
        }
        break;
      // ミュートする文字列の追加
      case "mLtrAdd":
        buttonAction.addMuteLtr(document.querySelector("[checked]").value, document.getElementById("mLtrForm").value);
        break;
      // ミュートする文字列の削除
      case "mLtrRmv":
        buttonAction.delMuteLtr(document.querySelector("[checked]").value, document.getElementById("mLtrForm").value);
        break;
      // ミュートする文字列の確認
      case "mLtrConf":
        buttonAction.confMuteLtr(document.querySelector("[checked]").value);
        break;
      default:
        // どれに対してミュートするかラジオボタンにチェック
        if (tgtNode.name === "muteLetter") {
          if (document.querySelector("[checked]")) { // 2つ以上付かないように前のチェックを消去
            document.querySelector("[checked]").removeAttribute("checked");
          }
          tgtNode.setAttribute("checked", "checked");
        }
        break;
    }
  }, false);
  // 追加のページの読み込みを監視して実行-----------------------------------------------------------------------
  observer = new MutationObserver(function (mutations) {
    mutations.forEach(function (mutation) {
      if (GM_getValue("style_flag") === true) {
        tweetStyleChange();
      }
      // 空じゃない時
      if (mutation.addedNodes.length !== 0) {
        muteAction.muteTweet(mutation.addedNodes); // 追加されたノードを渡す
      }
    });
  });
  observer.observe(document.getElementById("stream-items-id"), {childList: true } );
})();