BetterExercises_JS

mec-itutorの演習画面を修正

Versión del día 10/11/2025. Echa un vistazo a la versión más reciente.

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Necesitará instalar una extensión como Tampermonkey para instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==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();
  });
}