MediaWiki:Script/Tabber.js

Revisão em 20h52min de 17 de janeiro de 2026 por Eleia (Discussão | contribs)
(dif) ← Revisão anterior | Revisão atual (dif) | Revisão seguinte → (dif)

Nota: Após gravar, terá de limpar a cache do seu navegador para ver as alterações.

  • Firefox / Safari: Pressione Shift enquanto clica Recarregar, ou pressione Ctrl-F5 ou Ctrl-R (⌘-R no Mac)
  • Google Chrome: Pressione Ctrl-Shift-R (⌘-Shift-R no Mac)
  • Internet Explorer: Pressione Ctrl enquanto clica Recarregar, ou pressione Ctrl-F5
  • Opera: Ir para Menu → Configurações (Opera → Preferências no Mac) e, em seguida, Privacidade e segurança → Limpar dados de navegação → Imagens e ficheiros em cache.
function changeDisplay(button, textContainer, method) {
  button.classList[method]("tabber-active");
  textContainer.children[button.dataset.position].classList[method]("tabber-active");
}

function globalChange(button, allButton, allText, toggleButton, changeUrl, bool = false) {
  var activeButton = allButton.querySelector(".tabber-active");
  if (toggleButton || button !== activeButton) {
    if (bool && changeUrl) {
      var newHash = "#"+button.id;
      history.pushState({}, "", newHash);
    }
    changeDisplay(button, allText, "toggle");
    if (button !== activeButton && activeButton !== null) {
      changeDisplay(activeButton, allText, "remove");
    }
  }
}

function updateTabber(buttonContainer, textContainer, toggleButton, changeUrl) {
  var targetButton = buttonContainer.querySelector(":target");
  if (targetButton !== null && targetButton.classList.contains("button")) {
    globalChange(targetButton, buttonContainer, textContainer, false, false);
  }
  buttonContainer.addEventListener("click", function(event) {
    var target = event.target.closest(".button");
    if (target) {
      globalChange(target, buttonContainer, textContainer, toggleButton, changeUrl, true);
    }
  });
}

function updateTabberWithUrlChange() {
  window.addEventListener("hashchange", function(e) {
  var newHash = e.target.location.hash;
  if (newHash !== "") {
    var targetButton = document.getElementById(newHash.slice(1));
    if (targetButton) {
      if (targetButton.classList.contains("button")) {
        var [buttonContainer, textContainer] = targetButton.parentElement.parentElement.children;
        globalChange(targetButton, buttonContainer, textContainer, false, false);
      }
    }
  }
  });
}

(function() {
  var tabberContainer = document.querySelectorAll("div.tabber-container");
  tabberContainer.forEach(function(tabber) {
    var [buttonContainer, textContainer] = tabber.children;
    var toggleButton = tabber.dataset.toggle === "1";
    var changeUrl = tabber.dataset.url === "1";
    updateTabber(buttonContainer, textContainer, toggleButton, changeUrl);
  });
  updateTabberWithUrlChange();
})();

/* NOVO */

class SpawnLayerManager {
  static SPAWN_COLOR_KEY = "mt2.spawn.color";
  static OPTION_MAPPING = {
    0: "🟥 Vermelho",
    50: "🟫 Castanho",
    140: "🟩 Verde",
    230: "🟦 Azul",
    290: "🟪 Roxo",
    black: "⬛ Preto",
    white: "⬜ Branco",
  };
  static STYLE_MAPPING = {
    position: "absolute",
    top: "0",
    left: "0",
    margin: "4px",
    background: "#434242b3",
    color: "white",
    borderRadius: "5px",
    cursor: "pointer",
    border: "1px white solid",
  };

  constructor(containerSelector = ".spawn-map-container") {
    this.containerSelector = containerSelector;
    this.currentFilter = null;
    this.selects = [];
    this.spawnLayers = [];
    this.isClipboardImageSupported = this._isClipboardImageSupported();
    this._initialize();
  }

  _isClipboardImageSupported() {
    const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
    return !!(navigator.clipboard?.write && window.ClipboardItem) && !isSafari;
  }

  _initialize() {
    const containers = this._getContainers();
    if (!containers.length) return;

    containers.forEach((container) => this._setupContainer(container));

    const savedColor = this._getSavedColor();
    if (savedColor) this._applyColor(savedColor);
  }

  _getContainers() {
    return document.querySelectorAll(this.containerSelector);
  }

  _getSavedColor() {
    return localStorage.getItem(SpawnLayerManager.SPAWN_COLOR_KEY);
  }

  _saveColor(value) {
    localStorage.setItem(SpawnLayerManager.SPAWN_COLOR_KEY, value);
  }

  _setupContainer(container) {
    const [mapContainer, spawnContainer] = container.children;

    if (!mapContainer || !spawnContainer) return;

    const map = mapContainer.querySelector("img");
    const spawnLayer = spawnContainer.querySelector("img");

    if (!map || !spawnLayer) return;

    const select = this._createColorSelect();
    spawnContainer.appendChild(select);

    this.selects.push(select);
    this.spawnLayers.push(spawnLayer);

    select.addEventListener("change", (e) => this._onColorChange(e));

    if (this.isClipboardImageSupported) {
      this._setupCopyButton(spawnContainer, map, spawnLayer);
    }
  }

  _createColorSelect() {
    const select = document.createElement("select");

    for (const [value, label] of Object.entries(
      SpawnLayerManager.OPTION_MAPPING
    )) {
      const option = document.createElement("option");
      option.value = value;
      option.textContent = label;
      select.appendChild(option);
    }

    Object.assign(select.style, SpawnLayerManager.STYLE_MAPPING);
    return select;
  }

  _onColorChange(event) {
    const value = event.target.value;
    this._applyColor(value);
  }

  _applyColor(value) {
    if (!SpawnLayerManager.OPTION_MAPPING.hasOwnProperty(value)) return;

    const filter = this._getFilterForValue(value);
    this.currentFilter = filter;

    this.selects.forEach((select) => (select.value = value));
    this.spawnLayers.forEach((layer) => (layer.style.filter = filter));
    this._saveColor(value);
  }

  _getFilterForValue(value) {
    switch (value) {
      case "black":
        return "invert(1) brightness(0) contrast(100%)";
      case "white":
        return "invert(1) sepia(1) saturate(100%) brightness(3)";
      default:
        return `hue-rotate(${value}deg)`;
    }
  }

  _setupCopyButton(spawnContainer, map, spawnLayer) {
    const copyButton = spawnContainer.querySelector(".copy-to-clipboard");

    if (!copyButton) return;

    const defaultEmoji = copyButton.querySelector("[data-default]");
    const clickedEmoji = copyButton.querySelector("[data-clicked]");

    if (!defaultEmoji || !clickedEmoji) return;

    showElement(copyButton);

    copyButton.addEventListener("click", () => {
      this._copyCombinedImageToClipboard(map, spawnLayer);
      this._copyAnimation(defaultEmoji, clickedEmoji);
    });
  }

  _copyCombinedImageToClipboard(map, spawnLayer) {
    const canvas = document.createElement("canvas");
    canvas.width = Math.max(map.naturalWidth, spawnLayer.naturalWidth);
    canvas.height = Math.max(map.naturalHeight, spawnLayer.naturalHeight);

    const ctx = canvas.getContext("2d");
    ctx.drawImage(map, 0, 0);

    const filteredLayer = this._drawFilteredLayer(spawnLayer);
    ctx.drawImage(filteredLayer, 0, 0);

    this._copyCanvasContentsToClipboard(canvas);
  }

  _drawFilteredLayer(layer) {
    const canvas = document.createElement("canvas");
    canvas.width = layer.naturalWidth;
    canvas.height = layer.naturalHeight;

    const ctx = canvas.getContext("2d");
    ctx.filter = this.currentFilter || "none";
    ctx.drawImage(layer, 0, 0);

    return canvas;
  }

  async _getBlobFromCanvas(canvas) {
    return new Promise((resolve, reject) => {
      canvas.toBlob((blob) => {
        if (blob) {
          resolve(blob);
        } else {
          reject(new Error("Canvas toBlob failed"));
        }
      });
    });
  }

  async _copyCanvasContentsToClipboard(canvas) {
    try {
      const blob = await this._getBlobFromCanvas(canvas);
      const data = [new ClipboardItem({ [blob.type]: blob })];
      await navigator.clipboard.write(data);
    } catch (error) {
      console.error(error);
    }
  }

  _copyAnimation(defaultEmoji, clickedEmoji) {
    hideElement(defaultEmoji);
    showElement(clickedEmoji);

    setTimeout(() => {
      hideElement(clickedEmoji);
      showElement(defaultEmoji);
    }, 1500);
  }
}

new SpawnLayerManager();