月別アーカイブ: 2021年3月

【iPhone / iPad】続・Ohajiki Web ブラウザでねじれ天国のUIをそこそこ快適にする

はじめに

前回記事では検索窓の幅調整だけというショボい内容だったが、今回大幅にUI改善を加えてみた。Ohajiki Web ブラウザの導入は前回記事を参考にし、貼り付けるコードをこの記事の最後のものに置き換えてほしい。

2021/03/26追記

コードを修正し、発言ボタンの2度押しを防止する機能を追加。また、各機能の有効/無効をフラグでコードの先頭に追加した。

追加内容

文学ブロッカー

規定文字数以上の発言を途中で省略する。コード内の BLK_MAX_LENGTH の値を変えれば何文字以上で省略するかを変更可能。デフォルトは800文字。

サイドバー格納

左の参加者リストおよび検索窓をデフォルトで非表示にし、ログを画面幅最大で表示できるように。サイドバーの中身は「リスト・検索窓を開く▼」ボタンで開閉可能(表示位置が適当なのはご愛敬)。

発言欄のフォントサイズを調整

これによって入力時にズームされないようになり、発言の全体が見やすくなった(はず)。

「村を出る」ボタンタップ時に確認ダイアログ表示

誤タップによる退村を防げる。

発言ボタン2度押し防止 2021/03/26追加

そのまま。通常の発言欄だけでなく、すべてのフォームに適用される。

その他

最初にねじ天の村かどうかを判定しているので、他のサイトで悪さをする可能性はありません。

修正版コード

タップでコピーされます。適用手順は前回記事を確認してください。このコードより下に文章はありません。

(function() {
  // 各機能ごとの有効フラグ。不要なものは true を false にすると無効になります。
  const USE_BLK_LTR = true;    // 文学ブロッカー
  const USE_ADJ_SEARCH = true; // 検索窓幅調整
  const USE_RMV_SIDE = true;   // 左リスト畳み込み&発言入力欄ズームなし
  const USE_CFM_EXT = true;    // 村を出るボタンに確認ダイアログ追加
  const USE_BLK_DBL = true;    // 発言ボタン2度押し抑止

  // BLK_MAX_LENGTH 以上の文字数を短縮表示する
  const BLK_MAX_LENGTH = 800;

  const url = window.location.href;
  if (!url.match(/nejiten\.halfmoon\.jp\/index\.cgi\?vid=/)) {
    return;
  }

  if (USE_BLK_LTR) {
    blockLiterature();
  }
  if (USE_ADJ_SEARCH) {
    adjustSearchBox();
  }
  if (USE_RMV_SIDE) {
    removeSidebar();
  }
  if (USE_CFM_EXT) {
    confirmExit();
  }
  if (USE_BLK_DBL) {
    disableSubmit();
  }

  // 文学ブロッカー
  function blockLiterature() {
    // 表示変更リンクのテキスト
    const OPEN_MES = '▼全文表示';
    const CLOSE_MES = '▲短縮表示';

    function createOpenDiv(mes_num) {
      let div = document.createElement('div');
      div.style.color = 'blue';
      let a = document.createElement('a')
      a.id = 'open' + mes_num;
      a.innerText = OPEN_MES;
      a.style.cursor = 'pointer';
      div.append(a);
      return div;
    }

    function createCloseDiv(mes_num) {
      let div = document.createElement('div');
          div.style.color = 'blue';
      let a = document.createElement('a')
      a.id = 'close' + mes_num;
      a.innerText = CLOSE_MES;
      a.style.cursor = 'pointer';
      div.append(a);
      return div;
    }

    function createMsgDiv(msg, id) {
      let div = document.createElement('div');
      div.id = id;
      div.innerText = msg;

      return div;
    }

    let mes = document.querySelectorAll('[class$=body1]');
    for (let i = 0; i < mes.length; i++) {
      if (BLK_MAX_LENGTH < mes[i].innerText.length) {
        let msg = mes[i].innerText;
        let shortMsg = msg.slice(0, BLK_MAX_LENGTH) + "...\n\n";
        mes[i].innerText = '';

        // 長文を退避
        let msgDiv = createMsgDiv(msg, 'msg' + i);
        let closeDiv = createCloseDiv(i);
        msgDiv.append(closeDiv);
        msgDiv.style.display = 'none';

        // 短縮文を作成
        let shortMsgDiv = createMsgDiv(shortMsg, 'shortMsg' + i);
        let openDiv = createOpenDiv(i);
        shortMsgDiv.append(openDiv);

        // クリック時に開閉を呼ぶようにイベントリスナ設定
        closeDiv.addEventListener('click', function() {
          toggle(i, true);
        });
        openDiv.addEventListener('click', function() {
          toggle(i, false);
        });

        // 追記
        mes[i].append(shortMsgDiv);
        mes[i].append(msgDiv);

      }
    }

    function toggle(i, isOpened) {
      const msgDivId = 'msg' + i;
      const shortMsgDivId = 'shortMsg' + i;
      let msgDiv = document.getElementById(msgDivId);
      let shortMsgDiv = document.getElementById(shortMsgDivId);

      if (isOpened) {
        // 全文表示から短縮表示に切り替える
        msgDiv.style.display = 'none';
        shortMsgDiv.style.display = 'inline';

        // 短縮時に発言が詰まってしまうので元発言のトップにスクロール
        shortMsgDiv.scrollIntoView(true);
      } else {
        // 短縮表示から全文表示に切り替える
        shortMsgDiv.style.display = 'none';
        msgDiv.style.display = 'inline';
      }
    }
  }

  // 検索窓幅調整
  function adjustSearchBox() {
    var target = document.querySelector('input#cse-search-box');
    const observer = new MutationObserver((mutations) => {
        mutations.forEach((mutation) => {
            target.style.width = "auto";
        });
    });

    var config = { attributes: true, childList: true, characterData: true }
    observer.observe(target, config);
  }

  // 左リスト削除
  function removeSidebar() {
    var side = document.querySelector('#side');
    var side2 = document.querySelector('#side2');
    var sides = document.createElement('div');
    sides.id = 'sides';
    sides.style.display = 'none';
    sides.appendChild(side);
    sides.appendChild(side2);
    var btn = document.createElement('span');
    var btnMsg = document.createTextNode('リスト・検索窓を開く▼');
    btn.id = 'btn';
    btn.classList.add('hope_toggle');
    btn.appendChild(btnMsg);
    btn.onclick = () => {
      if (sides.style.display === 'none') {
        btn.innerText = btn.innerText.replace('開く▼', '閉じる▲');
        sides.style.display = 'block';
      } else {
        btn.innerText = btn.innerText.replace('閉じる▲', '開く▼');
        sides.style.display = 'none';
      }
    }
    var content = document.querySelector('#content');
    content.appendChild(btn);
    content.appendChild(sides);
  
    document.querySelector('body > table > tbody > tr > td > table > tbody > tr > td > table > tbody > tr:nth-child(2) > td:nth-child(1)').style.display = 'none';
    document.querySelector('#main > td:nth-child(1)').style.display = 'none';
    document.querySelector('body > table > tbody > tr > td > table > tbody > tr > td > table > tbody > tr:nth-child(5) > td:nth-child(1)').style.display = 'none';
    document.querySelector('body > table > tbody > tr > td > table').style.width = 'auto';
    
    // 発言フォームのフォントサイズ変更(フォーカス時にズームされないようにする)
    let textAreas = document.querySelectorAll('textarea');
    (Array.from(textAreas)).forEach((ta) => { ta.style.fontSize = '24px' });
  }

  // 村を出るボタンに確認ダイアログ追加
  function confirmExit() {
    var exit = document.querySelector('input[value="村を出る"]');
    if (exit) {
      var form = exit.closest('form');
      form.onsubmit = () => {
        if (window.confirm('村を出ますか?')) {
          return true;
        } else {
          return false;
        }
      };
    }
  }

  // 発言ボタン2度押し防止
  function disableSubmit() {
    let forms = Array.from(document.querySelectorAll('form'));
    let btn = Array.from(document.querySelectorAll('input[type="submit"]'));
    
    forms.forEach((form) => {
        form.onsubmit = () => {
            btn.forEach((b) => {
                b.disabled = true;
            })
        }
    });
  }
})();

【iPhone / iPad】Ohajiki Web ブラウザでねじれ天国のUIをちょっと快適にする

※2021/03/25追記 こちらで紹介しているよりも多機能なスクリプトを次の記事で公開しています。合わせてご覧ください。

はじめに

500以上の役職が遊べる人狼サイト、ねじれ天国。99人村のようなアホみたいな村も不定期に開催されており、そのカオスっぷりは多くの人狼プレイヤーを引き付けてやまない。

この記事ではiOS向けブラウザアプリの「Ohajiki Web ブラウザ」でユーザースクリプトを適用して使うことで、スマホからでもちょっと快適にねじれ天国を操作する方法を解説する。具体的には、村中での左リスト下のGoogle検索ボックスが横に伸びてしまっているのを、適切なサイズに調整する。

※Android版は現在配信されていないようなので、本記事はiPhone / iPad ユーザーのみが対象です。もしAndroidでもユーザースクリプトが使えるブラウザがあれば教えてください。

Ohajiki のインストールと設定手順

インストール

AppStore Ohajiki Web ブラウザからアプリをインストールしてねじれ天国にアクセスして、適当な村を開く。

強制ダークモードの解除

※OSの設定がダークモードでなければ、この設定は不要かもしれないので飛ばしてください。

強制ダークモードがONになっているとねじれ天国の表示が崩れるため、オフにしておく。

強制ダークモードONの状態

画面中央下のアイコンをタップ→上に現れた同じアイコンをもう一度タップ→左上の歯車アイコン(設定)をタップして設定画面に遷移して行う。タップじゃなくてスワイプでも可。

タップ1度目
タップ2度目。左上に設定のアイコンが表示される。

設定画面の「目の保護機能」にある「強制ダークモードを使用」をオフにする。

強制ダークモードがONの状態
オフにすると画面全体が明るくなる。
ねじれ天国の表示も正常になった。

ユーザースクリプトの設定

上のスクショでもわかるように、画面左下のGoogle検索ボックスが横長になっていて、レイアウトが崩れている。ユーザースクリプトを適用することでこれを適切な幅に調整するため、先ほど同様に設定画面から「コンテンツ」にある「ユーザースクリプトの編集」をタップ。

ユーザースクリプトを実行するタイミングで設定箇所が異なる。

「タイミング」の画面が表示されたら「読み込み後」の方の書き込みボタンをタップする(おそらく読み込み前でも動くが、たぶん読み込み後の方がいい)。

読み込み後に適用されるユーザースクリプトの初期表示

初期値を削除し、ここに以下のコードをコピーアンドペーストする。タップでコピーされます。

(function() {
    'use strict';

    var target = document.querySelector('input#cse-search-box');
    const observer = new MutationObserver((mutations) => {
        mutations.forEach((mutation) => {
            target.style.width = "auto";
        });
    });

    var config = { attributes: true, childList: true, characterData: true }

    observer.observe(target, config);
})();
貼り付けたあと

「戻る」からタイミング画面に戻り、読み込み後のスイッチをONにする。

スイッチは緑が有効

これで設定完了。村のページをリロードすると検索ボックスの幅が正常になっているはず。

ENHANCED BY Google がちゃんと収まった

その他つぶやき

  • 上記の検索ボックス幅調整スクリプトはPC版でも利用できます。Tampermonkey や Greasemonkey などが導入してあれば、こちらからインストールできます。
  • 他にも文学ブロッカーやレイアウトの変更など、UIを改善するコードを追加公開するかも。需要次第なので村とかTwitterで声をかけてもらえるとやる気が出ます。
  • 仕様的にねじれ天国と関係のないサイトでもスクリプトが実行されてそう。害はないと思うけど、気が向いたら修正します。