Vai al contenuto
Apri/Chiudi il menu
Toggle preferences menu
Apri/Chiudi il menu personale
Accesso non effettuato
Il tuo indirizzo IP sarà visibile pubblicamente se effettuerai modifiche.

MediaWiki:Gadget-course.js

Pagina dell'interfaccia di MediaWiki

Nota: dopo aver pubblicato, potrebbe essere necessario pulire la cache del proprio browser per vedere i cambiamenti.

  • Firefox / Safari: tieni premuto il tasto delle maiuscole Shift e fai clic su Ricarica, oppure premi Ctrl-F5 o Ctrl-R (⌘-R su Mac)
  • Google Chrome: premi Ctrl-Shift-R (⌘-Shift-R su un Mac)
  • Edge: tieni premuto il tasto Ctrl e fai clic su Aggiorna, oppure premi Ctrl-F5.
/* Gadget "course": rende interattivi blocchi MakeCode, quiz e griglie LED.
   Port di assets/blocks.js + assets/quiz.js + assets/led-grid.js
   per MediaWiki. Scoped: agisce solo sugli elementi con le classi attese.
   Tecnologia: legge la classe blk-<tech> sul blocco per scegliere la palette;
   fallback: classe course-<tech> sul wrapper. */
(function () {
  "use strict";

  var PALETTES = {
    microbit: {
		  basic:      "#1e90ff", // Base
		  input:      "#d400d4", // Input
		  music:      "#e63022", // Musica
		  led:        "#5c2d91", // Led
		  radio:      "#e3008c", // Radio
		  loops:      "#00aa00", // Cicli
		  logic:      "#00a4a6", // Logica
		  variables:  "#dc143c", // Variabili
		  math:       "#9400d3", // Matematica
		  game:       "#007a4b", // Gioco
		  pins:       "#b22222", // Pin
		  images:     "#b8860b", // Immagini
		  text:       "#b8860b", // Testo (stringhe)
		  serial:     "#002050", // Seriale
		  control:    "#333333", // Controllo
		  functions:  "#3455db", // Funzioni
		  arrays:     "#e65722", // Array (elenchi)
		  bluetooth:  "#0082fb"  // Bluetooth (non fornito, valore indicativo)
		}
  };

  var FONT = "700 13px -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif";
  var H = 26, PAD = 9, uid = 0;

  function measure(text) {
    try {
      var c = document.createElement("canvas");
      var ctx = c.getContext("2d");
      if (!ctx) throw new Error("no canvas");
      ctx.font = FONT;
      return ctx.measureText(text).width;
    } catch (e) {
      return text.length * 7.5;
    }
  }

  function escapeHtml(s) {
    return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
  }

  function classList(el) {
    return (el.className || "").split(/\s+/).filter(Boolean);
  }

  function kindOf(el) {
    var c = classList(el);
    if (c.indexOf("blk-hat") >= 0) return "hat";
    if (c.indexOf("blk-val") >= 0) return "val";
    if (c.indexOf("blk-bool") >= 0) return "bool";
    return "stmt";
  }

  function techOf(el, root) {
    var c = classList(el);
    var tech = null;
    for (var key in PALETTES) {
      if (c.indexOf("blk-" + key) >= 0) tech = key;
    }
    if (!tech) {
      var w = root && root.className || document.body.className || "";
      for (var k2 in PALETTES) {
        if (w.indexOf("course-" + k2) >= 0) tech = k2;
      }
    }
    return tech || Object.keys(PALETTES)[0];
  }

  function colorOf(el, root) {
    var palette = PALETTES[techOf(el, root)];
    var c = classList(el);
    for (var key in palette) {
      if (c.indexOf("blk-" + key) >= 0) return palette[key];
    }
    return palette.basic;
  }

  function build(text, kind, color) {
    var tw = measure(text);
    var W = Math.round(tw + PAD * 2);
    var id = "blksvg" + (++uid);
    var br = 5, nr = 5, vbX = 0, vbY = -br, vbW = W, vbH = H + br;
    var shape = "", maskCircle = "";
    if (kind === "stmt") {
      shape = '<rect x="0" y="0" width="' + W + '" height="' + H + '" rx="4" fill="' + color + '"/>' +
        '<circle cx="8" cy="0" r="' + br + '" fill="' + color + '"/>';
      maskCircle = '<circle cx="8" cy="' + H + '" r="' + nr + '" fill="#000"/>';
    } else if (kind === "hat") {
      vbY = 0; vbH = H + 6;
      shape = '<rect x="0" y="0" width="' + W + '" height="' + H + '" rx="8" fill="' + color + '"/>' +
        '<circle cx="8" cy="0" r="' + br + '" fill="' + color + '"/>';
      maskCircle = '<circle cx="8" cy="' + H + '" r="' + nr + '" fill="#000"/>';
    } else if (kind === "val") {
      vbX = -6; vbW = W + 6;
      shape = '<rect x="0" y="0" width="' + W + '" height="' + H + '" rx="' + H / 2 + '" fill="' + color + '"/>' +
        '<circle cx="0" cy="' + H / 2 + '" r="6" fill="' + color + '"/>';
      maskCircle = '<circle cx="' + W + '" cy="' + H / 2 + '" r="6" fill="#000"/>';
    } else {
      vbX = -6; vbW = W + 12;
      shape = '<path d="M0 ' + H / 2 + ' L8 0 L' + (W - 8) + ' 0 L' + W + ' ' + H / 2 +
        ' L' + (W - 8) + ' ' + H + ' L8 ' + H + ' Z" fill="' + color + '"/>' +
        '<circle cx="0" cy="' + H / 2 + '" r="5" fill="' + color + '"/>';
      maskCircle = '<circle cx="' + W + '" cy="' + H / 2 + '" r="5" fill="#000"/>';
    }
    return '<svg class="blk-svg" viewBox="' + vbX + " " + vbY + " " + vbW + " " + vbH +
      '" width="' + vbW + '" height="' + vbH + '" role="img" aria-label="' + escapeHtml(text) + '">' +
      '<defs><mask id="' + id + '">' +
      '<rect x="-8" y="-8" width="' + (vbW + 16) + '" height="' + (vbH + 16) + '" fill="#fff"/>' +
      maskCircle + "</mask></defs>" +
      '<g mask="url(#' + id + ')">' + shape + "</g>" +
      '<text x="' + W / 2 + '" y="' + H / 2 + '" dominant-baseline="central" text-anchor="middle" ' +
      'fill="#fff" font-family="-apple-system, BlinkMacSystemFont, Segoe UI, Roboto, sans-serif" ' +
      'font-size="13" font-weight="700">' + escapeHtml(text) + "</text></svg>";
  }

  function upgradeBlks(root) {
    root.querySelectorAll(".blk").forEach(function (el) {
      if (el.querySelector("svg")) return;
      var text = (el.textContent || "").replace(/\s+/g, " ").trim();
      if (!text) return;
      var svg = build(text, kindOf(el), colorOf(el, root));
      el.innerHTML = svg;
      el.classList.add("blk-upgraded");
    });
  }

  function wireQuiz(root) {
    root.querySelectorAll(".quiz-q").forEach(function (q) {
      if (q.getAttribute("data-bound")) return;
      q.setAttribute("data-bound", "1");
      var answer = q.getAttribute("data-answer");
      var okMsg = q.getAttribute("data-ok") || "Sì! Esatto. 👏";
      var retryMsg = q.getAttribute("data-retry") || "Non ancora, riprova!";
      var feedback = q.querySelector(".quiz-feedback");
      function answerPick(btn) {
        var correct = btn.getAttribute("data-opt") === answer;
        btn.disabled = true;
        if (correct) {
          btn.classList.add("correct");
          q.querySelectorAll(".quiz-btn").forEach(function (b) { b.disabled = true; });
          q.classList.add("answered");
          if (feedback) { feedback.textContent = okMsg; feedback.className = "quiz-feedback ok"; }
        } else {
          btn.classList.add("wrong");
          if (feedback) { feedback.textContent = retryMsg; feedback.className = "quiz-feedback no"; }
        }
      }
      q.querySelectorAll(".quiz-btn").forEach(function (btn) {
        btn.addEventListener("click", function () { answerPick(btn); });
        btn.addEventListener("keydown", function (e) {
          if (e.key === "Enter" || e.key === " ") { e.preventDefault(); answerPick(btn); }
        });
      });
    });
  }

  function renderGrids(root) {
    root.querySelectorAll(".ledgrid[data-leds]").forEach(function (grid) {
      if (grid.querySelector(".led")) return;
      var pattern = (grid.getAttribute("data-leds") || "").replace(/[\/\s]+/g, "");
      for (var i = 0; i < 25; i++) {
        var led = document.createElement("span");
        led.className = "led" + (pattern[i] === "#" ? " on" : "");
        grid.appendChild(led);
      }
    });
  }

  function init(root) {
    var target = root || document;
    upgradeBlks(target);
    wireQuiz(target);
    renderGrids(target);
  }

  window.course = { init: init };

  if (typeof mw !== "undefined" && mw.hook) {
    mw.hook("wikipage.content").add(function ($content) {
      init(($content && $content[0]) || document);
    });
  } else {
    if (document.readyState === "loading") {
      document.addEventListener("DOMContentLoaded", function () { init(document); });
    } else {
      init(document);
    }
  }
})();