BetterExercises_JS

mec-itutorの演習画面を修正

Από την 10/11/2025. Δείτε την τελευταία έκδοση.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey, το Greasemonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

You will need to install an extension such as Tampermonkey to install this script.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Userscripts για να εγκαταστήσετε αυτόν τον κώδικα.

You will need to install an extension such as Tampermonkey to install this script.

Θα χρειαστεί να εγκαταστήσετε μια επέκταση διαχείρισης κώδικα χρήστη για να εγκαταστήσετε αυτόν τον κώδικα.

(Έχω ήδη έναν διαχειριστή κώδικα χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Έχω ήδη έναν διαχειριστή στυλ χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

// ==UserScript==
// @name        BetterExercises_JS
// @include     *://mec-itutor.jp/rpv/home/question/practice*
// @description mec-itutorの演習画面を修正
// @author      zom.u
// @version     1.3.5
// @namespace https://greasyfork.org/users/1534273
// ==/UserScript==

// GoogleアイコンCSSを追加(1回だけ)
if (!document.querySelector("link[href*='Material+Icons']")) {
  document.head.insertAdjacentHTML('beforeend', 
    '<link href="https://fonts.googleapis.com/css?family=Material+Icons|Material+Icons+Outlined|Material+Icons+Round|Material+Icons+Sharp|Material+Icons+Two+Tone" rel="stylesheet">'
  );
}

// 再適用処理
function applyCustomizations() {
  console.log("[iTutor] applyCustomizations on", location.href);
  // タイマー移動
  const timer = document.getElementById("timer");
  if (timer && !document.querySelector("#head_area .col-xs-3.text-right #timer")) {
    $("#timer").appendTo("#head_area .col-xs-3.text-right");
  }
    // 見出し移動
  const heading = document.querySelector(
    "#ctl00_cplPageContent_upd1 > div.container.pb70 > div.well.mec-bg-none.mt40 > p.h4"
  );
  if (heading) {
    // 古い見出しを消す
    $("#head_area > div.col-xs-3.text-left .h4").remove();
    // 新しい見出しを移動
    $(heading).appendTo("#head_area > div.col-xs-3.text-left");
  }
  // 本文テキストを中央へ
  const p = document.querySelector(
    "#ctl00_cplPageContent_upd1 > div.container.pb70 > div.well.mec-bg-none.mt40 > p"
  );
  if (p) {
    // 中央エリアを一度クリア
    $("#head_area > div.col-xs-6.text-center").empty();
    // p のテキストノードだけ抽出して移動
    $(p)
      .contents()
      .filter(function() {
        return this.nodeType === 3 && $.trim(this.nodeValue) !== "";
      })
      .appendTo("#head_area > div.col-xs-6.text-center");
  }

  // セレクト → ボタン化
  const select = document.getElementById("ctl00_cplPageContent_certaintyFactor");
  if (select && !select.nextElementSibling?.classList.contains("toggle-buttons")) {
    select.style.display = "none";

    const wrapper = document.createElement("div");
    wrapper.className = "toggle-buttons";

    Array.from(select.options).forEach(opt => {
      const btn = document.createElement("button");
      btn.type = "button";
      btn.textContent = opt.textContent;
      btn.dataset.value = opt.value;

      if (opt.selected) btn.classList.add("active");

      btn.addEventListener("click", () => {
        select.value = opt.value;

        wrapper.querySelectorAll("button").forEach(b => b.classList.remove("active"));
        btn.classList.add("active");

        select.dispatchEvent(new Event("change", { bubbles: true }));
      });

      wrapper.appendChild(btn);
    });

    select.parentNode.insertBefore(wrapper, select.nextSibling);

    // セレクトが外部から変更されたときにボタンを同期
    select.addEventListener("change", () => {
      const val = select.value;
      wrapper.querySelectorAll("button").forEach(b => {
        if (b.dataset.value === val) {
          b.classList.add("active");
        } else {
          b.classList.remove("active");
        }
      });
    });
  }
}
// 初回適用
applyCustomizations();
// ASP.NET の UpdatePanel 完了イベントにフック
if (window.Sys && Sys.WebForms && Sys.WebForms.PageRequestManager) {
  const prm = Sys.WebForms.PageRequestManager.getInstance();
  prm.add_endRequest(function() {
    console.log("[iTutor] async postback ended → reapply");
    applyCustomizations();
  });
}